編輯:關於Android編程
1.先假設一個ListView的Item子布局message_item.xml是這樣的:
前面的RelativeLayout裡的內容就是大家常見的ListView的Item視圖,後面的TextView就是我們主角刪除按鈕,這裡把它也作為Item的子布局內容了。從布局裡可以看出,刪除按鈕TextView已經被RelativeLayout擠到最右邊,而不在屏幕顯示區域內。此時該Item的長度實際長度是屏幕的長度+刪除的按鈕的長度(這裡是70dp)。
2.下面我們自定義ListView----->SlideDeleteListView 這裡注意一點,就是盡量不要在任何自定義View中傳入某布局,那麼以後修改或用於別的項目,其要求發生了一些變化,還要針對被改變的布局修改邏輯代碼,這是我個人的一種開發思想,大家聽聽就好了。
/** * 構造方法,實例化入口,初始化相關數據或實例 * * @param context * @param attrs * @param defStyleAttr */ public SlideDeleteListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 窗口管理器 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // 新建顯示度量尺 DisplayMetrics metrics = new DisplayMetrics(); // 對度量尺進行包裝,附參 wm.getDefaultDisplay().getMetrics(metrics); // 初始化屏幕寬度參數 mSreeenWidth = metrics.widthPixels; }
SlideDeleteListView構造方法中獲取屏幕寬度mSreeenWidth
/** * 手勢操作 * * @param ev * @return */ @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN:// 按壓 onActionDowm(ev); break; case MotionEvent.ACTION_MOVE:// 移動 return onActionMove(ev); case MotionEvent.ACTION_UP:// 釋放 onActionUp(ev); break; } return super.onTouchEvent(ev); }重寫SlideDeleteListView手勢事件
/** * 手指按下邏輯 */ private void onActionDowm(MotionEvent e) { if (isBtnDelShow) { resetItemView(); } mDownX = (int) e.getX(); mDownY = (int) e.getY(); // 獲得被按下位置的item Integer currentPosition = pointToPosition(mDownX, mDownY); if (-1 == currentPosition) { return; } itemViewGroup = (ViewGroup) getChildAt(currentPosition - getFirstVisiblePosition()); // 獲得刪除按鈕的寬度,刪除按鈕屬於第二個子View(上述布局中能看得出來),position為1 mBtnDelWidth = itemViewGroup.getChildAt(1).getLayoutParams().width; /* 將第一個子View也就是我們常見的Item顯示的View的寬固定為屏幕同寬度 */ params = (LinearLayout.LayoutParams) itemViewGroup.getChildAt(0).getLayoutParams(); params.width = mSreeenWidth; itemViewGroup.getChildAt(0).setLayoutParams(params); }
手指按下的時候,把剛才那個item常見顯示的視圖RelativeLayout寬度成屏幕的寬度,以及獲得刪除按鈕TextView 的寬度,isBtnDelShow為flag,用於標記刪除是否處於顯示狀態,若顯示,點擊時重置下Item顯示狀態(即不顯示刪除按鈕的視圖狀態),Integer currentPosition = pointToPosition(mDownX, mDownY),currentPosition 為-1時表示手指點擊點是在item之間的分割線上,不作邏輯處理。itemViewGroup即Item的布局,itemViewGroup.getChildAt(0)為Item子View,即上述的RelativeLayout。
/** * 手指移動邏輯 */ private boolean onActionMove(MotionEvent e) { int nowX = (int) e.getX(); int nowY = (int) e.getY(); // 判斷是否為偏向左右的滑動 if (Math.abs(nowX - mDownX) > Math.abs(nowY - mDownY)) { // 左右滑動請求消費該事件,防止上下滑動以及被ScrollView嵌套的手勢沖突 requestDisallowInterceptTouchEvent(true); // 判斷是否為向左滑動 if (nowX < mDownX) { int srollX = mDownX - nowX; // 判斷左滑距離是否超過刪除按鈕寬 if (srollX >= mBtnDelWidth) { srollX = mBtnDelWidth; } params.leftMargin = -srollX; itemViewGroup.getChildAt(0).setLayoutParams(params); } // 消費掉該移動事件 return true; } return super.onTouchEvent(e); }注釋已經很清楚了,這裡的思路就是判定左滑時,並根據左滑的絕對距離(即手指向左邊滑動的實際水平距離),實時設定RelativeLayout視圖的MarginLeft為相應距離的負值以達到感覺item布局像是被手指劃走的效果,刪除按鈕也隨即從左邊逐漸顯示出來。注意下requestDisallowInterceptTouchEvent(true)這行代碼的注釋,手指點擊的位置是在ListView上,且是左右滑,為了避免手勢沖突,不讓父View即ScrollView攔截該手勢事件。
手指釋放時判斷向左滑動的距離,做顯示按鈕或重置最初的Item顯示狀態邏輯。
/** * 手指釋放邏輯 */ private void onActionUp(MotionEvent e) { //判斷手指釋放後,刪除按鈕是否已顯示超過其寬度的一半 if (-params.leftMargin >= mBtnDelWidth / 2) { params.leftMargin = -mBtnDelWidth; isBtnDelShow = true; } else { //恢復滑動前的視圖狀態 resetItemView(); } itemViewGroup.getChildAt(0).setLayoutParams(params); }
/** * 重寫該方法是用來應對ScrollView嵌套顯示不全的問題 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 獲得ScrollView或其子類對象,這裡視情況而定,可能不需要只需要一個getParent()或多次,視自己的布局層次而定 Object object = getParent().getParent(); if (object instanceof ScrollView) {// 是ScrollView或其子類 /*解決與ScrollView的布局沖突,讓ListView完全顯示*/ int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } else { // 沒有ScrollView嵌套,正常super的方法 super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
/** * 重置itemView,恢復原顯示狀態 */ public void resetItemView() { params.leftMargin = 0; itemViewGroup.getChildAt(0).setLayoutParams(params); isBtnDelShow = false; }看注釋。
3.在適配器Adapter中獲取該ListView對象,當刪除按鈕顯示時,點擊刪除,刪除集合裡對應的數據,ListView對象再調用上述的resetItemView()方法,再調用adapter的notifyDataSetChanged()方法更新界面。
holder.tv_btn_delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { items.remove(items.get(position)); lv_messages.resetItemView(); notifyDataSetChanged(); } });
效果圖:
OK,實現方式的核心代碼已貼上,如果還有什麼不懂的地方或有更好的建議歡迎留言。Demo源碼下載
Android 系統從2008年到現在(2016年4月),八年時間裡版本從1.0一直升到6.0,由於Android系統更新速度快,導致市面上的Android設備運行的An
Android開發中遇到要從相冊選擇圖片時,大多數人都會選擇調用Android自帶的相冊,畢竟這樣可以節約時間,又不用自己去處理圖片的問題,不過這樣也會產生一些問題,有些
Activity在inflate layout時,通過DataBindingUtil來生成綁定,從代碼看,是遍歷contentView得到View數組對象,然後通過數據綁
前言:在還沒有做任何一件事情之前,千萬不要覺得這件事情很難,因為還沒有開始做內心就已經對這件事情產生了恐懼,這將會阻止你的進步,也許當你動手開始做了這件事後發現其實並不是