Android仿騰訊QQ實(shí)現(xiàn)滑動(dòng)刪除 附源碼下載
看了很多大神們的文章,感覺受益良多,也非常欣賞大家的分享態(tài)度,所以決定開始寫B(tài)log,給大家分享自己的心得。
先看看效果圖:
本來準(zhǔn)備在ListView的每個(gè)Item的布局上設(shè)置一個(gè)隱藏的Button,當(dāng)滑動(dòng)的時(shí)候顯示。但是因?yàn)槊看沃灰嬖谝粋€(gè)Button,發(fā)現(xiàn)每個(gè)Item上的Button相互間不好控制。所以決定繼承ListView然后結(jié)合PopupWindow。
首先是布局文件:
delete_btn.xml:這里只需要一個(gè)Button
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:id="@+id/id_item_btn" android:layout_width="60dp" android:singleLine="true" android:layout_height="wrap_content" android:text="刪除" android:background="@drawable/d_delete_btn" android:textColor="#ffffff" android:paddingLeft="15dp" android:paddingRight="15dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="15dp" /> </LinearLayout>
主布局文件:activity_main.xml,ListView的每個(gè)Item的樣式直接使用了系統(tǒng)的android.R.layout.simple_list_item_1
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.listviewitemslidedeletebtnshow.QQListView android:id="@+id/id_listview" android:layout_width="fill_parent" android:layout_height="wrap_content" > </com.example.listviewitemslidedeletebtnshow.QQListView> </RelativeLayout>
接下來看看QQListView的實(shí)現(xiàn):
package com.example.listviewitemslidedeletebtnshow; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.PopupWindow; public class QQListView extends ListView { private static final String TAG = "QQlistView"; // private static final int VELOCITY_SANP = 200; // private VelocityTracker mVelocityTracker; /** * 用戶滑動(dòng)的最小距離 */ private int touchSlop; /** * 是否響應(yīng)滑動(dòng) */ private boolean isSliding; /** * 手指按下時(shí)的x坐標(biāo) */ private int xDown; /** * 手指按下時(shí)的y坐標(biāo) */ private int yDown; /** * 手指移動(dòng)時(shí)的x坐標(biāo) */ private int xMove; /** * 手指移動(dòng)時(shí)的y坐標(biāo) */ private int yMove; private LayoutInflater mInflater; private PopupWindow mPopupWindow; private int mPopupWindowHeight; private int mPopupWindowWidth; private Button mDelBtn; /** * 為刪除按鈕提供一個(gè)回調(diào)接口 */ private DelButtonClickListener mListener; /** * 當(dāng)前手指觸摸的View */ private View mCurrentView; /** * 當(dāng)前手指觸摸的位置 */ private int mCurrentViewPos; /** * 必要的一些初始化 * * @param context * @param attrs */ public QQListView(Context context, AttributeSet attrs) { super(context, attrs); mInflater = LayoutInflater.from(context); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); View view = mInflater.inflate(R.layout.delete_btn, null); mDelBtn = (Button) view.findViewById(R.id.id_item_btn); mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); /** * 先調(diào)用下measure,否則拿不到寬和高 */ mPopupWindow.getContentView().measure(0, 0); mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight(); mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth(); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction(); int x = (int) ev.getX(); int y = (int) ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: xDown = x; yDown = y; /** * 如果當(dāng)前popupWindow顯示,則直接隱藏,然后屏蔽ListView的touch事件的下傳 */ if (mPopupWindow.isShowing()) { dismissPopWindow(); return false; } // 獲得當(dāng)前手指按下時(shí)的item的位置 mCurrentViewPos = pointToPosition(xDown, yDown); // 獲得當(dāng)前手指按下時(shí)的item View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition()); mCurrentView = view; break; case MotionEvent.ACTION_MOVE: xMove = x; yMove = y; int dx = xMove - xDown; int dy = yMove - yDown; /** * 判斷是否是從右到左的滑動(dòng) */ if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop) { // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx + // " , dy = " + dy); isSliding = true; } break; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); /** * 如果是從右到左的滑動(dòng)才相應(yīng) */ if (isSliding) { switch (action) { case MotionEvent.ACTION_MOVE: int[] location = new int[2]; // 獲得當(dāng)前item的位置x與y mCurrentView.getLocationOnScreen(location); // 設(shè)置popupWindow的動(dòng)畫 mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style); mPopupWindow.update(); mPopupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP, location[0] + mCurrentView.getWidth(), location[1] + mCurrentView.getHeight() / 2 - mPopupWindowHeight / 2); // 設(shè)置刪除按鈕的回調(diào) mDelBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.clickHappend(mCurrentViewPos); mPopupWindow.dismiss(); } } }); // Log.e(TAG, "mPopupWindow.getHeight()=" + mPopupWindowHeight); break; case MotionEvent.ACTION_UP: isSliding = false; } // 相應(yīng)滑動(dòng)期間屏幕itemClick事件,避免發(fā)生沖突 return true; } return super.onTouchEvent(ev); } /** * 隱藏popupWindow */ private void dismissPopWindow() { if (mPopupWindow != null && mPopupWindow.isShowing()) { mPopupWindow.dismiss(); } } public void setDelButtonClickListener(DelButtonClickListener listener) { mListener = listener; } interface DelButtonClickListener { public void clickHappend(int position); } }
代碼注釋寫得很詳細(xì),簡(jiǎn)單說一下,在dispatchTouchEvent中設(shè)置當(dāng)前是否響應(yīng)用戶滑動(dòng),然后在onTouchEvent中判斷是否響應(yīng),如果響應(yīng)則popupWindow以動(dòng)畫的形式展示出來。當(dāng)然屏幕上如果存在PopupWindow則屏幕ListView的滾動(dòng)與Item的點(diǎn)擊,以及從右到左滑動(dòng)時(shí)屏幕Item的click事件。
接下來是MainActivity.java,這里代碼很簡(jiǎn)單不做介紹了。
package com.example.listviewitemslidedeletebtnshow; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Toast; import com.example.listviewitemslidedeletebtnshow.QQListView.DelButtonClickListener; public class MainActivity extends Activity { private QQListView mListView; private ArrayAdapter<String> mAdapter; private List<String> mDatas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (QQListView) findViewById(R.id.id_listview); // 不要直接Arrays.asList mDatas = new ArrayList<String>(Arrays.asList("HelloWorld", "Welcome", "Java", "Android", "Servlet", "Struts", "Hibernate", "Spring", "HTML5", "Javascript", "Lucene")); mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDatas); mListView.setAdapter(mAdapter); mListView.setDelButtonClickListener(new DelButtonClickListener() { @Override public void clickHappend(final int position) { Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show(); mAdapter.remove(mAdapter.getItem(position)); } }); mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show(); } }); } }
樓主使用asm.jar以及gifcamera截的gif,由于button的動(dòng)畫很短感覺截圖效果很卡不流暢,大家有什么好的截圖,還望推薦。
有興趣的還是下載源碼看看效果,源碼下載
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 逐幀動(dòng)畫創(chuàng)建實(shí)例詳解
這篇文章主要介紹了Android 逐幀動(dòng)畫創(chuàng)建實(shí)例詳解的相關(guān)資料,這里主要說明Android 動(dòng)畫的創(chuàng)建及使用方法,希望通過此文能幫助到大家,需要的朋友可以參考下2017-08-08Android自定義View實(shí)現(xiàn)游戲搖桿鍵盤的方法示例
Android進(jìn)階過程中有一個(gè)繞不開的話題——自定義View。最近在做項(xiàng)目中又遇到了,所以下面這篇文章主要給大家介紹了利用Android自定義View實(shí)現(xiàn)游戲搖桿鍵盤的相關(guān)資料,操作方式類似王者榮耀的搖桿操作,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面來一起看看吧。2017-07-07Android開發(fā)Compose集成高德地圖實(shí)例
這篇文章主要為大家介紹了Android開發(fā)Compose里使用高德地圖實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08解析android中的幫助、about、關(guān)于作者、HELP等提示頁(yè)面
本篇文章是對(duì)android中的幫助、about、關(guān)于作者、HELP等提示頁(yè)面進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法
這篇文章主要介紹了Android實(shí)現(xiàn)在屏幕上移動(dòng)圖片的方法,實(shí)例分析了Android操作圖片的相關(guān)技巧,需要的朋友可以參考下2015-06-06Android 二維碼 生成和識(shí)別二維碼 附源碼下載
這篇文章主要介紹了Android 生成和識(shí)別二維碼的方法,提供源碼下載,需要的朋友可以參考下。2016-06-06Android自定義控件實(shí)現(xiàn)方向盤效果
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)方向盤效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04