Android ListView實(shí)現(xiàn)上拉加載下拉刷新和滑動(dòng)刪除功能
最近項(xiàng)目需要用到可以滑動(dòng)刪除并且?guī)в猩侠虞d下拉刷新的Listview,查閱了一些資料,大多都是在SwipeMenuListView的基礎(chǔ)上去添加頭部和底部View,來擴(kuò)展上拉加載和下拉刷新的功能,不過需要手動(dòng)的去繪制UI及處理一些動(dòng)畫效果.用起來也不是特別方便.剛好項(xiàng)目中用到PulltorefreshLibrary庫,就嘗試著擴(kuò)展了一個(gè)PullToRefreshSwipeMenuListView類來實(shí)現(xiàn)需求.先看一下效果:

實(shí)現(xiàn)步驟
一、組合Pulltorefresh與SwipeMenuListView
PulltorefreshLibrary庫中包含很多種可以上拉加載下拉刷新的控件,經(jīng)常用到的比如PullToRefreshListView,PullToRefreshGridView,PullToRefreshScrollView,它們的實(shí)現(xiàn)方式類似,本質(zhì)上是在控件外部添加父布局,父布局中去添加控件的頭部和底部View,來實(shí)現(xiàn)上拉加載下拉刷新的功能,所以擴(kuò)展性很強(qiáng).照貓畫虎,copy一份PullToRefreshListView,對(duì)他做一些處理.
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;
}
找到這部分代碼,簡(jiǎn)單的做下修改:
protected SwipeMenuListView createListView(Context context, AttributeSet attrs) {
final SwipeMenuListView lv;
lv = new SwipeMenuListView(context, attrs);
return lv;
}
為什么要copy一份PullToRefreshListView而不是其他的呢?因?yàn)镾wipeMenuListView是繼承自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;
}
是繼承父類實(shí)現(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);
看一下注釋,大概的意思是說,如果需要一個(gè)自定義的上拉加載下拉刷新View,可以返回該自定義View.并且返回值是T,一個(gè)泛型,說的很明白.看一下這個(gè)方法的引用mRefreshableView = createRefreshableView(context, attrs);看命名就知道,這個(gè)方法最終返回的是需要上拉加載下拉刷新功能的View.
感覺差不多可以了,來試一下,看一下效果:

