1. 程式人生 > >載入RecycleView時為itemView新增一些過渡動畫(一)

載入RecycleView時為itemView新增一些過渡動畫(一)

效果圖如下:

這裡寫圖片描述

採用什麼方式實現該種動畫效果?

  Android動畫可以分為三類:幀動畫(Frame Animation)、補間動畫(Tween Animation)、屬性動畫(Property Animation)。我們主要這裡用到了補間動畫的Alpha(透明度)和Translate(位移)屬性。

在哪裡為Item項新增動畫?

  由於我們是為RecyclerView的Item檢視繪製動畫效果,所以我們在自定義的MyAdapter(繼承了RecyclerView.Adapter)的onBindViewHolder(…)方法裡為Item項開啟動畫。
  

分析動畫效果的組成

  仔細觀察動畫效果,我們可以看到動畫效果由兩部分組成:

  • Item項從無到有:這個我們利用補間動畫的Alpha(透明度)屬性完成
  • Item項慢慢從下往上浮現:利用補間動畫的Translate(位移)屬性完成

具體的動畫方法程式碼

private void runEnterAnimation(View view, int position) {  



     if (animationsLocked) return;              //animationsLocked是布林型別變數,一開始為false
                                               //確保僅螢幕一開始能夠容納顯示的item項才開啟動畫  
if (position > lastAnimatedPosition) {//lastAnimatedPosition是int型別變數,預設-1, //這兩行程式碼確保了recyclerview滾動式回收利用檢視時不會出現不連續效果 lastAnimatedPosition = position; view.setTranslationY(500); //Item項一開始相對於原始位置下方500距離 view.setAlpha(0.f); //item項一開始完全透明
//每個item項兩個動畫,從透明到不透明,從下方移動到原始位置 view.animate() .translationY(0).alpha(1.f) //設定最終效果為完全不透明 //並且在原來的位置 .setStartDelay(delayEnterAnimation ? 20 * (position) : 0)//根據item的位置設定延遲時間 //達到依次動畫一個接一個進行的效果 .setInterpolator(new DecelerateInterpolator(0.5f)) //設定動畫位移先快後慢的效果 .setDuration(700) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animationsLocked = true; //確保僅螢幕一開始能夠顯示的item項才開啟動畫 //也就是說螢幕下方還沒有顯示的item項滑動時是沒有動畫效果 } }) .start(); } }

下面給出完整實現程式碼

  • 介面主佈局activity_main.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:id="@+id/contentRoot"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:paddingTop="16dp"  
    android:orientation="vertical"  
    tools:context=".MainActivity">  


    <android.support.v7.widget.RecyclerView  
        android:id="@+id/rcv"  
        android:layout_width="match_parent"  
        android:layout_weight="1"  
        android:layout_height="0dp" />  


    <LinearLayout  
        android:layout_marginTop="2dp"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:orientation="horizontal">  


        <EditText  
            android:id="@+id/edit"  
            android:layout_width="0dp"  
            android:layout_height="wrap_content"  
            android:layout_weight="1" />  
        <Button  
            android:id="@+id/send"  
            android:text="傳送"  
            android:textColor="#ffffff"  
            android:background="#02c754"  
            android:layout_width="72dp"  
            android:layout_height="46dp"  
            android:layout_marginBottom="2dp"  
            android:layout_marginRight="6dp"  
            android:layout_marginLeft="8dp" />  
    </LinearLayout>  
</LinearLayout>
  • RecyclerView的Item項佈局item_view.xml

 <?xml version="1.0" encoding="utf-8"?>  
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:app="http://schemas.android.com/apk/res-auto"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content">  


    <LinearLayout  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:orientation="horizontal"  
        android:paddingBottom="8dp"  
        android:paddingTop="8dp">  


        <ImageView  
            android:id="@+id/ivUser"  
            android:layout_width="40dp"  
            android:layout_height="40dp"  
            android:layout_marginLeft="16dp"  
            android:layout_marginRight="16dp"  
            android:src="@drawable/icon3" />  


        <TextView  
            android:id="@+id/tvComment"  
            android:layout_width="0dp"  
            android:layout_height="wrap_content"  
            android:layout_gravity="center_vertical"  
            android:layout_marginRight="16dp"  
            android:layout_weight="1"  
            android:text="Lorem ipsum dolor sit amet。" />  
    </LinearLayout>  


    <View  
        android:layout_width="match_parent"  
        android:layout_height="1dp"  
        android:layout_gravity="bottom"  
        android:layout_marginBottom="2dp"  
        android:layout_marginLeft="88dp"  
        android:background="#cccccc" />  
</FrameLayout>  
  • MainActivity.java

import android.support.v7.app.AppCompatActivity;  
import android.os.Bundle;  
import android.support.v7.widget.LinearLayoutManager;  
import android.support.v7.widget.RecyclerView;  
import android.widget.EditText;  
import java.util.ArrayList;  
import butterknife.ButterKnife;  
import butterknife.BindView;  
public class MainActivity extends AppCompatActivity {  
    @BindView(R.id.rcv)  
    RecyclerView rcy;  
    @BindView(R.id.edit)  
    EditText editText;  
    @BindView(R.id.contentRoot)  
    LinearLayout contentRoot;  




    private ArrayList<String> mDataSet;  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        ButterKnife.bind(this);  
        initDate();  
        initRcy();  
    }  




    private void initRcy() {  
        rcy.setLayoutManager(new LinearLayoutManager(this));  
        rcy.setAdapter(new MyAdapter(this,mDataSet));  
    }  




    private void initDate() {  
        mDataSet=new ArrayList<String>();  
        mDataSet.add("要想實現這個動畫效果,必須考慮到取消原本的重繪回撥機制。");  
        mDataSet.add("item項首先是不透明,並且在原來位置的下方100處,然後慢慢變回透明,並且同時回到原來的位置");  
        mDataSet.add("底部的輸入評論檢視首先在原來的位置下方100處,item動畫完成後重新回到原來的位置");  
        mDataSet.add("要想實現這個動畫效果,必須考慮到取消原本的重繪回撥機制。");  
        mDataSet.add("item項首先是不透明,並且在原來位置的下方100處,然後慢慢變回透明,並且同時回到原來的位置");  
        mDataSet.add("底部的輸入評論檢視首先在原來的位置下方100處,item動畫完成後重新回到原來的位置");  
        mDataSet.add("要想實現這個動畫效果,必須考慮到取消原本的重繪回撥機制。");  
        mDataSet.add("item項首先是不透明,並且在原來位置的下方100處,然後慢慢變回透明,並且同時回到原來的位置");  
        mDataSet.add("底部的輸入評論檢視首先在原來的位置下方100處,item動畫完成後重新回到原來的位置");  
        mDataSet.add("要想實現這個動畫效果,必須考慮到取消原本的重繪回撥機制。");  
        mDataSet.add("item項首先是不透明,並且在原來位置的下方100處,然後慢慢變回透明,並且同時回到原來的位置");  
        mDataSet.add("底部的輸入評論檢視首先在原來的位置下方100處,item動畫完成後重新回到原來的位置");  
    }  
}  
  • RecyclerView的介面卡程式碼MyAdapter.java

import android.animation.Animator;  
import android.animation.AnimatorListenerAdapter;  
import android.content.Context;  
import android.support.v7.widget.RecyclerView;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
import android.view.animation.DecelerateInterpolator;  
import android.widget.ImageView;  
import android.widget.TextView;  
import java.util.ArrayList;  
import butterknife.ButterKnife;  
import butterknife.BindView;  


/** 
 * Created by yang on 16-4-18. 
 */  
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {  


    private Context mContext;  
    private ArrayList<String> mDataSet;  
    private int lastAnimatedPosition=-1;  
    private boolean animationsLocked = false;  
    private boolean delayEnterAnimation = true;  
    private int itemCount=0;  


    public void setmDataSet(ArrayList<String> mDataSet) {  
        this.mDataSet = mDataSet;  
    }  

    public MyAdapter(Context mContext, ArrayList<String> mDataSet) {  
        this.mContext = mContext;  
        this.mDataSet = mDataSet;  
    }  

    public MyAdapter(Context mContext) {  
        this.mContext = mContext;  
    }  

    @Override  
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
        MyViewHolder viewHolder = new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_view, parent, false));  
        return viewHolder;  
    }  


     private void runEnterAnimation(View view, int position) {  



     if (animationsLocked) return;              //animationsLocked是布林型別變數,一開始為false
                                               //確保僅螢幕一開始能夠容納顯示的item項才開啟動畫  



     if (position > lastAnimatedPosition) {//lastAnimatedPosition是int型別變數,預設-1,
                                          //這兩行程式碼確保了recyclerview滾動式回收利用檢視時不會出現不連續效果
         lastAnimatedPosition = position;  
         view.setTranslationY(500);     //Item項一開始相對於原始位置下方500距離  
         view.setAlpha(0.f);           //item項一開始完全透明  
                                      //每個item項兩個動畫,從透明到不透明,從下方移動到原始位置 


         view.animate()  
             .translationY(0).alpha(1.f)                                //設定最終效果為完全不透明
                                                                       //並且在原來的位置  
             .setStartDelay(delayEnterAnimation ? 20 * (position) : 0)//根據item的位置設定延遲時間
                                                                     //達到依次動畫一個接一個進行的效果  
             .setInterpolator(new DecelerateInterpolator(0.5f))     //設定動畫位移先快後慢的效果
              .setDuration(700)  
              .setListener(new AnimatorListenerAdapter() {  
                  @Override  
                  public void onAnimationEnd(Animator animation) {  
                      animationsLocked = true;
                           //確保僅螢幕一開始能夠顯示的item項才開啟動畫
                           //也就是說螢幕下方還沒有顯示的item項滑動時是沒有動畫效果  
                        }  
                    })  
                    .start();  
        }  
    }  



    @Override  
    public void onBindViewHolder(MyViewHolder holder, int position) {  

        runEnterAnimation(holder.itemView,position);  
        if(position%2==0){  
            holder.ivUser.setImageResource(R.drawable.icon2);  
        }else if(position%3==0){  
            holder.ivUser.setImageResource(R.drawable.icon3);  
        }else{  
            holder.ivUser.setImageResource(R.drawable.icon1);  
        }  

        holder.tvComment.setText(mDataSet.get(position));  

    }  


    @Override  
    public int getItemCount() {  
        return mDataSet.size();  
    }  


    public class MyViewHolder extends RecyclerView.ViewHolder {  
        @BindView(R.id.tvComment)  
        TextView tvComment;  
        @BindView(R.id.ivUser)  
        ImageView ivUser;  

        public MyViewHolder(View itemView) {  
            super(itemView);  
            ButterKnife.bind(this,itemView);  

        }  
    }  
}  

這樣子最終效果就出來了,如果有錯誤的地方請指出。

PS:
  該動畫效果僅在首次顯示RecyclerView時顯示,如果有重新整理等操作需要重新顯示動畫效果時,可以考慮重新恢復animationsLoackedLastAnimatedPosition的值為false-1