加载RecycleView时为itemView添加一些过渡动画(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_21700489/article/details/78779204

参考:实现Instagram的Material Design概念设计

效果图如下:

这里写图片描述


采用什么方式实现该种动画效果?

  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


猜你喜欢

转载自blog.csdn.net/qq_21700489/article/details/78779204