天天看點

模仿美團抛物線效果

以前在畢業設計裡用到了類似美團抛物線的效果,當時是找的網上的一個例子,最近有時間自己實作了一個,也算是彌補了一下心裡的遺憾。

實作思路:點選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。