載入RecycleView時為itemView新增一些過渡動畫(一)
阿新 • • 發佈:2019-01-08
效果圖如下:
採用什麼方式實現該種動畫效果?
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時顯示,如果有重新整理等操作需要重新顯示動畫效果時,可以考慮重新恢復animationsLoacked和LastAnimatedPosition的值為false
和-1
。