好像效果不是很理想,有很多問題,比如滑動(dòng)刪除的時(shí)候可以上拉下拉,上拉時(shí)沒有底部View.接下來來解決這些問題.
二、解決滑動(dòng)沖突及相關(guān)問題
先來解決為什么沒有底部View的問題,看一下copy過來修改過的PullToRefreshSwipeMenuListView類和PullToRefreshListView類,對(duì)比一下到底有什么區(qū)別,使得PullToRefreshSwipeMenuListView沒有底部View,在PullToRefreshSwipeMenuListView中只修改了一個(gè)部分,就是把之前返回的InternalListView替換成了SwipeMenuListView,顯然問題出現(xiàn)在InternalListView上,查看一下InternalListView(很容易找,是個(gè)內(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方法時(shí)添加上的,那頭部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)頭部是在初始化的時(shí)候被添加上,而底部并沒有添加(代碼中…的部分),InternalListView在setAdapter方法中,添加上了底部,SwipeMenuListView中并沒有相關(guān)的處理,所以在…處添加代碼
mRefreshableView.addFooterView(mLvFooterLoadingFrame, null, false);把底部加上,之前發(fā)現(xiàn)的沒有底部的問題就解決了(當(dāng)然也可以仿照InternalListView去修改一下SwipeMenuListView,不過比較麻煩,這里就不去做了)
接下來處理一下滑動(dòng)刪除時(shí),可以進(jìn)行上拉下拉操作的問題,很明顯是滑動(dòng)沖突的問題,想一下,當(dāng)滑動(dòng)刪除時(shí),不希望進(jìn)行上拉下拉操作,而PullToRefreshSwipeMenuListView本身是一個(gè)ViewGroup,所以當(dāng)滑動(dòng)刪除時(shí),屏蔽掉父布局的滑動(dòng)事件就可以了,打開SwipeMenuListView,在滑動(dòng)事件中做一下處理即可:
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)沖突,當(dāng)處于滑動(dòng)刪除狀態(tài)時(shí),請(qǐng)求父布局不處理滑動(dòng)事件
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;
很簡(jiǎn)單,就不多做說明了,不太清楚點(diǎn)擊事件分發(fā)的童鞋,可以去查閱一下材料,這樣一個(gè)帶有上拉加載下拉刷新可滑動(dòng)刪除的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)沖突,當(dāng)處于滑動(dòng)刪除狀態(tài)時(shí),請(qǐng)求父布局不處理滑動(dòng)事件
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);
// 滑塊點(diǎn)擊事件
((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;
}
});
// 滑動(dòng)監(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);
}
});
// 點(diǎn)擊事件
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"> <!--上拉加載下拉刷新滑動(dòng)刪除控件--> <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í)研究。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android ExpandableListView實(shí)現(xiàn)下拉刷新和加載更多效果
- Android ListView實(shí)現(xiàn)下拉頂部圖片變大效果
- android使用SwipeRefreshLayout實(shí)現(xiàn)ListView下拉刷新上拉加載
- android使用PullToRefresh框架實(shí)現(xiàn)ListView下拉刷新上拉加載更多
- android ListView結(jié)合xutils3仿微信實(shí)現(xiàn)下拉加載更多
- Android中ListView下拉刷新的實(shí)現(xiàn)代碼
- Android自定義漸變式炫酷ListView下拉刷新動(dòng)畫
- Android自定義listview布局實(shí)現(xiàn)上拉加載下拉刷新功能
- Android XListView下拉刷新和上拉加載更多
- Android自定義控件ListView下拉刷新的代碼
相關(guān)文章
詳細(xì)講解Android中使用LoaderManager加載數(shù)據(jù)的方法
這篇文章主要介紹了Android中使用LoaderManager加載數(shù)據(jù)的方法,講到了LoaderManager的異步加載與聲明周期的管理等相關(guān)用法,需要的朋友可以參考下2016-04-04
Android WebView自定義長(zhǎng)按選擇實(shí)現(xiàn)收藏/分享選中文本功能
這篇文章主要介紹了Android WebView自定義長(zhǎng)按選擇實(shí)現(xiàn)收藏/分享選中文本功能,需要的朋友可以參考下2017-06-06
Android編程設(shè)計(jì)模式之Builder模式實(shí)例詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之Builder模式,結(jié)合實(shí)例形式詳細(xì)分析了Android設(shè)計(jì)模式之Builder模式概念、功能、使用場(chǎng)景、用法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-12-12
Android 手機(jī)獲取手機(jī)號(hào)實(shí)現(xiàn)方法
本文主要介紹Android 獲取手機(jī)號(hào)的實(shí)現(xiàn)方法,這里提供了實(shí)現(xiàn)方法,和具體操作流程,并符實(shí)現(xiàn)代碼,有需要的小伙伴可以參考下2016-09-09
Android kotlin+協(xié)程+Room數(shù)據(jù)庫的簡(jiǎn)單使用
這篇文章主要介紹了Android kotlin+協(xié)程+Room數(shù)據(jù)庫的簡(jiǎn)單使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
Android 中 Fragment 嵌套 Fragment使用存在的bug附完美解決方案
本文從兩個(gè)方面淺析Android 中 Fragment 嵌套 Fragment使用存在的bug問題,原因找到就可以完美的解決了,對(duì)fragment嵌套fragment使用相關(guān)知識(shí)感興趣的朋友一起看看吧2016-08-08
Android BLE 藍(lán)牙開發(fā)之實(shí)現(xiàn)掃碼槍基于BLESSED開發(fā)
這篇文章主要介紹了Android BLE 藍(lán)牙開發(fā)之實(shí)現(xiàn)掃碼槍基于BLESSED開發(fā),示例代碼介紹了第三方庫BLESSED for Android的使用,需要的朋友可以參考下2022-03-03
Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法
這篇文章主要介紹了Android如何通過命令行操作Sqlite3數(shù)據(jù)庫的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析
StrictMode意思為嚴(yán)格模式,是用來檢測(cè)程序中違例情況的開發(fā)者工具。最常用的場(chǎng)景就是檢測(cè)主線程中本地磁盤和網(wǎng)絡(luò)讀寫等耗時(shí)的操作。這篇文章給大家介紹Android性能調(diào)優(yōu)利器StrictMode應(yīng)用分析,感興趣的朋友一起看看吧2018-01-01

