Android实现评论栏随Recyclerview滑动左右移动
最近在玩一个叫“约会吧”的应用,也是在看直播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软件编程有所帮助。