編輯:關於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從1.0到 6.0各版本的差別
Android 系統從2008年到現在(2016年4月),八年時間裡版本從1.0一直升到6.0,由於Android系統更新速度快,導致市面上的Android設備運行的An
安卓開發 第八篇 我的安卓應用架構設計-----圖片選擇以及剪裁
Android開發中遇到要從相冊選擇圖片時,大多數人都會選擇調用Android自帶的相冊,畢竟這樣可以節約時間,又不用自己去處理圖片的問題,不過這樣也會產生一些問題,有些
Android的DataBinding原理介紹
Activity在inflate layout時,通過DataBindingUtil來生成綁定,從代碼看,是遍歷contentView得到View數組對象,然後通過數據綁
android使用AIDL實現跨進程通訊(IPC)
前言:在還沒有做任何一件事情之前,千萬不要覺得這件事情很難,因為還沒有開始做內心就已經對這件事情產生了恐懼,這將會阻止你的進步,也許當你動手開始做了這件事後發現其實並不是