Android中怎么利用SlideListView自定義View,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
主要用到了 Scroller 這個滑動類,剛開始攔截觸摸事件在 action ==MotionEvent.ACTION_DOWN的時候,根據出點獲取我們點擊的itemView 然后根據滑動模式(左滑動 or 右滑動)來自動獲取左側或者右側的寬度;
在 action == MotionEvent.ACTION_MOVE 中根據移動判斷是否可以側滑,以及側滑的方向,并使用 itemView.scrollTo(deltaX, 0); 來移動itemView ;
***在 ction == MotionEvent.ACTION_UP 中判斷模式和移動的距離完成側滑或者還原到初始狀態。
實現
***步 初始化Scroller
scroller = new Scroller(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
第二步 action ==MotionEvent.ACTION_DOWN
case MotionEvent.ACTION_DOWN: if (this.mode == MOD_FORBID) { return super.onTouchEvent(ev); } // 如果處于側滑完成狀態,側滑回去,并直接返回 if (isSlided) { scrollBack(); return false; } // 假如scroller滾動還沒有結束,我們直接返回 if (!scroller.isFinished()) { return false; } downX = (int) ev.getX(); downY = (int) ev.getY(); slidePosition = pointToPosition(downX, downY); // 無效的position, 不做任何處理 if (slidePosition == AdapterView.INVALID_POSITION) { return super.onTouchEvent(ev); } // 獲取我們點擊的item view itemView = getChildAt(slidePosition - getFirstVisiblePosition()); /*此處根據設置的滑動模式,自動獲取左側或右側菜單的長度*/ if (this.mode == MOD_BOTH) { this.leftLength = -itemView.getPaddingLeft(); this.rightLength = -itemView.getPaddingRight(); } else if (this.mode == MOD_LEFT) { this.leftLength = -itemView.getPaddingLeft(); } else if (this.mode == MOD_RIGHT) { this.rightLength = -itemView.getPaddingRight(); } break;第三步 action == MotionEvent.ACTION_MOVE
case MotionEvent.ACTION_MOVE: if (!canMove && slidePosition != AdapterView.INVALID_POSITION && (Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev .getY() - downY) < mTouchSlop)) { if (mSwipeLayout != null) mSwipeLayout.setEnabled(false); int offsetX = downX - lastX; if (offsetX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { /*從右向左滑*/ canMove = true; } else if (offsetX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)) { /*從左向右滑*/ canMove = true; } else { canMove = false; } /*此段代碼是為了避免我們在側向滑動時同時觸發ListView的OnItemClickListener時間*/ MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent .setAction(MotionEvent.ACTION_CANCEL | (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); onTouchEvent(cancelEvent); } if (canMove) { /*設置此屬性,可以在側向滑動時,保持ListView不會上下滾動*/ requestDisallowInterceptTouchEvent(true); // 手指拖動itemView滾動, deltaX大于0向左滾動,小于0向右滾 int deltaX = downX - lastX; if (deltaX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)) { /*向左滑*/ itemView.scrollTo(deltaX, 0); } else if (deltaX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { /*向右滑*/ itemView.scrollTo(deltaX, 0); } else { itemView.scrollTo(0, 0); } return true; } break;第四步 action == MotionEvent.ACTION_UP
case MotionEvent.ACTION_UP: if (mSwipeLayout != null) mSwipeLayout.setEnabled(true); //requestDisallowInterceptTouchEvent(false); if (canMove){ canMove = false; scrollByDistanceX(); } break;完整代碼
以下是完整代碼
package com.jwenfeng.fastdev.view; import android.content.Context; import android.support.v4.widget.SwipeRefreshLayout; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Scroller; /** * 當前類注釋: ListView 側滑出菜單 * 項目名:fastdev * 包名:com.jwenfeng.fastdev.view * 作者:jinwenfeng on 16/4/11 10:55 * 郵箱:823546371@qq.com * QQ: 823546371 * 公司:南京穆尊信息科技有限公司 * © 2016 jinwenfeng * ©版權所有,未經允許不得傳播 */ public class SlideListView extends ListView { /**下拉刷新view*/ private SwipeRefreshLayout mSwipeLayout; /** * 禁止側滑模式 */ public static int MOD_FORBID = 0; /** * 從左向右滑出菜單模式 */ public static int MOD_LEFT = 1; /** * 從右向左滑出菜單模式 */ public static int MOD_RIGHT = 2; /** * 左右均可以滑出菜單模式 */ public static int MOD_BOTH = 3; /** * 當前的模式 */ private int mode = MOD_FORBID; /** * 左側菜單的長度 */ private int leftLength = 0; /** * 右側菜單的長度 */ private int rightLength = 0; /** * 當前滑動的ListView position */ private int slidePosition; /** * 手指按下X的坐標 */ private int downY; /** * 手指按下Y的坐標 */ private int downX; /** * ListView的item */ private View itemView; /** * 滑動類 */ private Scroller scroller; /** * 認為是用戶滑動的最小距離 */ private int mTouchSlop; /** * 判斷是否可以側向滑動 */ private boolean canMove = false; /** * 標示是否完成側滑 */ private boolean isSlided = false; public SlideListView(Context context) { this(context, null); } public SlideListView(Context context, AttributeSet attrs) { this(context, attrs,0); } public SlideListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); scroller = new Scroller(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } /** * 初始化菜單的滑出模式 * * @param mode */ public void initSlideMode(int mode) { this.mode = mode; } /** * 處理我們拖動ListView item的邏輯 */ @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); int lastX = (int) ev.getX(); switch (action) { case MotionEvent.ACTION_DOWN: if (this.mode == MOD_FORBID) { return super.onTouchEvent(ev); } // 如果處于側滑完成狀態,側滑回去,并直接返回 if (isSlided) { scrollBack(); return false; } // 假如scroller滾動還沒有結束,我們直接返回 if (!scroller.isFinished()) { return false; } downX = (int) ev.getX(); downY = (int) ev.getY(); slidePosition = pointToPosition(downX, downY); // 無效的position, 不做任何處理 if (slidePosition == AdapterView.INVALID_POSITION) { return super.onTouchEvent(ev); } // 獲取我們點擊的item view itemView = getChildAt(slidePosition - getFirstVisiblePosition()); /*此處根據設置的滑動模式,自動獲取左側或右側菜單的長度*/ if (this.mode == MOD_BOTH) { this.leftLength = -itemView.getPaddingLeft(); this.rightLength = -itemView.getPaddingRight(); } else if (this.mode == MOD_LEFT) { this.leftLength = -itemView.getPaddingLeft(); } else if (this.mode == MOD_RIGHT) { this.rightLength = -itemView.getPaddingRight(); } break; case MotionEvent.ACTION_MOVE: if (!canMove && slidePosition != AdapterView.INVALID_POSITION && (Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev .getY() - downY) < mTouchSlop)) { if (mSwipeLayout != null) mSwipeLayout.setEnabled(false); int offsetX = downX - lastX; if (offsetX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { /*從右向左滑*/ canMove = true; } else if (offsetX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)) { /*從左向右滑*/ canMove = true; } else { canMove = false; } /*此段代碼是為了避免我們在側向滑動時同時觸發ListView的OnItemClickListener時間*/ MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent .setAction(MotionEvent.ACTION_CANCEL | (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); onTouchEvent(cancelEvent); } if (canMove) { /*設置此屬性,可以在側向滑動時,保持ListView不會上下滾動*/ requestDisallowInterceptTouchEvent(true); // 手指拖動itemView滾動, deltaX大于0向左滾動,小于0向右滾 int deltaX = downX - lastX; if (deltaX < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)) { /*向左滑*/ itemView.scrollTo(deltaX, 0); } else if (deltaX > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)) { /*向右滑*/ itemView.scrollTo(deltaX, 0); } else { itemView.scrollTo(0, 0); } return true; } break; case MotionEvent.ACTION_UP: if (mSwipeLayout != null) mSwipeLayout.setEnabled(true); //requestDisallowInterceptTouchEvent(false); if (canMove){ canMove = false; scrollByDistanceX(); } break; } return super.onTouchEvent(ev); } private void scrollByDistanceX() { if(this.mode == MOD_FORBID){ return; } if(itemView.getScrollX() > 0 && (this.mode == MOD_BOTH || this.mode == MOD_RIGHT)){ /*從右向左滑*/ if (itemView.getScrollX() >= rightLength / 2) { scrollLeft(); } else { // 滾回到原始位置 scrollBack(); } }else if(itemView.getScrollX() < 0 && (this.mode == MOD_BOTH || this.mode == MOD_LEFT)){ /*從左向右滑*/ if (itemView.getScrollX() <= -leftLength / 2) { scrollRight(); } else { // 滾回到原始位置 scrollBack(); } }else{ // 滾回到原始位置 scrollBack(); } } /** * 往右滑動,getScrollX()返回的是左邊緣的距離,就是以View左邊緣為原點到開始滑動的距離,所以向右邊滑動為負值 */ private void scrollRight() { isSlided = true; final int delta = (leftLength + itemView.getScrollX()); // 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item scroller.startScroll(itemView.getScrollX(), 0, -delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView } /** * 向左滑動,根據上面我們知道向左滑動為正值 */ private void scrollLeft() { isSlided = true; final int delta = (rightLength - itemView.getScrollX()); // 調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item scroller.startScroll(itemView.getScrollX(), 0, delta, 0, Math.abs(delta)); postInvalidate(); // 刷新itemView } private void scrollBack() { isSlided = false; scroller.startScroll(itemView.getScrollX(), 0, -itemView.getScrollX(), 0, Math.abs(itemView.getScrollX())); postInvalidate(); // 刷新itemView } @Override public void computeScroll() { // 調用startScroll的時候scroller.computeScrollOffset()返回true, if (scroller.computeScrollOffset()) { // 讓ListView item根據當前的滾動偏移量進行滾動 itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } } /** * 提供給外部調用,用以將側滑出來的滑回去 */ public void slideBack() { this.scrollBack(); } public void setSwipeLayout(SwipeRefreshLayout mSwipeLayout) { this.mSwipeLayout = mSwipeLayout; } }看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。