天天看点

模仿美团抛物线效果

以前在毕业设计里用到了类似美团抛物线的效果,当时是找的网上的一个例子,最近有时间自己实现了一个,也算是弥补了一下心里的遗憾。

实现思路:点击item中的按钮,在MainActivity中添加动画图片,添加的图片执行一个类似抛物线的动画,运动到底部指定位置。

我们先来看看运行效果:

模仿美团抛物线效果

动画效果的实现:

先贴出Adapter的代码:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    public interface OnClickLitener {
        void onClick(int x, int y);
    }

    private OnClickLitener mOnClickLitener;

    public void setOnClickLitener(OnClickLitener onClickLitener) {
        this.mOnClickLitener = onClickLitener;
    }

    private Context context;
    private String[] mDataset;

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public LinearLayout item;
        public TextView title;
        public ImageView button;
        public ViewHolder(LinearLayout v) {
            super(v);
            item = v;
        }
    }

    public MyAdapter(Context context, String[] myDataset) {
        mDataset = myDataset;
        this.context = context;
    }

    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_view, parent, false);
        ViewHolder vh = new ViewHolder((LinearLayout) v);
        vh.title = (TextView) v.findViewById(R.id.title);
        vh.button = (ImageView) v.findViewById(R.id.button);
        return vh;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.title.setText(mDataset[position]);
        holder.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int[] location = new int[];
                view.getLocationOnScreen(location);
                int x = location[];
                int y = location[];
                mOnClickLitener.onClick(x, y);
            }
        });

    }

    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}
           
Adapter中的代码很简单,其中item布局中只有一个TextView,跟一个Imageview,当点击ImageView时将ImageView在屏幕中的坐标传递给MainActivity。

下面是MainActivity的具体代码:

public class MainActivity extends AppCompatActivity implements MyAdapter.OnClickLitener {

    private RecyclerView mRecyclerView;
    private MyAdapter mAdapter;
    private LinearLayoutManager linearLayoutManager;
    private ImageView iv_end;
    RelativeLayout mainLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
        setSupportActionBar(myToolbar);
        ActionBar ab = getSupportActionBar();
        ab.setDisplayHomeAsUpEnabled(true);

        iv_end = (ImageView) findViewById(R.id.end);
        mainLayout = (RelativeLayout) findViewById(R.id.activity_main);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        String[] myDataset = {"断", "桥", "残", "雪"};

        mRecyclerView.setHasFixedSize(true);
        linearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(linearLayoutManager);

        mAdapter = new MyAdapter(this, myDataset);
        mRecyclerView.setAdapter(mAdapter);

        mAdapter.setOnClickLitener(this);
    }

    @Override
    public void onClick(int x, int y) {
        Log.d("paowu", "onClick");
        int[] location = new int[];
        iv_end.getLocationOnScreen(location);
        int endX = location[];
        int endY = location[];
        int height = getStatusBarHeight();
        int coordinateX = x;
        int coordinateY = y - height;
        endY = endY - height;
        final ImageView imageView = new ImageView(this);
        imageView.setImageResource(R.mipmap.ic_launcher);

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParams.leftMargin = coordinateX;
        layoutParams.topMargin = coordinateY;
        mainLayout.addView(imageView, layoutParams);

        ObjectAnimator x1 = ObjectAnimator.ofFloat(imageView, "x", (float) coordinateX, endX);
        x1.setDuration();
        ObjectAnimator y1 = ObjectAnimator.ofFloat(imageView, "y", (float) coordinateY, (float) (coordinateY - ));
        y1.setInterpolator(new DecelerateInterpolator());
        y1.setDuration();
        ObjectAnimator y2 = ObjectAnimator.ofFloat(imageView, "y", (float) (coordinateY - ), endY);
        y2.setInterpolator(new AccelerateInterpolator());
        y2.setDuration();
        AnimatorSet set1 = new AnimatorSet();
        set1.play(x1).with(y1);
        set1.play(y2).after(y1);
        set1.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mainLayout.removeView(imageView);
            }
        });
        set1.start();
    }

    /**
     * 获取状态栏的高度
     *
     * @return
     */
    public int getStatusBarHeight() {
        int result = ;
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > ) {
            result = getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }
}
           

MainActivity布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jqk.meituananimation.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/my_toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:elevation="4dp"
            android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        <include layout="@layout/activity_main_content"></include>
    </LinearLayout>

</RelativeLayout>
           

activity_main_content布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="9">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/my_recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:gravity="center_vertical"
        android:layout_height="0dp"
        android:layout_weight="1">

        <ImageView
            android:id="@+id/end"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_launcher" />
    </LinearLayout>

</LinearLayout>
           
类似抛物线的动画由x轴动画和y轴动画组合而成,x轴是匀速直线运动;y轴动画分为两部分:上升和下降,为了达到减速跟加速的效果,使用了系统自带的两个插值器,然后将这三个动画按照一定的顺序组合起来,在动画结束时要将添加的图片移除。这样就达到了我们要的效果。

注意:

如果我们使用直接获取的坐标,我们会发现添加的图片跟实际的图片总会相差一个状态栏的高度,因此起始跟结束的y坐标都应减去状态栏的高度。我们是根据具体的坐标值添加的图片,因此MainActivity最外层的布局应是RelativeLayout。