English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Wenn wir ein Projekt für einen E-Commerce-Klassenseminar schreiben, haben wir normalerweise die Funktion "Warenkorb hinzufügen", und wenn wir den Warenkorb hinzufügen, gibt es einige Parabolische Animationen, der spezifische Code ist wie folgt:
Ergebnis der Implementierung wie gezeigt:
Denkweise:
Schwierigkeiten:
Verwendung von PathMeasure
- getLength()
- Verständnis von "boolean getPosTan(float distance, float[] pos, float[] tan)"
涉及到的知识点:
如何获取控件在屏幕中的绝对坐标
//得到父布局的起始点坐标(用于辅助计算动画开始/结束时的点的坐标) int[] parentLocation = new int[2]; rl.getLocationInWindow(parentLocation);
如何使用贝塞尔曲线以及属性动画插值器ValueAnimator
// 四、计算中间动画的插值坐标(贝塞尔曲线)(其实就是用贝塞尔曲线来完成起终点的过程) //开始绘制贝塞尔曲线 Path path = new Path(); //移动到起始点(贝塞尔曲线的起点) path.moveTo(startX, startY); //使用二次萨贝尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的公式取即可 path.quadTo((startX + toX) / 2, startY, toX, toY); //mPathMeasure用于计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标, // 如果是true,path会形成一个闭环 mPathMeasure = new PathMeasure(path, false); //★★★属性动画实现(在0到贝塞尔曲线长度之间进行插值计算,获取中间过程的距离值) ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength()); valueAnimator.setDuration(1000); // Gleichestes lineares Interpolationsverfahren valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // Wenn die Interpolationsberechnung durchgeführt wird, werden die Werte jedes Mittelpunkts abgerufen // Dieser Wert ist die Länge der Kurve im Mittelverlauf (basierend auf diesem Wert wird der Koordinatenpunkt des Mittelpunkts bestimmt) float value = (Float) animation.getAnimatedValue(); // ★★★★★Packen Sie den aktuellen Punkt in mCurrentPosition // boolean getPosTan(float distance, float[] pos, float[] tan) : // Einen Abstand distance (0 <= distance <= getLength()) übergeben, dann wird der aktuelle Abstand berechnet // Der Koordinatenpunkt und die Tangente, pos wird automatisch mit den Koordinaten gefüllt, diese Methode ist sehr wichtig. mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition ist zu diesem Zeitpunkt der Koordinatenwert des Mittelpunkts // Der Koordinatenpunkt des bewegten Warenbildes (animierten Bildes) wird auf den Koordinatenpunkt des Mittelpunkts gesetzt goods.setTranslationX(mCurrentPosition[0]); goods.setTranslationY(mCurrentPosition[1}); } }); // Fünfter Abschnitt: Start der Animation valueAnimator.start();
所有代码:
package cn.c.com.beziercurveanimater; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Path; import android.graphics.PathMeasure; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private ImageView cart; private ArrayList<Bitmap> bitmapList = new ArrayList<>(); private RelativeLayout rl; private PathMeasure mPathMeasure; /** * Punktekoordinaten im Mittelteil der Bezierkurve */ private float[] mCurrentPosition = new float[2]; private TextView count; private int i = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initImg(); MyAdapter myAdapter = new MyAdapter(bitmapList); mRecyclerView.setAdapter(myAdapter); mRecyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this)); } private void initImg() { bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin)); bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin1)); bitmapList.add(BitmapFactory.decodeResource(getResources(), R.drawable.coin91)); } private void initView() { mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); cart = (ImageView) findViewById(R.id.cart); rl = (RelativeLayout) findViewById(R.id.rl); count = (TextView) findViewById(R.id.count); } class MyAdapter extends RecyclerView.Adapter<MyVH> { private ArrayList<Bitmap> bitmapList; public MyAdapter(ArrayList<Bitmap> bitmapList) { this.bitmapList = bitmapList; } @Override public MyVH onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(MainActivity.this); View itemView = inflater.inflate(R.layout.item, parent, false); MyVH myVH = new MyVH(itemView); return myVH; } @Override public void onBindViewHolder(final MyVH holder, final int position) { holder.iv.setImageBitmap(bitmapList.get(position)); holder.buy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { addCart(holder.iv); } }); } @Override public int getItemCount() { return bitmapList.size(); } } /** * ★★★★★ Animationseffekt zum Hinzufügen von Waren zum Einkaufswagen ★★★★★ * @param iv */ private void addCart(ImageView iv) { // 1. Erstellen Sie das Thema für die Animation---ImageView //Code, um ein ImageView mit dem Bild des obigen ImageView zu erstellen // Dieses Bild ist das Bild für die Animation, das von einem Ausgangspunkt aus, über eine Parabel (Bézier-Kurve), bis in den Einkaufswagen bewegt wird) final ImageView goods = new ImageView(MainActivity.this); goods.setImageDrawable(iv.getDrawable()); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100); rl.addView(goods, params); // 二、计算动画开始/结束点的坐标的准备工作 //得到父布局的起始点坐标(用于辅助计算动画开始/结束时的点的坐标) int[] parentLocation = new int[2]; rl.getLocationInWindow(parentLocation); //得到商品图片的坐标(用于计算动画开始的坐标) int startLoc[] = new int[2]; iv.getLocationInWindow(startLoc); //得到购物车图片的坐标(用于计算动画结束后的坐标) int endLoc[] = new int[2]; cart.getLocationInWindow(endLoc); // 三、正式开始计算动画开始/结束的坐标 //开始掉落的商品的起始点:商品起始点-父布局起始点+该商品图片的一半 float startX = startLoc[0] - parentLocation[0] + iv.getWidth() / 2; float startY = startLoc[1] - parentLocation[1] + iv.getHeight() / 2; //商品掉落后的终点坐标:购物车起始点-父布局起始点+购物车图片的1/5 float toX = endLoc[0] - parentLocation[0] + cart.getWidth() / 5; float toY = endLoc[1] - parentLocation[1]; // 四、计算中间动画的插值坐标(贝塞尔曲线)(其实就是用贝塞尔曲线来完成起终点的过程) //开始绘制贝塞尔曲线 Path path = new Path(); //移动到起始点(贝塞尔曲线的起点) path.moveTo(startX, startY); //使用二次萨贝尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的公式取即可 path.quadTo((startX + toX) / 2, startY, toX, toY); //mPathMeasure用于计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标, // 如果是true,path会形成一个闭环 mPathMeasure = new PathMeasure(path, false); //★★★属性动画实现(在0到贝塞尔曲线长度之间进行插值计算,获取中间过程的距离值) ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength()); valueAnimator.setDuration(1000); // Gleichestes lineares Interpolationsverfahren valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // Wenn die Interpolationsberechnung durchgeführt wird, werden die Werte jedes Mittelpunkts abgerufen // Dieser Wert ist die Länge der Kurve im Mittelverlauf (basierend auf diesem Wert wird der Koordinatenpunkt des Mittelpunkts bestimmt) float value = (Float) animation.getAnimatedValue(); // ★★★★★Packen Sie den aktuellen Punkt in mCurrentPosition // boolean getPosTan(float distance, float[] pos, float[] tan) : // Einen Abstand distance (0 <= distance <= getLength()) übergeben, dann wird der aktuelle Abstand berechnet // Der Koordinatenpunkt und die Tangente, pos wird automatisch mit den Koordinaten gefüllt, diese Methode ist sehr wichtig. mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition ist zu diesem Zeitpunkt der Koordinatenwert des Mittelpunkts // Der Koordinatenpunkt des bewegten Warenbildes (animierten Bildes) wird auf den Koordinatenpunkt des Mittelpunkts gesetzt goods.setTranslationX(mCurrentPosition[0]); goods.setTranslationY(mCurrentPosition[1}); } }); // Fünfter Abschnitt: Start der Animation valueAnimator.start(); // Sechster Abschnitt: Verarbeitungen nach Abschluss der Animation valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } //Nach dem Ende der Animation:} @Override public void onAnimationEnd(Animator animation) { // Die Anzahl der Warenkorbartikel wird erhöht1 i++; count.setText(String.valueOf(i)); // Entfernen Sie das bewegte Bild ImageView aus dem Eltern-Layout. rl.removeView(goods); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); } class MyVH extends RecyclerView.ViewHolder { private ImageView iv; private TextView buy; public MyVH(View itemView) { super(itemView); iv = (ImageView) itemView.findViewById(R.id.iv); buy = (TextView) itemView.findViewById(R.id.buy); } } }
Das ist der gesamte Inhalt dieses Artikels. Ich hoffe, er hilft Ihnen bei Ihrem Lernen und ich hoffe, dass alle viele Unterstützung für das Shouting-Tutorial geben.
Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem Urheberrechtsinhaber. Der Inhalt wurde von Internetbenutzern freiwillig beigesteuert und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht von Hand bearbeitet. Diese Website übernimmt keine rechtlichen Verantwortlichkeiten. Wenn Sie verdächtige urheberrechtliche Inhalte finden, sind Sie herzlich eingeladen, eine E-Mail an notice#w zu senden.3Erklärung: Bitte ersetzen Sie beim Senden einer E-Mail # durch @ und melden Sie den Verdacht auf Urheberrechtsverletzung, und fügen Sie relevante Beweise bei. Sobald nachgewiesen, wird diese Website den verdächtigen Inhalt sofort löschen.