Android條目拖拽刪除功能實(shí)例代碼
項(xiàng)目中需求,要做條目條目拖拽刪除效果,實(shí)際效果和QQ消息刪除一樣,側(cè)滑有制定和刪除。
效果圖

第一步效果圖

1.0自定義控件 SwipeLayout 繼承FrameLayout重寫(xiě)里面三個(gè)構(gòu)造方法,分別調(diào)用initView().
2.0在布局中使用自定義控件
3.0在initView()方法中,創(chuàng)建拖拽輔輔助工具 ViewDragHelper()
該方法需要傳入回調(diào) MyCallBack()
4.0,創(chuàng)建MyCallBack()回調(diào),繼承ViewDragHelper.Callback
在回調(diào)中 覆蓋tryCaptureView方法,返回true 允許child被拖拽,被 覆蓋clampViewPositionHorizontal 返回left系統(tǒng)提供拖拽位置
5.0 onInterceptTouchEvent 返回:讓ViewDragHelper判斷是否需要攔截事件
6.0 onTouchEvent 返回true 并且讓ViewDragHelper分析事件
具體代碼:
布局:
<cn.itheima.swipelayout.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="wrap_content"> <!--正文部分--> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#fff" android:orientation="horizontal"> <TextView android:id="@+id/item_tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="張三" android:textSize="20sp" /> </RelativeLayout> <!--按鈕部分--> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#888888" android:padding="10dp" android:text="呼叫" android:textSize="20sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#f00" android:padding="10dp" android:text="刪除" android:textSize="20sp" /> </LinearLayout> </cn.itheima.swipelayout.SwipeLayout>
SwipeLayout 代碼:
public class SwipeLayout extends FrameLayout {
private ViewDragHelper mDragHelper;
public SwipeLayout(Context context) {
super(context);
initView();
}
public SwipeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mDragHelper = ViewDragHelper.create(this,new MyCallBack());
}
// 讓ViewDragHelper就是拖拽輔助工具 返回true 則表示要攔截觸摸事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//讓拖拽輔助工具判斷是否需要攔截 事件
return mDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//讓拖拽輔助工具分析事件 分析用戶手勢(shì)
mDragHelper.processTouchEvent(event);
return true;
}
private class MyCallBack extends ViewDragHelper.Callback{
/**
* 如果返回 true 則表示 child 允許被拖拽
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
/**
* 固定被拖拽控件的水平位置,
* 參數(shù)里的 left 是系統(tǒng)推薦移動(dòng)到的位置,可以進(jìn)行修正,
* 方法返回的值就是 child 將要移動(dòng)到的位置
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
}
}
第二步:
1.0創(chuàng)建onFinishInflate方法獲取子控件,并且判斷健壯性
/*
控件初始化時(shí)執(zhí)行,可以用于獲取子控件
*/
@Override
protected void onFinishInflate() {
// 健壯性檢查
if (getChildCount()!=2){
throw new RuntimeException("SwipeLayout 必須存放兩個(gè)子控件");
}
if (!(getChildAt(0) instanceof ViewGroup)||!(getChildAt(1) instanceof ViewGroup)){
throw new RuntimeException("SwipeLayout 的子控件必須是 ViewGroup");
}
mContent = (ViewGroup) getChildAt(0);
mDeletePanel = (ViewGroup) getChildAt(1);
}
2.0創(chuàng)建onSizeChanged方法,在控件大小改變的時(shí)候調(diào)用,獲取控件的寬高,和刪除的面板的最大移動(dòng)范圍
/**
* 當(dāng)控件大小改變的時(shí)候調(diào)用這個(gè)方法
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int mWith = w;
int mHeigth = h;
//界面創(chuàng)建過(guò)程中,不能使用 getWidth 方法
int mRang = mDeletePanel.getMeasuredWidth();
}
3.0在onLayout中指定側(cè)拉面板的位置
//指定側(cè)拉面板的位置
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mDeletePanel.layout(mWith,0,mWith+mRang,mHeigth);
}
4.0在onViewPositionChanged方法中實(shí)現(xiàn)聯(lián)動(dòng)效果
/**
* 當(dāng)被拖拽的控件已經(jīng)移動(dòng)過(guò)后,會(huì)調(diào)用這個(gè)方法,可以用于處理控件間的聯(lián)動(dòng)效果
* @left 被拖拽控件的真實(shí)移動(dòng)位置
* @dx 被拖拽控件的真實(shí)偏移大小
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView==mContent){
// 移動(dòng)正文的同時(shí)也要移動(dòng)側(cè)欄
mDeletePanel.offsetLeftAndRight(dx);
}else{
mContent.offsetLeftAndRight(dx);
}
}
5.0在 clampViewPositionHorizontal方法中 固定被拖拽控件的水平位置,
/**
* 固定被拖拽控件的水平位置,
* 參數(shù)里的 left 是系統(tǒng)推薦移動(dòng)到的位置,可以進(jìn)行修正,
* 方法返回的值就是 child 將要移動(dòng)到的位置
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (child==mContent){
if (left>0){
left=0;
}else if (left<-mRang){
left=-mRang;
}
}else{
if (left>mWith){//mWith是屏幕的寬度
left=mWith;
}else if (left<mWith-mRang){
left=mWith-mRang;
}
}
return left;
}
第三步:
效果圖

1.0onViewReleased中根據(jù)來(lái)開(kāi)局里面,判斷是否打開(kāi)還是關(guān)閉
2.0 在 moveContent中第一次滑動(dòng)
3.0computeScroll中,繼續(xù)滑動(dòng),直到滑動(dòng)到指定的位置
4.0注意在onViewPositionChanged中手動(dòng)刷新界面,調(diào)用invalidate方法
如果不手動(dòng)刷新界面,效果展示不出來(lái)
/**
* 當(dāng)用戶松手時(shí)執(zhí)行
* @xvel 松手時(shí)在 X 方向的移動(dòng)速度,如果為 正數(shù) 則說(shuō)明是向右移動(dòng),如果是 負(fù)數(shù) 則說(shuō)明是向左移動(dòng),如果為零,說(shuō)明是靜止?fàn)顟B(tài)
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (xvel>0){
//向右移動(dòng)
close();
}else if (xvel<0){
//向左移動(dòng)
opend();
}else if (xvel>-mRang/2){// 靜止?fàn)顟B(tài)
close();// 展開(kāi)不到一半,關(guān)閉面板
}else{
opend();
}
}
}
/**
* 打開(kāi)面板
*/
private void opend() {
int left=-mRang;
moveContent(left);
}
/**
* 關(guān)閉面板
*/
private void close() {
int left=0;
moveContent(left);
}
private void moveContent(int left) {
// 開(kāi)啟平滑滾動(dòng),如果返回 true 則說(shuō)明要繼續(xù)刷新界面,保持滾動(dòng)
if(mDragHelper.smoothSlideViewTo(mContent,left,0)){
invalidate();
}
}
@Override
public void computeScroll() {
// 繼續(xù)平滑滾動(dòng),如果返回 true 則說(shuō)明要繼續(xù)刷新界面,保持滾動(dòng)
if (mDragHelper.continueSettling(true)){
invalidate();
}
}
第四步:
1.0現(xiàn)給ListView賦值 在這就省略
2.0在SwipeLayout中使用枚舉記錄面板的狀態(tài)
private enum Status{
CLOSED,OPENED,DRAGING;
}
private Status status = Status.CLOSED;
public Status getStatus() {
return status;
}
3.0// 記錄上一個(gè)打開(kāi)的面板。注意:一定要是 靜態(tài)變量
private static SwipeLayout preSwipeLayout;
4.0在onViewPositionChanged中創(chuàng)建一個(gè)方法操作關(guān)閉面板
// 關(guān)閉上一個(gè)打開(kāi)的面板 closePre();
5.0closePre()在這個(gè)方法中,判斷當(dāng)前面板的狀態(tài),并且根據(jù)狀態(tài),關(guān)閉上一個(gè)打開(kāi)的面板
// 判斷當(dāng)前面板是否正在打開(kāi),如果正在打開(kāi)則將上一個(gè)打開(kāi)的面板關(guān)閉
private void closePre() {
//記錄舊狀態(tài)
Status preStatus=status;
if (mContent.getLeft()==-mRang){
//記錄當(dāng)前面板已經(jīng)打開(kāi)
status=status.OPENED;
}else if (mContent.getLeft()==0){
//當(dāng)前面板已經(jīng)關(guān)閉
status=status.CLOSED;
}else {
status=status.DRAGING;
}
// 如果當(dāng)前面板舊狀態(tài)為關(guān)閉,并且新?tīng)顟B(tài)為拖拽,那么此時(shí)可以關(guān)閉之前打開(kāi)的面板
if (preStatus==status.CLOSED&&status==status.DRAGING){
if (preSwipeLayout!=null&&preSwipeLayout!=this){
// 關(guān)閉上一個(gè)面板
preSwipeLayout.close();
}
// 將當(dāng)前面板標(biāo)記為 打開(kāi)的面板
preSwipeLayout=this;
}
}
總結(jié)
以上所述是小編給大家介紹的Android條目拖拽刪除功能實(shí)例代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Android RecyclerView實(shí)現(xiàn)點(diǎn)擊條目刪除
- Android自定義SwipeLayout仿QQ側(cè)滑條目
- Android仿京東分類模塊左側(cè)分類條目效果
- Android更多條目收縮展開(kāi)控件ExpandView的示例代碼
- Android ListView自動(dòng)生成列表?xiàng)l目的實(shí)例
- Android XRecyclerView實(shí)現(xiàn)多條目加載
- Android ListView 條目多樣式展示實(shí)例詳解
- android RecyclerView實(shí)現(xiàn)條目Item拖拽排序與滑動(dòng)刪除
- Android中l(wèi)istview和imageview實(shí)現(xiàn)條目單選效果
- Android編程實(shí)現(xiàn)canvas繪制餅狀統(tǒng)計(jì)圖功能示例【自動(dòng)適應(yīng)條目數(shù)量與大小】
- Android中RecyclerView上拉下拉,分割線,多條目的實(shí)例代碼
- Android 中 SwipeLayout一個(gè)展示條目底層菜單的側(cè)滑控件源碼解析
- 詳解Android中實(shí)現(xiàn)ListView左右滑動(dòng)刪除條目的方法
- Android實(shí)現(xiàn)下拉展示條目效果
相關(guān)文章
android 版本檢測(cè) Android程序的版本檢測(cè)與更新實(shí)現(xiàn)介紹
做個(gè)網(wǎng)站的安卓客戶端,用戶安裝到自己手機(jī)上,如果我出了新版本怎么辦呢?要有版本更新功能,感興趣的朋友可以了解下2013-01-01
android短信管理器SmsManager實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹了android短信管理器SmsManager實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
Android實(shí)現(xiàn)的數(shù)字格式化用法示例
這篇文章主要介紹了Android實(shí)現(xiàn)的數(shù)字格式化用法,結(jié)合實(shí)例形式分析了Android數(shù)學(xué)運(yùn)算中數(shù)字格式化輸出的相關(guān)技巧,需要的朋友可以參考下2016-08-08
Android編程實(shí)現(xiàn)擦除Bitmap中某一塊的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)擦除Bitmap中某一塊的方法,涉及Android操作Bitmap顏色像素值調(diào)整的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
android實(shí)現(xiàn)listview分頁(yè)的方法
這篇文章主要介紹了android實(shí)現(xiàn)listview分頁(yè)的方法,涉及Android生成listview列表的相關(guān)技巧,需要的朋友可以參考下2015-05-05
詳解Android項(xiàng)目多服務(wù)端接口適配(超簡(jiǎn)單)
這篇文章主要介紹了Android項(xiàng)目多服務(wù)端接口適配(超簡(jiǎn)單),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Android?Drawable代碼編寫(xiě)的新姿勢(shì)分享
Drawable是什么?按照字面翻譯,就是可繪制的,由于能夠繪制的東西很多,所以這個(gè)類是一個(gè)抽象類,下面這篇文章主要給大家介紹了關(guān)于Android?Drawable代碼編寫(xiě)的新姿勢(shì),需要的朋友可以參考下2022-01-01
Android AOP 注解詳解及簡(jiǎn)單使用實(shí)例(三)
這篇文章主要介紹了Android AOP 注解詳解及簡(jiǎn)單使用實(shí)例(三)的相關(guān)資料,需要的朋友可以參考下2017-03-03
Android中判斷網(wǎng)絡(luò)連接是否可用及監(jiān)控網(wǎng)絡(luò)狀態(tài)
獲取網(wǎng)絡(luò)信息需要在AndroidManifest.xml文件中加入相應(yīng)的權(quán)限,接下來(lái)詳細(xì)介紹Android中判斷網(wǎng)絡(luò)連接是否可用及監(jiān)控網(wǎng)絡(luò)狀態(tài),感興趣的朋友可以參考下2012-12-12

