English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

تأثير الرسم البياني البيسيوس في Android عند إضافة المنتجات إلى عربة التسوق

عند كتابة مشاريع متاجر إلكترونية، عادةً ما يتم إضافة ميزة إضافة المنتجات إلى السلة، حيث يتم استخدامه في هذه الحالة حركة منحنى باربيرو، والكود التالي هو:

النتيجة كما في الرسم التوضيحي:

الطريقة:

  1. تحديد نقطة البداية والنهاية للحركة
  2. استخدام منحنى بيزيرو ثنائي لتعبئة مسار النقاط بين البداية والنهاية
  3. إعداد التعديل الديناميكي، مصفوفة التعديل الديناميكي ValueAnimator، للحصول على إحداثيات النقطة الوسطى
  4. تعيين إحداثيات x و y للعنصر الذي سيقوم بالحركة إلى النقطة الوسطى التي تم الحصول عليها
  5. إطلاق التعديل الديناميكي
  6. العمل عند انتهاء الحركة

الصعوبة:

استخدام PathMeasure
- getLength()
- فهم boolean getPosTan(float distance, float[] pos, float[] tan)

المفاهيم المعنية:

كيفية الحصول على الإحداثيات النسبية للعنصر على الشاشة

//get the starting coordinates of the parent layout (used to assist in calculating the coordinates of the points at the start/end of the animation)
  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 يستخدم لحساب طول المنحنى البيسيزاري والنقاط الإدارية بين المنحنى البيسيزاري،
    // إذا كان صحيحًا، فإن path سيشكل حلقة مغلقة
    mPathMeasure = new PathMeasure(path, false);
    //★★★تحقيق الحركة المرئية الخاص بالخصائص (من 0 إلى طول المنحنى البيسيزاري بين插补 حساب بين الوسطاء، للحصول على قيمة المسافة في العملية الوسطاء)
    مؤلفة ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
    valueAnimator.setDuration(1000);
    // 匀速线性插值器
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        // 当插值计算进行时,获取中间的每个值,
        // 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值)
        float value = (Float) animation.getAnimatedValue();
        // ★★★★★获取当前点坐标封装到mCurrentPosition
        // boolean getPosTan(float distance, float[] pos, float[] tan) :
        // 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距
        // 离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。
        mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition此时就是中间距离点的坐标值
        // 移动的商品图片(动画图片)的坐标设置为该中间点的坐标
        goods.setTranslationX(mCurrentPosition[0]);
        goods.setTranslationY(mCurrentPosition[1]);
      }
    });
//   五、 开始执行动画
    valueAnimator.start();

جميع الكود:

الباقة: cn.c.com.beziercurveanimater;
استيراد android.animation.Animator;
استيراد android.animation.ValueAnimator;
استيراد android.graphics.Bitmap;
استيراد android.graphics.BitmapFactory;
استيراد 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;
  /**
   * وسط نقاط منحنى البيزيير
   */
  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();
    }
  }
  /**
   * ★★★★★Add the product to the shopping cart animation effect★★★★★
   * @param iv
   */
  private void addCart(ImageView iv) {
//   Create the main theme for the animation - imageview
    //code to create a new imageview, the image resource is the image of the above imageview
    // (this image is the image that performs the animation, starting from the starting position, moving through a parabola (Bezier curve), and moving to the shopping cart)
    final ImageView goods = new ImageView(MainActivity.this);
    goods.setImageDrawable(iv.getDrawable());
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100, 100);
    rl.addView(goods, params);
//    Prepare for calculating the coordinates of the start/end points of the animation
    //get the starting coordinates of the parent layout (used to assist in calculating the coordinates of the points at the start/end of the animation)
    int[] parentLocation = new int[2];
    rl.getLocationInWindow(parentLocation);
    //get the coordinates of the product image (used to calculate the starting coordinates of the animation)
    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 يستخدم لحساب طول المنحنى البيسيزاري والنقاط الإدارية بين المنحنى البيسيزاري،
    // إذا كان صحيحًا، فإن path سيشكل حلقة مغلقة
    mPathMeasure = new PathMeasure(path, false);
    //★★★تحقيق الحركة المرئية الخاص بالخصائص (من 0 إلى طول المنحنى البيسيزاري بين插补 حساب بين الوسطاء، للحصول على قيمة المسافة في العملية الوسطاء)
    مؤلفة ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());
    valueAnimator.setDuration(1000);
    // 匀速线性插值器
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        // 当插值计算进行时,获取中间的每个值,
        // 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值)
        float value = (Float) animation.getAnimatedValue();
        // ★★★★★获取当前点坐标封装到mCurrentPosition
        // boolean getPosTan(float distance, float[] pos, float[] tan) :
        // 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距
        // 离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。
        mPathMeasure.getPosTan(value, mCurrentPosition, null);//mCurrentPosition此时就是中间距离点的坐标值
        // 移动的商品图片(动画图片)的坐标设置为该中间点的坐标
        goods.setTranslationX(mCurrentPosition[0]);
        goods.setTranslationY(mCurrentPosition[1]);
      }
    });
//   五、 开始执行动画
    valueAnimator.start();
//   六、动画结束后的处理
    valueAnimator.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animation) {
      }
      //当动画结束后:
      @Override
      public void onAnimationEnd(Animator animation) {
        // زيادة عدد المنتجات في عربة التسوق بـ 1
        i++;
        count.setText(String.valueOf(i));
        // إزالة الصورة المتنقلة imageview من التركيب الأب
        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);
    }
  }
}

هذا هو نهاية محتويات هذا المقال، نأمل أن تكون قد ساعدتكم في التعلم، ونأمل أن تدعموا دليل التدريب بالكثير من الدعم.

بيان: محتويات هذا المقال تم جمعها من الإنترنت، ويتمتع المالك الحقيقي بحقوق الطبع والنشر، ويتم جمع المحتويات من قبل المستخدمين عبر الإنترنت بشكل متعاوني وتم تحميلها بشكل مستقل، ويتمتع الموقع بلا حقوق ملكية، ولا يتم تعديل المحتويات بشكل يدوي، ولا يتحمل الموقع أي مسؤولية قانونية. إذا كنت قد وجدت محتوى يشتبه في حقوق الطبع والنشر، فالرجاء إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # بـ @) للإبلاغ، وتقديم الدليل، وسيتم حذف المحتوى المزعوم عن حقوق الطبع والنشر فور التحقق منه.

أنت قد تحب