Android ListView實現(xiàn)上拉加載下拉刷新和滑動刪除功能
最近項目需要用到可以滑動刪除并且?guī)в猩侠虞d下拉刷新的Listview,查閱了一些資料,大多都是在SwipeMenuListView的基礎(chǔ)上去添加頭部和底部View,來擴(kuò)展上拉加載和下拉刷新的功能,不過需要手動的去繪制UI及處理一些動畫效果.用起來也不是特別方便.剛好項目中用到PulltorefreshLibrary庫,就嘗試著擴(kuò)展了一個PullToRefreshSwipeMenuListView類來實現(xiàn)需求.先看一下效果:
實現(xiàn)步驟
一、組合Pulltorefresh與SwipeMenuListView
PulltorefreshLibrary庫中包含很多種可以上拉加載下拉刷新的控件,經(jīng)常用到的比如PullToRefreshListView,PullToRefreshGridView,PullToRefreshScrollView,它們的實現(xiàn)方式類似,本質(zhì)上是在控件外部添加父布局,父布局中去添加控件的頭部和底部View,來實現(xiàn)上拉加載下拉刷新的功能,所以擴(kuò)展性很強(qiáng).照貓畫虎,copy一份PullToRefreshListView,對他做一些處理.
protected ListView createListView(Context context, AttributeSet attrs) { final ListView lv; if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { lv = new InternalListViewSDK9(context, attrs); } else { lv = new InternalListView(context, attrs); } return lv; }
找到這部分代碼,簡單的做下修改:
protected SwipeMenuListView createListView(Context context, AttributeSet attrs) { final SwipeMenuListView lv; lv = new SwipeMenuListView(context, attrs); return lv; }
為什么要copy一份PullToRefreshListView而不是其他的呢?因為SwipeMenuListView是繼承自ListView的(看名字就可以發(fā)現(xiàn)),修改起來比較方便.為什么要修改這部分代碼呢?往下看.找一下引用這部分代碼的地方:
@Override protected ListView createRefreshableView(Context context, AttributeSet attrs) { ListView lv = createListView(context, attrs); // Set it to this so it can be used in ListActivity/ListFragment lv.setId(android.R.id.list); return lv; }
是繼承父類實現(xiàn)的方法,打開父類的該方法:
/** * This is implemented by derived classes to return the created View. If you * need to use a custom View (such as a custom ListView), override this * method and return an instance of your custom class. * <p/> * Be sure to set the ID of the view in this method, especially if you're * using a ListActivity or ListFragment. * * @param context Context to create view with * @param attrs AttributeSet from wrapped class. Means that anything you * include in the XML layout declaration will be routed to the * created View * @return New instance of the Refreshable View */ protected abstract T createRefreshableView(Context context, AttributeSet attrs);
看一下注釋,大概的意思是說,如果需要一個自定義的上拉加載下拉刷新View,可以返回該自定義View.并且返回值是T,一個泛型,說的很明白.看一下這個方法的引用mRefreshableView = createRefreshableView(context, attrs);看命名就知道,這個方法最終返回的是需要上拉加載下拉刷新功能的View.
感覺差不多可以了,來試一下,看一下效果:
好像效果不是很理想,有很多問題,比如滑動刪除的時候可以上拉下拉,上拉時沒有底部View.接下來來解決這些問題.
二、解決滑動沖突及相關(guān)問題
先來解決為什么沒有底部View的問題,看一下copy過來修改過的PullToRefreshSwipeMenuListView類和PullToRefreshListView類,對比一下到底有什么區(qū)別,使得PullToRefreshSwipeMenuListView沒有底部View,在PullToRefreshSwipeMenuListView中只修改了一個部分,就是把之前返回的InternalListView替換成了SwipeMenuListView,顯然問題出現(xiàn)在InternalListView上,查看一下InternalListView(很容易找,是個內(nèi)部類),可以看到這部分代碼:
@Override public void setAdapter(ListAdapter adapter) { // Add the Footer View at the last possible moment if (null != mLvFooterLoadingFrame && !mAddedLvFooter) { addFooterView(mLvFooterLoadingFrame, null, false); mAddedLvFooter = true; } super.setAdapter(adapter); }
底部View是在InternalListView調(diào)用setAdapter方法時添加上的,那頭部View呢?查找一下,找到如下代碼:
@Override protected void handleStyledAttributes(TypedArray a) { super.handleStyledAttributes(a); mListViewExtrasEnabled = a.getBoolean(com.handmark.pulltorefresh.library.R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true); if (mListViewExtrasEnabled) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); // Create Loading Views ready for use later FrameLayout frame = new FrameLayout(getContext()); mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a); mHeaderLoadingView.setVisibility(View.GONE); // FrameLayout添加頭View frame.addView(mHeaderLoadingView, lp); // 添加頭部View mRefreshableView.addHeaderView(frame, null, false); mLvFooterLoadingFrame = new FrameLayout(getContext()); mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a); mFooterLoadingView.setVisibility(View.GONE); // FrameLayout添加底部View mLvFooterLoadingFrame.addView(mFooterLoadingView, lp); // 添加底部View ... /** * If the value for Scrolling While Refreshing hasn't been * explicitly set via XML, enable Scrolling While Refreshing. */ if (!a.hasValue(com.handmark.pulltorefresh.library.R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) { setScrollingWhileRefreshingEnabled(true); } } }
發(fā)現(xiàn)頭部是在初始化的時候被添加上,而底部并沒有添加(代碼中…的部分),InternalListView在setAdapter方法中,添加上了底部,SwipeMenuListView中并沒有相關(guān)的處理,所以在…處添加代碼
mRefreshableView.addFooterView(mLvFooterLoadingFrame, null, false);把底部加上,之前發(fā)現(xiàn)的沒有底部的問題就解決了(當(dāng)然也可以仿照InternalListView去修改一下SwipeMenuListView,不過比較麻煩,這里就不去做了)
接下來處理一下滑動刪除時,可以進(jìn)行上拉下拉操作的問題,很明顯是滑動沖突的問題,想一下,當(dāng)滑動刪除時,不希望進(jìn)行上拉下拉操作,而PullToRefreshSwipeMenuListView本身是一個ViewGroup,所以當(dāng)滑動刪除時,屏蔽掉父布局的滑動事件就可以了,打開SwipeMenuListView,在滑動事件中做一下處理即可:
case MotionEvent.ACTION_MOVE: float dy = Math.abs((ev.getY() - mDownY)); float dx = Math.abs((ev.getX() - mDownX)); if (mTouchState == TOUCH_STATE_X) { if (mTouchView != null) { mTouchView.onSwipe(ev); } getSelector().setState(new int[]{0}); ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); // 處理滑動沖突,當(dāng)處于滑動刪除狀態(tài)時,請求父布局不處理滑動事件 requestDisallowInterceptTouchEvent(true); return true; } else if (mTouchState == TOUCH_STATE_NONE) { if (Math.abs(dy) > MAX_Y) { mTouchState = TOUCH_STATE_Y; } else if (dx > MAX_X) { mTouchState = TOUCH_STATE_X; if (mOnSwipeListener != null) { mOnSwipeListener.onSwipeStart(mTouchPosition); } } } break;
很簡單,就不多做說明了,不太清楚點擊事件分發(fā)的童鞋,可以去查閱一下材料,這樣一個帶有上拉加載下拉刷新可滑動刪除的ListView就基本完工了.
三、完整代碼
PullToRefreshSwipeMenuListView:
package swipemenulistview; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; import android.widget.ListAdapter; import android.widget.ListView; import com.handmark.pulltorefresh.library.LoadingLayoutProxy; import com.handmark.pulltorefresh.library.PullToRefreshAdapterViewBase; import com.handmark.pulltorefresh.library.internal.LoadingLayout; /** * Created by junweiliu on 16/10/12. */ public class PullToRefreshSwipeMenuListView extends PullToRefreshAdapterViewBase<ListView> { private LoadingLayout mHeaderLoadingView; private LoadingLayout mFooterLoadingView; private FrameLayout mLvFooterLoadingFrame; private boolean mListViewExtrasEnabled; public PullToRefreshSwipeMenuListView(Context context) { super(context); } public PullToRefreshSwipeMenuListView(Context context, AttributeSet attrs) { super(context, attrs); } public PullToRefreshSwipeMenuListView(Context context, Mode mode) { super(context, mode); } public PullToRefreshSwipeMenuListView(Context context, Mode mode, AnimationStyle style) { super(context, mode, style); } @Override public final Orientation getPullToRefreshScrollDirection() { return Orientation.VERTICAL; } @Override protected void onRefreshing(final boolean doScroll) { /** * If we're not showing the Refreshing view, or the list is empty, the * the header/footer views won't show so we use the normal method. */ ListAdapter adapter = mRefreshableView.getAdapter(); if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) { super.onRefreshing(doScroll); return; } super.onRefreshing(false); final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView; final int selection, scrollToY; switch (getCurrentMode()) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: origLoadingView = getFooterLayout(); listViewLoadingView = mFooterLoadingView; oppositeListViewLoadingView = mHeaderLoadingView; selection = mRefreshableView.getCount() - 1; scrollToY = getScrollY() - getFooterSize(); break; case PULL_FROM_START: default: origLoadingView = getHeaderLayout(); listViewLoadingView = mHeaderLoadingView; oppositeListViewLoadingView = mFooterLoadingView; selection = 0; scrollToY = getScrollY() + getHeaderSize(); break; } // Hide our original Loading View origLoadingView.reset(); origLoadingView.hideAllViews(); // Make sure the opposite end is hidden too oppositeListViewLoadingView.setVisibility(View.GONE); // Show the ListView Loading View and set it to refresh. listViewLoadingView.setVisibility(View.VISIBLE); listViewLoadingView.refreshing(); if (doScroll) { // We need to disable the automatic visibility changes for now disableLoadingLayoutVisibilityChanges(); // We scroll slightly so that the ListView's header/footer is at the // same Y position as our normal header/footer setHeaderScroll(scrollToY); // Make sure the ListView is scrolled to show the loading // header/footer mRefreshableView.setSelection(selection); // Smooth scroll as normal smoothScrollTo(0); } } @Override protected void onReset() { /** * If the extras are not enabled, just call up to super and return. */ if (!mListViewExtrasEnabled) { super.onReset(); return; } final LoadingLayout originalLoadingLayout, listViewLoadingLayout; final int scrollToHeight, selection; final boolean scrollLvToEdge; switch (getCurrentMode()) { case MANUAL_REFRESH_ONLY: case PULL_FROM_END: originalLoadingLayout = getFooterLayout(); listViewLoadingLayout = mFooterLoadingView; selection = mRefreshableView.getCount() - 1; scrollToHeight = getFooterSize(); scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1; break; case PULL_FROM_START: default: originalLoadingLayout = getHeaderLayout(); listViewLoadingLayout = mHeaderLoadingView; scrollToHeight = -getHeaderSize(); selection = 0; scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1; break; } // If the ListView header loading layout is showing, then we need to // flip so that the original one is showing instead if (listViewLoadingLayout.getVisibility() == View.VISIBLE) { // Set our Original View to Visible originalLoadingLayout.showInvisibleViews(); // Hide the ListView Header/Footer listViewLoadingLayout.setVisibility(View.GONE); /** * Scroll so the View is at the same Y as the ListView * header/footer, but only scroll if: we've pulled to refresh, it's * positioned correctly */ if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) { mRefreshableView.setSelection(selection); setHeaderScroll(scrollToHeight); } } // Finally, call up to super super.onReset(); } @Override protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) { LoadingLayoutProxy proxy = super.createLoadingLayoutProxy(includeStart, includeEnd); if (mListViewExtrasEnabled) { final Mode mode = getMode(); if (includeStart && mode.showHeaderLoadingLayout()) { proxy.addLayout(mHeaderLoadingView); } if (includeEnd && mode.showFooterLoadingLayout()) { proxy.addLayout(mFooterLoadingView); } } return proxy; } protected SwipeMenuListView createListView(Context context, AttributeSet attrs) { final SwipeMenuListView lv; // if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { // lv = new InternalListViewSDK9(context, attrs); // } else { // lv = new InternalListView(context, attrs); // } lv = new SwipeMenuListView(context, attrs); return lv; } @Override protected ListView createRefreshableView(Context context, AttributeSet attrs) { ListView lv = createListView(context, attrs); // Set it to this so it can be used in ListActivity/ListFragment lv.setId(android.R.id.list); return lv; } @Override protected void handleStyledAttributes(TypedArray a) { super.handleStyledAttributes(a); mListViewExtrasEnabled = a.getBoolean(com.handmark.pulltorefresh.library.R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true); if (mListViewExtrasEnabled) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL); // Create Loading Views ready for use later FrameLayout frame = new FrameLayout(getContext()); mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a); mHeaderLoadingView.setVisibility(View.GONE); frame.addView(mHeaderLoadingView, lp); mRefreshableView.addHeaderView(frame, null, false); mLvFooterLoadingFrame = new FrameLayout(getContext()); mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a); mFooterLoadingView.setVisibility(View.GONE); mLvFooterLoadingFrame.addView(mFooterLoadingView, lp); // 添加底部加載view mRefreshableView.addFooterView(mLvFooterLoadingFrame, null, false); /** * If the value for Scrolling While Refreshing hasn't been * explicitly set via XML, enable Scrolling While Refreshing. */ if (!a.hasValue(com.handmark.pulltorefresh.library.R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) { setScrollingWhileRefreshingEnabled(true); } } } }
SwipeMenuListView:
package swipemenulistview; import android.content.Context; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.view.animation.Interpolator; import android.widget.ListAdapter; import android.widget.ListView; /** * @author baoyz * @date 2014-8-18 */ public class SwipeMenuListView extends ListView { private static final int TOUCH_STATE_NONE = 0; private static final int TOUCH_STATE_X = 1; private static final int TOUCH_STATE_Y = 2; public static final int DIRECTION_LEFT = 1; public static final int DIRECTION_RIGHT = -1; private int mDirection = 1;//swipe from right to left by default private int MAX_Y = 5; private int MAX_X = 3; private float mDownX; private float mDownY; private int mTouchState; private int mTouchPosition; private SwipeMenuLayout mTouchView; private OnSwipeListener mOnSwipeListener; private SwipeMenuCreator mMenuCreator; private OnMenuItemClickListener mOnMenuItemClickListener; private Interpolator mCloseInterpolator; private Interpolator mOpenInterpolator; public SwipeMenuListView(Context context) { super(context); init(); } public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public SwipeMenuListView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { MAX_X = dp2px(MAX_X); MAX_Y = dp2px(MAX_Y); mTouchState = TOUCH_STATE_NONE; } @Override public void setAdapter(ListAdapter adapter) { super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) { @Override public void createMenu(SwipeMenu menu) { if (mMenuCreator != null) { mMenuCreator.create(menu); } } @Override public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) { boolean flag = false; if (mOnMenuItemClickListener != null) { flag = mOnMenuItemClickListener.onMenuItemClick( view.getPosition(), menu, index); } if (mTouchView != null && !flag) { mTouchView.smoothCloseMenu(); } } }); } public void setCloseInterpolator(Interpolator interpolator) { mCloseInterpolator = interpolator; } public void setOpenInterpolator(Interpolator interpolator) { mOpenInterpolator = interpolator; } public Interpolator getOpenInterpolator() { return mOpenInterpolator; } public Interpolator getCloseInterpolator() { return mCloseInterpolator; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null) return super.onTouchEvent(ev); int action = MotionEventCompat.getActionMasked(ev); action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: int oldPos = mTouchPosition; mDownX = ev.getX(); mDownY = ev.getY(); mTouchState = TOUCH_STATE_NONE; mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); if (mTouchPosition == oldPos && mTouchView != null && mTouchView.isOpen()) { mTouchState = TOUCH_STATE_X; mTouchView.onSwipe(ev); return true; } View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); if (mTouchView != null && mTouchView.isOpen()) { mTouchView.smoothCloseMenu(); mTouchView = null; // return super.onTouchEvent(ev); // try to cancel the touch event MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent.setAction(MotionEvent.ACTION_CANCEL); onTouchEvent(cancelEvent); return true; } if (view instanceof SwipeMenuLayout) { mTouchView = (SwipeMenuLayout) view; mTouchView.setSwipeDirection(mDirection); } if (mTouchView != null) { mTouchView.onSwipe(ev); } break; case MotionEvent.ACTION_MOVE: float dy = Math.abs((ev.getY() - mDownY)); float dx = Math.abs((ev.getX() - mDownX)); if (mTouchState == TOUCH_STATE_X) { if (mTouchView != null) { mTouchView.onSwipe(ev); } getSelector().setState(new int[]{0}); ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); // 處理滑動沖突,當(dāng)處于滑動刪除狀態(tài)時,請求父布局不處理滑動事件 requestDisallowInterceptTouchEvent(true); return true; } else if (mTouchState == TOUCH_STATE_NONE) { if (Math.abs(dy) > MAX_Y) { mTouchState = TOUCH_STATE_Y; } else if (dx > MAX_X) { mTouchState = TOUCH_STATE_X; if (mOnSwipeListener != null) { mOnSwipeListener.onSwipeStart(mTouchPosition); } } } break; case MotionEvent.ACTION_UP: requestDisallowInterceptTouchEvent(false); if (mTouchState == TOUCH_STATE_X) { if (mTouchView != null) { mTouchView.onSwipe(ev); if (!mTouchView.isOpen()) { mTouchPosition = -1; mTouchView = null; } } if (mOnSwipeListener != null) { mOnSwipeListener.onSwipeEnd(mTouchPosition); } ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; } break; } return super.onTouchEvent(ev); } public void smoothOpenMenu(int position) { if (position >= getFirstVisiblePosition() && position <= getLastVisiblePosition()) { View view = getChildAt(position - getFirstVisiblePosition()); if (view instanceof SwipeMenuLayout) { mTouchPosition = position; if (mTouchView != null && mTouchView.isOpen()) { mTouchView.smoothCloseMenu(); } mTouchView = (SwipeMenuLayout) view; mTouchView.setSwipeDirection(mDirection); mTouchView.smoothOpenMenu(); } } } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics()); } public void setMenuCreator(SwipeMenuCreator menuCreator) { this.mMenuCreator = menuCreator; } public void setOnMenuItemClickListener( OnMenuItemClickListener onMenuItemClickListener) { this.mOnMenuItemClickListener = onMenuItemClickListener; } public void setOnSwipeListener(OnSwipeListener onSwipeListener) { this.mOnSwipeListener = onSwipeListener; } public static interface OnMenuItemClickListener { boolean onMenuItemClick(int position, SwipeMenu menu, int index); } public static interface OnSwipeListener { void onSwipeStart(int position); void onSwipeEnd(int position); } public void setSwipeDirection(int direction) { mDirection = direction; } }
MainActivity:
package com.example.junweiliu.pulltorefreshswipemenulistviewdemo; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.util.TypedValue; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import com.handmark.pulltorefresh.library.PullToRefreshBase; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import swipemenulistview.PullToRefreshSwipeMenuListView; import swipemenulistview.SwipeMenu; import swipemenulistview.SwipeMenuCreator; import swipemenulistview.SwipeMenuItem; import swipemenulistview.SwipeMenuListView; public class MainActivity extends AppCompatActivity { /** * 控件 */ private PullToRefreshSwipeMenuListView mPullToRefreshSwipeMenuListView; /** * 適配器 */ private SimpleAdapter mAdapter; /** * 數(shù)據(jù)源 */ List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>(); /** * 信息 */ private String[] message = {"數(shù)據(jù)0", "數(shù)據(jù)1", "數(shù)據(jù)2", "數(shù)據(jù)3", "數(shù)據(jù)4", "數(shù)據(jù)5", "數(shù)據(jù)6", "數(shù)據(jù)7", "數(shù)據(jù)8", "數(shù)據(jù)9", "數(shù)據(jù)10"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); } /** * 初始化控件 */ private void initView() { mPullToRefreshSwipeMenuListView = (PullToRefreshSwipeMenuListView) findViewById(R.id.psl_demo); mAdapter = new SimpleAdapter(this, datas, R.layout.item_adapter, new String[]{"message"}, new int[]{R.id.tv_message}); mPullToRefreshSwipeMenuListView.setMode(PullToRefreshBase.Mode.BOTH); mPullToRefreshSwipeMenuListView.setAdapter(mAdapter); // 創(chuàng)建刪除滑塊 SwipeMenuCreator creator = new SwipeMenuCreator() { @Override public void create(SwipeMenu menu) { SwipeMenuItem deleteItem = new SwipeMenuItem( getApplicationContext()); deleteItem.setBackground(new ColorDrawable(Color.rgb(0xFF, 0x20, 0x20))); deleteItem.setWidth(dp2px(63)); // deleteItem.setIcon(R.drawable.ic_delete); deleteItem.setTitle("刪除"); deleteItem.setTitleSize(14); deleteItem.setTitleColor(Color.WHITE); menu.addMenuItem(deleteItem); } }; // 設(shè)置滑塊 ((SwipeMenuListView) mPullToRefreshSwipeMenuListView.getRefreshableView()).setMenuCreator(creator); // 滑塊點擊事件 ((SwipeMenuListView) mPullToRefreshSwipeMenuListView.getRefreshableView()).setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(int position, SwipeMenu menu, int index) { switch (index) { case 0: Toast.makeText(MainActivity.this, "刪除我了" + position, Toast.LENGTH_SHORT).show(); break; } return false; } }); // 滑動監(jiān)聽 ((SwipeMenuListView) mPullToRefreshSwipeMenuListView.getRefreshableView()).setOnSwipeListener(new SwipeMenuListView.OnSwipeListener() { @Override public void onSwipeStart(int position) { } @Override public void onSwipeEnd(int position) { } }); // 刷新加載事件 mPullToRefreshSwipeMenuListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() { @Override public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) { new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { Toast.makeText(MainActivity.this, "刷新成功", Toast.LENGTH_SHORT).show(); mPullToRefreshSwipeMenuListView.onRefreshComplete(); return false; } }).sendEmptyMessageDelayed(1, 1000); } @Override public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) { new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { Toast.makeText(MainActivity.this, "加載成功", Toast.LENGTH_SHORT).show(); mPullToRefreshSwipeMenuListView.onRefreshComplete(); return false; } }).sendEmptyMessageDelayed(2, 1000); } }); // 點擊事件 mPullToRefreshSwipeMenuListView.getRefreshableView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { } }); } /** * 初始化數(shù)據(jù) */ private void initData() { for (int i = 0; i < message.length; i++) { Map<String, Object> data = new HashMap<String, Object>(); data.put("message", message[i]); datas.add(data); } } /** * dp轉(zhuǎn)px * * @param dp * @return */ private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } }
activity_main:
<?xml version="1.0" encoding="utf-8"?> <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" tools:context="com.example.junweiliu.pulltorefreshswipemenulistviewdemo.MainActivity"> <!--上拉加載下拉刷新滑動刪除控件--> <swipemenulistview.PullToRefreshSwipeMenuListView android:id="@+id/psl_demo" android:layout_width="match_parent" android:layout_height="match_parent" > </swipemenulistview.PullToRefreshSwipeMenuListView> </RelativeLayout>
item_adapter:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/tv_message" android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingBottom="30dp" android:paddingTop="30dp" android:text="數(shù)據(jù)" android:textColor="@android:color/black" android:textSize="16sp"/> </LinearLayout>
本文已經(jīng)被整理到《Android下拉刷新上拉加載效果》,歡迎大家學(xué)習(xí)研究。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android ExpandableListView實現(xiàn)下拉刷新和加載更多效果
- Android ListView實現(xiàn)下拉頂部圖片變大效果
- android使用SwipeRefreshLayout實現(xiàn)ListView下拉刷新上拉加載
- android使用PullToRefresh框架實現(xiàn)ListView下拉刷新上拉加載更多
- android ListView結(jié)合xutils3仿微信實現(xiàn)下拉加載更多
- Android中ListView下拉刷新的實現(xiàn)代碼
- Android自定義漸變式炫酷ListView下拉刷新動畫
- Android自定義listview布局實現(xiàn)上拉加載下拉刷新功能
- Android XListView下拉刷新和上拉加載更多
- Android自定義控件ListView下拉刷新的代碼
相關(guān)文章
詳細(xì)講解Android中使用LoaderManager加載數(shù)據(jù)的方法
這篇文章主要介紹了Android中使用LoaderManager加載數(shù)據(jù)的方法,講到了LoaderManager的異步加載與聲明周期的管理等相關(guān)用法,需要的朋友可以參考下2016-04-04Android WebView自定義長按選擇實現(xiàn)收藏/分享選中文本功能
這篇文章主要介紹了Android WebView自定義長按選擇實現(xiàn)收藏/分享選中文本功能,需要的朋友可以參考下2017-06-06Android編程設(shè)計模式之Builder模式實例詳解
這篇文章主要介紹了Android編程設(shè)計模式之Builder模式,結(jié)合實例形式詳細(xì)分析了Android設(shè)計模式之Builder模式概念、功能、使用場景、用法及相關(guān)注意事項,需要的朋友可以參考下2017-12-12Android 手機(jī)獲取手機(jī)號實現(xiàn)方法
本文主要介紹Android 獲取手機(jī)號的實現(xiàn)方法,這里提供了實現(xiàn)方法,和具體操作流程,并符實現(xiàn)代碼,有需要的小伙伴可以參考下2016-09-09Android kotlin+協(xié)程+Room數(shù)據(jù)庫的簡單使用
這篇文章主要介紹了Android kotlin+協(xié)程+Room數(shù)據(jù)庫的簡單使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01Android 中 Fragment 嵌套 Fragment使用存在的bug附完美解決方案
本文從兩個方面淺析Android 中 Fragment 嵌套 Fragment使用存在的bug問題,原因找到就可以完美的解決了,對fragment嵌套fragment使用相關(guān)知識感興趣的朋友一起看看吧2016-08-08Android BLE 藍(lán)牙開發(fā)之實現(xiàn)掃碼槍基于BLESSED開發(fā)
這篇文章主要介紹了Android BLE 藍(lán)牙開發(fā)之實現(xiàn)掃碼槍基于BLESSED開發(fā),示例代碼介紹了第三方庫BLESSED for Android的使用,需要的朋友可以參考下2022-03-03Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法
這篇文章主要介紹了Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析
StrictMode意思為嚴(yán)格模式,是用來檢測程序中違例情況的開發(fā)者工具。最常用的場景就是檢測主線程中本地磁盤和網(wǎng)絡(luò)讀寫等耗時的操作。這篇文章給大家介紹Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析,感興趣的朋友一起看看吧2018-01-01