最近在玩一个叫“约会吧”的应用,也是在看直播app,默认下载安装的,安装点进去看这个应用做的不错,就留下来了。然后看他们动态详情页底部有一个效果:Recyclerview滑动到的评论列表的时候,底部点赞那栏会往左滑动,出现一个输入评论的栏;然后下拉到底部的时候输入评论栏会往右滑动,出现点赞栏。详细细节直接来看效果图吧。
其实这种效果现在在应用中还是很常见的,有上拉,toolbar、底部view隐藏,下拉显示,或者像现在约会吧这样左右滑动的效果。而且网上资料现在也有很多,有通过ObjectAnimation来实现的,这里我们通过另外一种方法来实现。仔细下看下这个效果,其实他就是view滚动的效果,想到Android里面的滚动,马上就能想到scroller类了,scroller有一个startScroll()方法,通过这个方法我们就可以滚动了。滚动问题解决了,那么这个效果就很简单了,进入页面时,把要显示view的先显示出来,不该显示的暂时放在屏幕外面,当滚动的时间,我们控制view进入屏幕或者退出屏幕。大概思路就是这样,下面我们就来实现这样的效果吧。
效果的实现
首先,我们根据上面的思路把布局给整出来。结构如下图:
这里说明下上面的图,分为3块来说,
- 当Recyclerview上拉的时候,屏幕内5位置的view会隐藏,也就是移动到屏幕外面的6位置,当Recyclerview下拉的时候,屏幕外面的6位置view又会回到5位置显示。
- 当Recyclerview上拉的时候,屏幕内的1位置的view会隐藏,也就是移动到屏幕外面的4位置,当Recyclerview下拉的时候,屏幕外面的4位置view会回到1位置显示。
- 当RecyclerView上拉的时候,而且设置为水平方向左右滑动的时候,屏幕内的1位置的view会移动到3位置,同时屏幕外面2位置view会移动到屏幕内1位置来显示,当RecyclerView下拉的时候,屏幕外的3位置会移动到屏幕内的1位置。1位置显示的view也会回到屏幕外的2位置隐藏。这也就是上面应用的效果。
布局效果和代码如下(这里添加两个按钮来切换底部方向的效果):
效果图
activity_main.xml
<?xml version=\"1.0\" encoding=\"utf-8\"?> <RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" android:layout_width=\"match_parent\" android:layout_height=\"match_parent\" android:background=\"@android:color/white\"> <android.support.v7.widget.RecyclerView android:id=\"@+id/id_recyclerview\" android:layout_width=\"match_parent\" android:layout_height=\"match_parent\" /> <RelativeLayout android:id=\"@+id/id_horization_rl\" android:layout_width=\"match_parent\" android:layout_height=\"60dp\" android:layout_alignParentBottom=\"true\" android:orientation=\"horizontal\" > <TextView android:id=\"@+id/id_bottom_float\" android:layout_width=\"match_parent\" android:layout_height=\"60dp\" android:text=\"我是点赞操作布局\" android:textSize=\"18sp\" android:gravity=\"center\" android:background=\"#E2E2E2\"> </TextView> <TextView android:id=\"@+id/id_bottom_comment\" android:layout_width=\"match_parent\" android:layout_height=\"60dp\" android:text=\"我是评论输入布局\" android:textSize=\"18sp\" android:gravity=\"center\" android:background=\"#FF4500\"> </TextView> </RelativeLayout> <TextView android:id=\"@+id/id_bottom_vertical\" android:layout_width=\"match_parent\" android:layout_height=\"60dp\" android:text=\"你滑动,我随你而变\" android:layout_alignParentBottom=\"true\" android:background=\"#eeeeee\" android:gravity=\"center\" android:textSize=\"16sp\" /> <TextView android:id=\"@+id/id_top_vertical\" android:layout_width=\"match_parent\" android:layout_height=\"60dp\" android:text=\"你滑动,我随你而变\" android:background=\"#eeeeee\" android:gravity=\"center\" android:textSize=\"16sp\" /> <LinearLayout android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:id=\"@+id/id_switch\" android:orientation=\"vertical\" android:layout_alignParentRight=\"true\" android:layout_centerVertical=\"true\"> <TextView android:layout_width=\"wrap_content\" android:layout_height=\"60dp\" android:gravity=\"center\" android:background=\"#eeeeee\" android:text=\"切换底部水平动画\" android:onClick=\"showHorization\"/> <TextView android:layout_width=\"wrap_content\" android:layout_height=\"60dp\" android:gravity=\"center\" android:background=\"#eeeeee\" android:onClick=\"showVertical\" android:layout_marginTop=\"10dp\" android:text=\"切换底部垂直动画\"/> </LinearLayout> </RelativeLayout>
然后,我们再写一个线程来实现滚动的效果。代码如下:
public class AnimationUtil implements Runnable{ private Context mContext; //传入需要操作的view private View mAnimationView; //view的宽和高 private int mViewWidth; private int mViewHeight; //动画执行时间 private final int DURATION = 400; //是水平还是垂直滑动变化 public boolean mOrientaion ; //滚动操作类 private Scroller mScroller; private boolean isShow; public AnimationUtil(Context context,final View mAnimationView){ this.mContext = context ; this.mAnimationView = mAnimationView ; mScroller = new Scroller(context,new LinearInterpolator()); //水平布局这里以屏幕宽为准 mViewWidth = getScreenWidth(); mViewHeight = mAnimationView.getMeasuredHeight(); if(mViewHeight==0){ mAnimationView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mAnimationView.getViewTreeObserver().removeOnPreDrawListener(this); mViewHeight = mAnimationView.getMeasuredHeight(); return true; } }); } } public void setOrientaion(boolean isHorization){ this.mOrientaion = isHorization; } //根据滑动变化,isScrollUp为true水平左边滑动,否则反之, //为false垂直往下隐藏,否则反之, public void startHideAnimation(boolean isScrollUp){ isShow = false ; if(!mOrientaion){ int dy = (int) (mAnimationView.getTranslationY()+mViewHeight); if(!isScrollUp){ dy = (int)(mAnimationView.getTranslationY() - mViewHeight); } dy = cling(-mViewHeight,mViewHeight,dy); mScroller.startScroll(0, (int) mAnimationView.getTranslationY(),0,dy,DURATION); ViewCompat.postOnAnimation(mAnimationView,this); return; } int dx = (int) (mAnimationView.getTranslationX()-mViewWidth); if(!isScrollUp){ dx = (int)(mAnimationView.getTranslationX() + mViewWidth); } dx = cling(-mViewWidth,mViewWidth,dx); mScroller.startScroll((int)mAnimationView.getTranslationX(),0,dx,0,DURATION); ViewCompat.postOnAnimation(mAnimationView,this); } //显示控件 public void startShowAnimation(){ isShow = true ; if(!mOrientaion){ int dy = (int) ViewCompat.getTranslationY(mAnimationView); dy = cling(-mViewHeight,mViewHeight,dy); mScroller.startScroll(0,dy,0,-dy,DURATION); ViewCompat.postOnAnimation(mAnimationView,this); return; } int dx = (int) ViewCompat.getTranslationX(mAnimationView); dx = cling(-mViewWidth,mViewWidth,dx); mScroller.startScroll(dx,0,-dx,0,DURATION); ViewCompat.postOnAnimation(mAnimationView,this); } //判断当前绑定动画控件是否显示, public boolean isShow() { return isShow; } //终止动画 public void abortAnimation(){ mScroller.abortAnimation(); } @Override public void run() { if(mScroller.computeScrollOffset()){ //动画没停止就继续滑动 ViewCompat.postOnAnimation(mAnimationView,this); if(!mOrientaion){ ViewCompat.setTranslationY(mAnimationView,mScroller.getCurrY()); return; } ViewCompat.setTranslationX(mAnimationView,mScroller.getCurrX()); } } public int getScreenWidth(){ WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(dm); return dm.widthPixels; } //控制在一个范围的值 public int cling(int min,int max,int value){ return Math.min(Math.max(min, value), max); } }
这里简单说下上面AnimationUtil线程,首先它会创建一个滚动操作类Scroller,然后获取需要滚动的view的宽和高的获取,这里宽直接取屏幕的宽度。同时还有一个mOrientaion属性,方向的控制。然后startHideAnimation和startShowAnimation两个方法。其中startHideAnimation中,我们计算出每个效果的初始位置的x和y。然后x和y轴移动的偏移量,然后startScroll方法的调用,然后把通过ViewCompat.postOnAnimation把移动动画绑定在传入的view里面。startShowAnimation方法也是同理。我们知道,调用了startScroll,只是告诉Scroller移动到什么位置,具体的移动信息是在computeScrollOffset获取。所以我们通过这个方法就去判断view是否移动完成,没有移动,继续调用当前线程,同时根据方向设置setTranslationY或者setTranslationX。
view滚动的帮助类实现完了,我们就写个Recyclerview来简单的测试下,MainActivity代码如下:
public class MainActivity extends AppCompatActivity { //通过recyclerview来提供滑动事件 private RecyclerView mRecyclerView; //一些简单的测试数据 private TestAdapter mRecyclerAdapter; //水平简单赞布局view绑定动画 private AnimationUtil mZanAnimationUtil; //水平简单评论布局view绑定动画 private AnimationUtil mCommAnimationUtil; //垂直底部view绑定动画 private AnimationUtil mBottomVerticalUtil; //垂直头顶view绑定布局 private AnimationUtil mTopVerticalUtil; private List<String> mDataList=Arrays.asList(\"对Ta说了悄悄话\",\"冲哥\",\"小欢\",\"对象,你在哪\",\"暖心男神\",\"一次就好\", \"对Ta说了悄悄话\",\"冲哥\",\"小欢\",\"对象,你在哪\",\"暖心男神\",\"一次就好\", \"对Ta说了悄悄话\",\"冲哥\",\"小欢\",\"对象,你在哪\",\"暖心男神\",\"一次就好\", \"对Ta说了悄悄话\",\"冲哥\",\"小欢\",\"对象,你在哪\",\"暖心男神\",\"一次就好\"); private LinearLayoutManager mRecyclerManager; //赞布局控件 private TextView mZanTextView; //评论布局控件 private TextView mCommentView; private RelativeLayout mHorizationalRl; //底部布局控件 private TextView mVerticalBottomTv; //头部布局控件 private TextView mVerticalTopTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mZanTextView = (TextView) findViewById(R.id.id_bottom_float); mCommentView = (TextView)findViewById(R.id.id_bottom_comment) ; mVerticalBottomTv = (TextView)findViewById(R.id.id_bottom_vertical); mHorizationalRl = (RelativeLayout)findViewById(R.id.id_horization_rl) ; mVerticalTopTv = (TextView)findViewById(R.id.id_top_vertical); mZanAnimationUtil = new AnimationUtil(this,mZanTextView); mCommAnimationUtil = new AnimationUtil(this,mCommentView); mBottomVerticalUtil = new AnimationUtil(this,mVerticalBottomTv); mTopVerticalUtil = new AnimationUtil(this,mVerticalTopTv); mZanAnimationUtil.setOrientaion(true); mCommAnimationUtil.setOrientaion(true); mCommAnimationUtil.startHideAnimation(false); mHorizationalRl.setVisibility(View.GONE); mRecyclerManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mRecyclerManager); mRecyclerAdapter = new TestAdapter(mDataList,this); mRecyclerView.setAdapter(mRecyclerAdapter); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { //当滑动停止时动画开始 if(newState == RecyclerView.SCROLL_STATE_IDLE){ //在到达某个item改变水平布局 if(mRecyclerManager.findFirstVisibleItemPosition()>4){ mZanAnimationUtil.startHideAnimation(true); mCommAnimationUtil.startShowAnimation(); }else{ mZanAnimationUtil.startShowAnimation(); if(mCommAnimationUtil.isShow()){ mCommAnimationUtil.startHideAnimation(false); } } //头部和底部动画操作 if(mRecyclerManager.findFirstVisibleItemPosition()>0){ mBottomVerticalUtil.startHideAnimation(true); mTopVerticalUtil.startHideAnimation(false); }else{ mBottomVerticalUtil.startShowAnimation(); mTopVerticalUtil.startShowAnimation(); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } }); } public void showVertical(View view){ mHorizationalRl.setVisibility(View.GONE); mVerticalBottomTv.setVisibility(View.VISIBLE); } public void showHorization(View view){ mHorizationalRl.setVisibility(View.VISIBLE); mVerticalBottomTv.setVisibility(View.GONE); } }
主要是onScrollStateChanged方法里面的操作。主要就是注意下评论布局控件的初始化就好了。
再贴下其他的类
TestAdapter.class
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.SimpleViewHolder>{ private List<String> mDataList; private Context mContext; private LayoutInflater mInflater; public TestAdapter(List<String> mDataList, Context mContext) { this.mDataList = mDataList; this.mContext = mContext; mInflater = LayoutInflater.from(mContext); } @Override public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new SimpleViewHolder(mInflater.inflate(R.layout.simple_item,parent,false)); } @Override public void onBindViewHolder(SimpleViewHolder holder, int position) { holder.mTextView.setText(mDataList.get(position)); } @Override public int getItemCount() { return mDataList.size(); } public class SimpleViewHolder extends RecyclerView.ViewHolder{ private TextView mTextView; public SimpleViewHolder(View itemView) { super(itemView); this.mTextView = (TextView)itemView.findViewById(R.id.id_text); } } }
simple_item.xml
<?xml version=\"1.0\" encoding=\"utf-8\"?> <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" android:orientation=\"vertical\" android:layout_width=\"match_parent\" android:layout_height=\"match_parent\" android:background=\"@android:color/white\"> <LinearLayout android:layout_width=\"match_parent\" android:layout_height=\"100dp\" android:orientation=\"horizontal\" android:gravity=\"center_vertical\"> <ImageView android:layout_width=\"60dp\" android:layout_height=\"60dp\" android:background=\"#EEEEEE\" android:layout_margin=\"10dp\" android:src=\"@drawable/post_default_avatar\"/> <TextView android:id=\"@+id/id_text\" android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\" android:text=\"21111111\" android:textSize=\"14sp\" android:layout_marginLeft=\"10dp\"/> </LinearLayout> <View android:layout_width=\"match_parent\" android:layout_height=\"0.5dp\" android:layout_marginTop=\"10dp\" android:background=\"#eeeeee\"/> </LinearLayout>
最后,看下实现的效果:
这里 开发环境为android studio 2.1.0 -preview4
源码下载:Recyclerview滑动左右移动
以上就是本文的全部内容,希望对大家学习Android软件编程有所帮助。
本文地址:https://www.stayed.cn/item/6235
转载请注明出处。
本站部分内容来源于网络,如侵犯到您的权益,请 联系我