Android實現(xiàn)評論欄隨Recyclerview滑動左右移動
最近在玩一個叫“約會吧”的應(yīng)用,也是在看直播app,默認(rèn)下載安裝的,安裝點進去看這個應(yīng)用做的不錯,就留下來了。然后看他們動態(tài)詳情頁底部有一個效果:Recyclerview滑動到的評論列表的時候,底部點贊那欄會往左滑動,出現(xiàn)一個輸入評論的欄;然后下拉到底部的時候輸入評論欄會往右滑動,出現(xiàn)點贊欄。詳細(xì)細(xì)節(jié)直接來看效果圖吧。
其實這種效果現(xiàn)在在應(yīng)用中還是很常見的,有上拉,toolbar、底部view隱藏,下拉顯示,或者像現(xiàn)在約會吧這樣左右滑動的效果。而且網(wǎng)上資料現(xiàn)在也有很多,有通過ObjectAnimation來實現(xiàn)的,這里我們通過另外一種方法來實現(xiàn)。仔細(xì)下看下這個效果,其實他就是view滾動的效果,想到Android里面的滾動,馬上就能想到scroller類了,scroller有一個startScroll()方法,通過這個方法我們就可以滾動了。滾動問題解決了,那么這個效果就很簡單了,進入頁面時,把要顯示view的先顯示出來,不該顯示的暫時放在屏幕外面,當(dāng)滾動的時間,我們控制view進入屏幕或者退出屏幕。大概思路就是這樣,下面我們就來實現(xiàn)這樣的效果吧。
效果的實現(xiàn)
首先,我們根據(jù)上面的思路把布局給整出來。結(jié)構(gòu)如下圖:
這里說明下上面的圖,分為3塊來說,
- 當(dāng)Recyclerview上拉的時候,屏幕內(nèi)5位置的view會隱藏,也就是移動到屏幕外面的6位置,當(dāng)Recyclerview下拉的時候,屏幕外面的6位置view又會回到5位置顯示。
- 當(dāng)Recyclerview上拉的時候,屏幕內(nèi)的1位置的view會隱藏,也就是移動到屏幕外面的4位置,當(dāng)Recyclerview下拉的時候,屏幕外面的4位置view會回到1位置顯示。
- 當(dāng)RecyclerView上拉的時候,而且設(shè)置為水平方向左右滑動的時候,屏幕內(nèi)的1位置的view會移動到3位置,同時屏幕外面2位置view會移動到屏幕內(nèi)1位置來顯示,當(dāng)RecyclerView下拉的時候,屏幕外的3位置會移動到屏幕內(nèi)的1位置。1位置顯示的view也會回到屏幕外的2位置隱藏。這也就是上面應(yīng)用的效果。
布局效果和代碼如下(這里添加兩個按鈕來切換底部方向的效果):
效果圖
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>
然后,我們再寫一個線程來實現(xiàn)滾動的效果。代碼如下:
public class AnimationUtil implements Runnable{ private Context mContext; //傳入需要操作的view private View mAnimationView; //view的寬和高 private int mViewWidth; private int mViewHeight; //動畫執(zhí)行時間 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()); //水平布局這里以屏幕寬為準(zhǔn) 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; } //根據(jù)滑動變化,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); } //判斷當(dāng)前綁定動畫控件是否顯示, public boolean isShow() { return isShow; } //終止動畫 public void abortAnimation(){ mScroller.abortAnimation(); } @Override public void run() { if(mScroller.computeScrollOffset()){ //動畫沒停止就繼續(xù)滑動 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線程,首先它會創(chuàng)建一個滾動操作類Scroller,然后獲取需要滾動的view的寬和高的獲取,這里寬直接取屏幕的寬度。同時還有一個mOrientaion屬性,方向的控制。然后startHideAnimation和startShowAnimation兩個方法。其中startHideAnimation中,我們計算出每個效果的初始位置的x和y。然后x和y軸移動的偏移量,然后startScroll方法的調(diào)用,然后把通過ViewCompat.postOnAnimation把移動動畫綁定在傳入的view里面。startShowAnimation方法也是同理。我們知道,調(diào)用了startScroll,只是告訴Scroller移動到什么位置,具體的移動信息是在computeScrollOffset獲取。所以我們通過這個方法就去判斷view是否移動完成,沒有移動,繼續(xù)調(diào)用當(dāng)前線程,同時根據(jù)方向設(shè)置setTranslationY或者setTranslationX。
view滾動的幫助類實現(xiàn)完了,我們就寫個Recyclerview來簡單的測試下,MainActivity代碼如下:
public class MainActivity extends AppCompatActivity { //通過recyclerview來提供滑動事件 private RecyclerView mRecyclerView; //一些簡單的測試數(shù)據(jù) 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) { //當(dāng)滑動停止時動畫開始 if(newState == RecyclerView.SCROLL_STATE_IDLE){ //在到達(dá)某個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>
最后,看下實現(xiàn)的效果:
這里 開發(fā)環(huán)境為android studio 2.1.0 -preview4
源碼下載:Recyclerview滑動左右移動
以上就是本文的全部內(nèi)容,希望對大家學(xué)習(xí)Android軟件編程有所幫助。
相關(guān)文章
Android編程添加快捷方式(Short)到手機桌面的方法(含添加,刪除及查詢)
這篇文章主要介紹了Android編程添加快捷方式(Short)到手機桌面的方法,含有針對桌面快捷方式的添加,刪除及查詢的操作實現(xiàn)技巧,需要的朋友可以參考下2016-01-01Android中阻止AlertDialog關(guān)閉實例代碼
這篇文章主要介紹了Android阻止AlertDialog關(guān)閉實例代碼的相關(guān)資料,需要的朋友可以參考下2016-03-03Android用PopupWindow實現(xiàn)新浪微博的分組信息實例
PopupWindow可以實現(xiàn)浮層效果,而且可以自定義顯示位置,本篇文章主要介紹Android用PopupWindow實現(xiàn)新浪微博的分組信息,有需要的可以了解一下。2016-11-11