效果圖:
看網上的都是兩個view拼接,預設右側的不顯示,水平移動的時候把右側的view顯示出來。但是看最新版QQ上的效果不是這樣的,但給人的感覺卻很好,所以獻醜來一發比較高仿的。
知識點:
1、ViewDragHelper 的用法;
2、滑動衝突的解決;
3、自訂viewgroup。
ViewDragHelper 出來已經比較久了相信大家都比較熟悉,不熟悉的話google一大把這裡主要簡單用一下它的幾個方法
1、tryCaptureView(View child, int pointerId) :確定那個子view可以滑動
2、 getViewHorizontalDragRange(View child):用我蹩腳的英語翻譯一下是'返回的是子view在水平方向上可移動的大小,以像素為單位,返回0的時候表示水平方向上不能拖動'
3、clampViewPositionHorizontal(View child, int left, int dx):在這裡可以對邊界進行檢查,left和dx分別代表即將移動到的位置
4、onViewPositionChanged(View changedView, int left, int top,
int dx, int dy):當要捕獲view,由於拖曳或設定而發生位置變更時回調
它的基本用法是:
public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { viewDragHelper = ViewDragHelper.create(this, callback); } public boolean onInterceptTouchEvent(MotionEvent ev) { boolean result = viewDragHelper.shouldInterceptTouchEvent(ev); } public boolean onTouchEvent(MotionEvent event) { viewDragHelper.processTouchEvent(event); return true; }
1)、在構造方法中創建
2)、在onInterceptTouchEvent中判斷是否攔截
3 )、 在onTouchEvent出來事件
好了最不好理解的已經搞定了。接下來看看具體實作:
首先看佈局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <scrollviewgroup.lly.com.swiplayout.SwipeLayout android:id="@+id/swipeLayout" android:layout_width="match_parent" android:layout_height="wrap_content" > <!-- delete区域的布局 --> <include layout="@layout/layout_delete" /> <!-- item内容的布局 --> <include layout="@layout/layout_content" /> </scrollviewgroup.lly.com.swiplayout.SwipeLayout> </LinearLayout>
這個沒什麼好說的,一個自訂viewgroup包含兩個子控制項。
接著看看SwipeLayout是怎麼實現的:
@Override protected void onFinishInflate() { super.onFinishInflate(); deleteView = getChildAt(0); contentView = getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); deleteHeight = deleteView.getMeasuredHeight(); deleteWidth = deleteView.getMeasuredWidth(); contentWidth = contentView.getMeasuredWidth(); screenWidth = getWidth(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // super.onLayout(changed, left, top, right, bottom); deleteView.layout(screenWidth - deleteWidth, 0, (screenWidth - deleteWidth) + deleteWidth, deleteHeight); contentView.layout(0, 0, contentWidth, deleteHeight); }
上面程式碼進行了一些初始化的操作,重點看看onlayout裡面的,我們繼承的是framelayout 這裡先畫出來deleteView並讓他在右邊,然後在上面改了一層contentView,這樣顯示的時候只會顯示contentView。
接下來看ontouch方法
public boolean onTouchEvent(MotionEvent event) { //如果当前有打开的,则下面的逻辑不能执行 if(!SwipeLayoutManager.getInstance().isShouldSwipe(this)){ requestDisallowInterceptTouchEvent(true); return true; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); break; case MotionEvent.ACTION_MOVE: //1.获取x和y方向移动的距离 float moveX = event.getX(); float moveY = event.getY(); float delatX = moveX - downX;//x方向移动的距离 float delatY = moveY - downY;//y方向移动的距离 if(Math.abs(delatX)>Math.abs(delatY)){ //表示移动是偏向于水平方向,那么应该SwipeLayout应该处理,请求父view不要拦截 requestDisallowInterceptTouchEvent(true); } //更新downX,downY downX = moveX; downY = moveY; break; case MotionEvent.ACTION_UP: break; } viewDragHelper.processTouchEvent(event); return true; }
上面主要就是對事件衝突的處理,當是水平移動的時候就請求父視圖不要攔截。
接下來來重點就來了
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return child==contentView; } @Override public int getViewHorizontalDragRange(View child) { return deleteWidth; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if(child==contentView){ if(left>0)left = 0; if(left<-deleteWidth)left = -deleteWidth; } return left; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); //判断开和关闭的逻辑 if(contentView.getLeft()==0 && currentState!=SwipeState.Close){ //说明应该将state更改为关闭 currentState = SwipeState.Close; //回调接口关闭的方法 if(listener!=null){ listener.onClose(getTag()); } //说明当前的SwipeLayout已经关闭,需要让Manager清空一下 SwipeLayoutManager.getInstance().clearCurrentLayout(); }else if (contentView.getLeft()==-deleteWidth && currentState!=SwipeState.Open) { //说明应该将state更改为开 currentState = SwipeState.Open; //回调接口打开的方法 if(listener!=null){ listener.onOpen(getTag()); } //当前的Swipelayout已经打开,需要让Manager记录一下下 SwipeLayoutManager.getInstance().setSwipeLayout(SwipeLayout.this); } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if(contentView.getLeft()<-deleteWidth/2){ //应该打开 open(); }else { //应该关闭 close(); } } };
上面這段程式碼裡面的方法一開始我們都說過了,在來看下在tryCaptureView中我們讓contentView可以滑動,在getViewHorizontalDragRange中卻東滑動範圍是deleteWidth,在clampViewPositionHorizontal中對邊界進行了下限制,在onViewPositionChanged中進行狀態的更新, 最後在手指抬起的時候讓view自動回滾,
/** * 打开的方法 */ public void open() { viewDragHelper.smoothSlideViewTo(contentView,-deleteWidth,contentView.getTop()); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } /** * 关闭的方法 */ public void close() { viewDragHelper.smoothSlideViewTo(contentView,0,contentView.getTop()); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); }; public void computeScroll() { if(viewDragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } }
這裡注意一定要重寫computeScroll方法,不然滑動效果動一下就不動了。
至此這個自訂framelayout就完成了
但是發現一個問題,我們在已經滑動出來的view中上下滑動時,這個view的deleteView還是顯示狀態,所以還要在activity中處理一下:
recyView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if(dy>0 || dy<0){ SwipeLayoutManager.getInstance().closeCurrentLayout(); } } });
當這個RecyclerView是上下滑動時,讓子view重設。
收工。
ps:本來是在eclipse中listview中實現的,但是想想google都已經不支援eclipse了,而listview也快被RecyclerView取代了,所以最後還是切換到Android studio,用RecyclerView實作了一套。
以上所述是小編給大家介紹的Android中自訂view實現側滑效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對PHP中文網的支持!
更多Android自訂view實作側滑效果相關文章請關注PHP中文網!