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

来源:互联网 发布:python数组减1 编辑:程序博客网 时间:2024/05/16 09:38

参考:实现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


阅读全文
0 0
原创粉丝点击