Android 类ListView下拉刷新控件实现

Android 类ListView下拉刷新控件实现Android下拉刷新,在目前好多应用被使用到。

比如微博,下拉刷新更多数据。

一般我们在运用的ListView,本身就实现了下拉获取更多数据。

只是这个下拉刷新的操作时在listView拉到底端的监听。

对于ListView刷新,我们可以分为两种情况:1.获取更多的数据,按服务器数据库时间顺序存储入情况,此刻我们是获取是显示在我们应用中的数据更早前的数据,这也是最常见的情况。

比如(微博获取更多信息,就是获取更多更早前的信息,然后动态的添加到已有的数据的下方);2.获取更多的最新的数据,其实还是一种获取更多的操作方式。

但是这里主要考虑到用户的操作习惯了。

一般,用户的操作习惯分这么两种第一种,获取下一页,第二种,类似于网页的F5刷新,停留在当前页面的刷新。

ListView刷新其实类似于网页。

如果没用下拉刷新,那么用户得将ListView拖拉到最后(当然也可以是在界面顶端添加一个刷新按钮控件,但是,对于手机这样界面不是很大,这样的设计其实是不应太多的。

),如果数据太多,那么用户要下拉到很下面才能执行刷新。

而对于大多数用户习惯,获取更多的最新资讯后,希望他添加的时候是在界面最上面的显眼处的。

也就是,用户还是喜欢的是懒操作,在同一个可显示界面完成所有操作。

那么,下拉刷新是一个不错的设计。

效果图:正常状态下拉刷新:基本效果就是这样。

自定义控件代码。

/*** 刷新控制view** @author Nono**/public class RefreshableView extends LinearLayout {private static final String TAG = "LILITH";private Scroller scroller;private View refreshView;private ImageView refreshIndicatorView;private int refreshTargetTop = -60;private ProgressBar bar;private TextView downTextView;private TextView timeTextView;private RefreshListener refreshListener;private String downTextString;private String releaseTextString;private Long refreshTime = null;private int lastX;private int lastY;//拉动标记private boolean isDragging = false;//是否可刷新标记private boolean isRefreshEnabled = true;//在刷新中标记private boolean isRefreshing = false;private Context mContext;public RefreshableView(Context context) {super(context);mContext = context;}public RefreshableView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;init();}private void init() {//TODO Auto-generated method stub//滑动对象,scroller = new Scroller(mContext);//刷新视图顶端的的viewrefreshView =LayoutInflater.from(mContext).inflate(yout.refresh_top_i tem, null);//指示器viewrefreshIndicatorView = (ImageView)refreshView.findViewById(R.id.indicator);//刷新barbar = (ProgressBar)refreshView.findViewById(R.id.progress);//下拉显示textdownTextView = (TextView)refreshView.findViewById(R.id.refresh_hint);//下来显示时间timeTextView = (TextView)refreshView.findViewById(R.id.refresh_time);LayoutParams lp = newyoutParams(LayoutParams.FILL_PARENT,-refreshTargetTop);lp.topMargin = refreshTargetTop;lp.gravity = Gravity.CENTER;addView(refreshView, lp);downTextString =mContext.getResources().getString(R.string.refresh_down_text );releaseTextString =mContext.getResources().getString(R.string.refresh_release_t ext);}/*** 刷新* @param time*/private void setRefreshText(String time) {//TODO Auto-generated method stub//timeTextView.setText(time);}@Overridepublic boolean onTouchEvent(MotionEvent event) { int y= (int) event.getRawY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN://记录下y坐标lastY = y;break;case MotionEvent.ACTION_MOVE:Log.i(TAG, "ACTION_MOVE");//y移动坐标int m = y - lastY;if(((m < 6) && (m > -1)) || (!isDragging )){ doMovement(m);}//记录下此刻y坐标stY = y;break;case MotionEvent.ACTION_UP:Log.i(TAG, "ACTION_UP");fling();break;}return true;}/*** up事件处理*/private void fling() {//TODO Auto-generated method stubyoutParams lp = (LayoutParams) refreshView.getLayoutParams();Log.i(TAG, "fling()" + lp.topMargin);if(lp.topMargin > 0){//拉到了触发可刷新事件refresh();}else{returnInitState();}}private void returnInitState() {//TODO Auto-generated method stubyoutParams lp =(youtParams)this.refreshView.getLayoutParams( );int i = lp.topMargin;scroller.startScroll(0, i, 0, refreshTargetTop);invalidate();}private void refresh() {//TODO Auto-generated method stubyoutParams lp =(youtParams)this.refreshView.getLayoutParams( );int i = lp.topMargin;refreshIndicatorView.setVisibility(View.GONE);bar.setVisibility(View.VISIBLE);timeTextView.setVisibility(View.GONE);downTextView.setVisibility(View.GONE);scroller.startScroll(0, i, 0, 0-i);invalidate();if(refreshListener !=null){refreshListener.onRefresh(this);isRefreshing = true;}}/****/@Overridepublic void computeScroll() {//TODO Auto-generated method stubif(puteScrollOffset()){int i = this.scroller.getCurrY();youtParams lp = (youtParams)this.refreshView.getLayoutParams( );int k = Math.max(i, refreshTargetTop);lp.topMargin = k;this.refreshView.setLayoutParams(lp);this.refreshView.invalidate();invalidate();}}/*** 下拉move事件处理* @param moveY*/private void doMovement(int moveY) {//TODO Auto-generated method stubyoutParams lp = (LayoutParams) refreshView.getLayoutParams();if(moveY > 0){//获取view的上边距float f1 =lp.topMargin;float f2 = moveY * 0.3F;int i = (int)(f1+f2);//修改上边距lp.topMargin = i;//修改后刷新refreshView.setLayoutParams(lp);refreshView.invalidate();invalidate();}timeTextView.setVisibility(View.VISIBLE);if(refreshTime!= null){setRefreshTime(refreshTime);}downTextView.setVisibility(View.VISIBLE);refreshIndicatorView.setVisibility(View.VISIBLE);bar.setVisibility(View.GONE);if(lp.topMargin > 0){downTextView.setText(R.string.refresh_release_text); refreshIndicatorView.setImageResource(R.drawable.refresh_arr ow_up);}else{downTextView.setText(R.string.refresh_down_text); refreshIndicatorView.setImageResource(R.drawable.refresh_arr ow_down);}}public void setRefreshEnabled(boolean b) {this.isRefreshEnabled = b;}public void setRefreshListener(RefreshListener listener) {this.refreshListener = listener;}/*** 刷新时间* @param refreshTime2*/private void setRefreshTime(Long time) {//TODO Auto-generated method stub}/*** 结束刷新事件*/public void finishRefresh(){Log.i(TAG, "执行了=====finishRefresh");youtParams lp=(youtParams)this.refreshView.getLayoutParams( );int i = lp.topMargin;refreshIndicatorView.setVisibility(View.VISIBLE); timeTextView.setVisibility(View.VISIBLE);scroller.startScroll(0, i, 0, refreshTargetTop); invalidate();isRefreshing = false;}/*该方法一般和ontouchEvent 一起用* (non-Javadoc)* @seeandroid.view.ViewGroup#onInterceptTouchEvent(android.vi ew.MotionEvent)*/@Overridepublic boolean onInterceptTouchEvent(MotionEvent e) { //TODO Auto-generated method stubint action = e.getAction();int y= (int) e.getRawY();switch (action) {case MotionEvent.ACTION_DOWN:lastY = y;break;case MotionEvent.ACTION_MOVE://y移动坐标int m = y - lastY;//记录下此刻y坐标stY = y;if(m > 6 && canScroll()){return true;}break;case MotionEvent.ACTION_UP:break;case MotionEvent.ACTION_CANCEL:break;}return false;}private boolean canScroll() {//TODO Auto-generated method stubView childView;if(getChildCount()>1){childView = this.getChildAt(1);if(childView instanceof ListView){int top=((ListView)childView).getChildAt(0).getTop();int pad=((ListView)childView).getListPaddingTop();if((Math.abs(top-pad)) < 3&&((ListView)childView).getFirstVisiblePosition() == 0){return true;}else{return false;}}else if(childView instanceof ScrollView){if(((ScrollView)childView).getScrollY() == 0){return true;}else{return false;}}}return false;}/*** 刷新监听接口* @author Nono**/public interface RefreshListener{public void onRefresh(RefreshableView view);}}此控件自定义实现一个线性布局,内部包含一个第一个子控件,刷新显示的View。

合集下载

(Android)五分钟让你轻松学会下拉刷新和上拉加载更多

(Android)五分钟让你轻松学会下拉刷新和上拉加载更多

(Android)五分钟让你轻松学会下拉刷新和上拉加载更多为了更好的学习和工作,动动小手收藏起来吧!分享一个谷歌自带的下拉刷新和上拉加载更多例子:效果图:自定义RefreshLayout继承 SwipeRefreshLayout/*** 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.*/public class RefreshLayout extends SwipeRefreshLayout implementsOnScrollListener {/*** 滑动到最下面时的上拉操作*/private int mT ouchSlop;/*** listview实例*/private ListView mListView;/*** 上拉监听器, 到了最底部的上拉加载操作*/private OnLoadListener mOnLoadListener;/*** ListView的加载中footer*/private View mListViewFooter;/*** 按下时的y坐标*/private int mYDown;/*** 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉*/private int mLastY;/*** 是否在加载中 ( 上拉加载更多 )*/private boolean isLoading = false;/*** @param context*/public RefreshLayout(Context context) {this(context, null);}@SuppressLint("InflateParams")public RefreshLayout(Context context, AttributeSet attrs) {super(context, attrs);mTouchSlop =ViewConfiguration.get(context).getScaledTouchSlop();mListViewFooter = LayoutInflater.from(context).inflate(yout.listview_footer, null, false);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);// 初始化ListView对象if (mListView == null) {getListView();}}/*** 获取ListView对象*/private void getListView() {int childs = getChildCount();if (childs > 0) {View childView = getChildAt(0);if (childView instanceof ListView) {mListView = (ListView) childView;// 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载mListView.setOnScrollListener(this);Log.d(VIEW_LOG_TAG, "### 找到listview");}}}/** (non-Javadoc)** @see android.view.ViewGroup#dispatchT ouchEvent(android.view.Moti onEvent)*/@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {final int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:// 按下mYDown = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:// 移动mLastY = (int) event.getRawY();break;case MotionEvent.ACTION_UP:// 抬起if (canLoad()) {loadData();}break;default:break;}return super.dispatchT ouchEvent(event);}/*** 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.** @return*/private boolean canLoad() {return isBottom() && !isLoading && isPullUp();}/*** 判断是否到了最底部*/private boolean isBottom() {if (mListView != null && mListView.getAdapter() != null) {return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);}return false;}/*** 是否是上拉操作** @return*/private boolean isPullUp() {return (mYDown - mLastY) >= mT ouchSlop;}/*** 如果到了最底部,而且是上拉操作.那么执行onLoad方法*/private void loadData() {if (mOnLoadListener != null) {// 设置状态setLoading(true);//mOnLoadListener.onLoad();}}/*** @param loading*/public void setLoading(boolean loading) {isLoading = loading;if (isLoading) {mListView.addFooterView(mListViewFooter);} else {mListView.removeFooterView(mListViewFooter);mYDown = 0;mLastY = 0;}}/*** @param loadListener*/public void setOnLoadListener(OnLoadListener loadListener) {mOnLoadListener = loadListener;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// 滚动时到了最底部也可以加载更多if (canLoad()) {loadData();}}/*** 设置刷新*/public static void setRefreshing(SwipeRefreshLayout refreshLayout,boolean refreshing, boolean notify) {Class<? extends SwipeRefreshLayout> refreshLayoutClass = refreshLayout.getClass();if (refreshLayoutClass != null) {try {Method setRefreshing = refreshLayoutClass.getDeclaredMethod("setRefreshing", boolean.class, boolean.class);setRefreshing.setAccessible(true);setRefreshing.invoke(refreshLayout, refreshing, notify);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}/*** 加载更多的监听器*/public static interface OnLoadListener {public void onLoad();}}public class MainActivity extends Activity implements OnRefreshListener,OnLoadListener {private RefreshLayout swipeLayout;private ListView listView;private MyAdapter adapter;private ArrayList<HashMap<String, String>> list;private View header;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);initView();setData();setListener();/*设置自动刷新 swipeLayout.setRefreshing(true);在 setRefreshing(true)并没有触发onRefresh的,须要手动调用一次*/// swipeLayout.post(new Thread(new Runnable() {// @Override// public void run() {// swipeLayout.setRefreshing(true);// }// }));// onRefresh();}/*** 初始化布局*/@SuppressLint({ "InlinedApi", "InflateParams" })private void initView() {header = getLayoutInflater().inflate(yout.header, null);swipeLayout = (RefreshLayout) findViewById(R.id.swipe_container);swipeLayout.setColorSchemeResources(R.color.color_bule2, R.color.color_bule,R.color.color_bule2,R.color.color_bule3);}/*** 添加数据*/private void setData() {list = new ArrayList<HashMap<String, String>>();for (int i = 0; i < 10; i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("itemImage", i+"默认");map.put("itemText", i+"默认");list.add(map);}listView = (ListView) findViewById(R.id.list);listView.addHeaderView(header);adapter = new MyAdapter(this, list);listView.setAdapter(adapter);}/*** 设置监听*/private void setListener() {swipeLayout.setOnRefreshListener(this);swipeLayout.setOnLoadListener(this);}/*** 上拉刷新*/@Overridepublic void onRefresh() {swipeLayout.postDelayed(new Runnable() {@Overridepublic void run() {// 更新数据更新完后调用该方法结束刷新list.clear();for (int i = 0; i < 8; i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("itemImage", i+"刷新");map.put("itemText", i+"刷新");list.add(map);}adapter.notifyDataSetChanged();swipeLayout.setRefreshing(false);}}, 2000);}/*** 加载更多*/@Overridepublic void onLoad() {swipeLayout.postDelayed(new Runnable() {@Overridepublic void run() {// 更新数据更新完后调用该方法结束刷新swipeLayout.setLoading(false);for (int i = 1; i < 10; i++) {HashMap<String, String> map = new HashMap<String, String>();map.put("itemImage", i+"更多");map.put("itemText", i+"更多");list.add(map);}adapter.notifyDataSetChanged();}}, 2000);}public class MyAdapter extends BaseAdapter {public ArrayList<HashMap<String, String>> list;public Context context;public LayoutInflater layoutInflater;public MyAdapter(Context context, ArrayList<HashMap<String, String>> list) {this.context = context;this.list = list;layoutInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {View view = null;ViewHolder holder = null;if (convertView == null) {view = layoutInflater.inflate(yout.item, null);holder = new ViewHolder();holder.txt =(TextView) view.findViewById(R.id.textView1);view.setTag(holder);} else {view = convertView;holder = (ViewHolder) view.getTag();}holder.txt.setText(list.get(position).get("itemText")); return view;}static class ViewHolder {TextView txt;}}源码下载地址,请回复刷新即可。

listview控件的用法

listview控件的用法

listview控件的用法ListView控件是Android开发中常用的界面控件之一,用于展示大量数据或者是滚动显示内容。

一、ListView的基本使用1. 在XML布局文件中添加ListView控件:```<ListViewandroid:layout_width="match_parent"android:layout_height="match_parent" />```2. 在Java代码中获取ListView控件的引用:```ListView listView = findViewById(R.id.listView);```3. 准备数据源(一般是一个集合),并创建适配器Adapter:```List<String> dataList = new ArrayList<>(;dataList.add("数据1");dataList.add("数据2");//...ArrayAdapter<String> adapter = new ArrayAdapter<>(this, yout.simple_list_item_1, dataList);```4. 将适配器设置到ListView中:```listView.setAdapter(adapter);```二、ListView的常用属性和方法1.常用属性:- android:divider:设置列表项之间的分割线;- android:dividerHeight:设置列表项之间的分割线的高度;- android:headerDividersEnabled:是否显示ListView的头部分割线;- android:footerDividersEnabled:是否显示ListView的尾部分割线;- android:listSelector:设置列表项选中时的背景颜色;- android:scrollbarStyle:设置滚动条的样式。

android pulltorefresh实现原理

android pulltorefresh实现原理

android pulltorefresh实现原理PullToRefresh是一种常见的手势交互体验,通过在界面上向下滑动来刷新内容。

本文将介绍Android中PullToRefresh的实现原理。

Android中实现PullToRefresh的方法有很多,其中一种常见的实现方式是使用SwipeRefreshLayout类。

SwipeRefreshLayout是Android SDK提供的一个容器类,可以包含一个滚动视图(例如RecyclerView、ListView等),并实现下拉刷新效果。

当用户下拉SwipeRefreshLayout容器时,它会检测用户手势,并根据下拉的距离来触发下拉刷新事件。

下拉刷新事件可以通过设置OnRefreshListener来监听,当触发下拉刷新事件时,可以在回调函数中执行相应的刷新逻辑。

具体实现方式如下:1. 在布局文件中添加SwipeRefreshLayout作为容器,例如:```xml<androidx.swiperefreshlayout.widget.SwipeRefreshLayoutandroid:id="@+id/swipeRefreshLayout"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent" /></androidx.swiperefreshlayout.widget.SwipeRefreshLayout>```2. 在代码中获取SwipeRefreshLayout的实例,并设置OnRefreshListener监听器,例如:```javaSwipeRefreshLayout swipeRefreshLayout =findViewById(R.id.swipeRefreshLayout);swipeRefreshLayout.setOnRefreshListener(newSwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {// 执行刷新逻辑}});```3. 在回调函数onRefresh()中执行刷新逻辑,例如更新数据或重新加载内容。

swiperefreshlayout用法

swiperefreshlayout用法

《SwipeRefreshLayout用法全面解析》1. 介绍SwipeRefreshLayout是Android中常用的下拉刷新组件,它能够为应用程序提供良好的用户体验。

本文将从基本用法、高级功能和个人实践等方面全面解析SwipeRefreshLayout的用法。

2. 基本用法在使用SwipeRefreshLayout时,首先需要在布局文件中添加SwipeRefreshLayout组件,并将需要实现下拉刷新的内容嵌套在其中。

接着在相应的Activity或Fragment中,通过findViewById()方法找到SwipeRefreshLayout的实例,并调用setOnRefreshListener()方法来设置下拉刷新的监听器。

当用户下拉时,监听器中的onRefresh()方法将会被调用,我们可以在这里实现数据的更新操作。

3. 高级功能除了基本的下拉刷新功能外,SwipeRefreshLayout还提供了一些高级功能,比如自定义下拉进度条的颜色、触发刷新的手势控制、刷新动画的定制等。

这些功能可以让我们根据实际需求来进行定制,以便更好地满足用户的需求。

4. 个人实践在实际项目中,我曾经遇到了使用SwipeRefreshLayout的需求。

通过对SwipeRefreshLayout的深入了解和实践,我发现它的灵活性和易用性非常高,能够轻松地集成到项目中,并且有效地提升了用户体验。

在实际项目中,我还结合RecyclerView等其他组件来实现更加丰富的下拉刷新效果,取得了非常不错的效果。

总结通过本文的介绍和解析,我们可以发现SwipeRefreshLayout的用法并不复杂,但却能够为应用程序带来极大的价值。

它的灵活性和丰富的功能使得我们能够根据实际需求来进行定制,从而更好地满足用户的需求。

个人实践中的成功经验也证明了SwipeRefreshLayout的可靠性和有效性。

个人观点在我看来,SwipeRefreshLayout作为Android中常用的下拉刷新组件,不仅提供了基本的下拉刷新功能,而且还具备了丰富的高级功能。

【Android培训】Android LRecyclerView 操作案例分享-实现下拉刷新、滑动到底部自动加载

【Android培训】Android LRecyclerView 操作案例分享-实现下拉刷新、滑动到底部自动加载

【Android培训】Android LRecyclerView 操作案例分享-实现下拉刷新、滑动到底部自动加载一直想抽空写下这个开源项目,但是各种原因没有抽时间,今天还是趁着工作间隙写下了这篇文库,与大家分享。

简介LRecyclerView是支持addHeaderView、addFooterView、下拉刷新、分页加载数据的RecyclerView。

它对RecyclerView 控件进行了拓展,给RecyclerView增加HeaderView、FooterView,并且不需要对你的Adapter做任何修改。

主要功能下拉刷新、滑动到底部自动加载下页数据;可以方便添加Header和Footer;头部下拉样式可以自定义;具备item点击和长按事件。

网络错误加载失败点击Footer重新请求数据;可以动态为FooterView赋予不同状态(加载中、加载失败、滑到最底等)。

感谢如果我比别人看得远些,那是因为我站在巨人们的肩上。

(牛顿)本开源控件是基于HeaderAndFooterRecyclerView 开源项目而来,在原基础上进行了扩充。

GradleStep 1. 在你的根build.gradle文件中增加JitPack仓库依赖。

allprojects {repositories {jcenter()maven { url "https://jitpack.io" }}}Step 2. 在你的model的build.gradle文件中增加LRecyclerView依赖。

compile 'com.github.jdsjlzx:LRecyclerView:1.0.0'使用添加HeaderView、FooterViewmDataAdapter = new DataAdapter(this);mDataAdapter.setData(dataList); mHeaderAndFooterRecyclerViewAdapter = new HeaderAndFooterRecyclerViewAdapter(this, mDataAdapter);mRecyclerView.setAdapter(mHeaderAndFooterRecyclerViewAdapter); mRecyclerView.setLayoutManager(new LinearLayoutManager(this));//add a HeaderViewRecyclerViewUtils.setHeaderView(mRecyclerView, new SampleHeader(this));//add a FooterViewRecyclerViewUtils.setFooterView(mRecyclerView, new SampleFooter(this));注意:mHeaderAndFooterRecyclerViewAdapter = new HeaderAndFooterRecyclerViewAdapter(this, mDataAdapter); HeaderAndFooterRecyclerViewAdapter提供了一些实用的功能,使用者不用关心它的实现,只需构造的时候把自己的mDataAdapter以参数形式传进去即可。

android开发中listview的妙用之上拉刷...

android开发中listview的妙用之上拉刷...

Android ListView下拉刷新、上拉载入更多
0. XListView继承ListView。

1. 下拉刷新组件是ListView的一个Header。

在ListView创建时就将这个自定义View塞进去,默认情况是看不到的,所以这个HeaderView的高度初始设置为0。

2. 上拉载入更多组件是Footer,为了确保这个footer在最后(可能会添加多个自定义footer),在用户调用setAdatper的时候再把这个footer塞进去。

3. 覆写ListView的onTouchEvent方法,处理各种情况。

4. 用户松手,启动mScroller,将header、footer回滚到所需状态。

5. 添加了用户下拉、上拉移动delay的效果,类似iOS的行为。

6. 提供了两个接口:
a) IXListViewListener: 触发下拉刷新、上拉载入更多
b) OnXScrollListener: 这个和原生的OnScrollListener一样,但是在mScroller回滚时,也会触发这里的事件。

Android中自定义ListView控件实现下拉刷新,简单实用效果好(原创)

花了一天时间写出了这个类来实现下拉刷新。

首先这是一个自定义的listView控件类,我在许多项目中都用到了它,效果很稳定。

实现也很简单。

用的时候其他功能都和系统提供的ListView一样,就只是多了一个下拉刷新监听。

用这个类替代系统提供的ListView,下拉刷新再也不会烦恼了。

\(^o^)/~希望对大家有用。

我写的自定义ListView的代码:import java.util.Date;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import youtInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ProgressBar;import android.widget.TextView;public class MyListView extends ListView implements OnScrollListener {private static final String TAG = "listview";private final static int RELEASE_To_REFRESH = 0;private final static int PULL_To_REFRESH = 1;private final static int REFRESHING = 2;private final static int DONE = 3;private final static int LOADING = 4;// 实际的padding的距离与界面上偏移距离的比例private final static int RATIO = 3;private LayoutInflater inflater;private LinearLayout headView;private TextView tipsTextview;private TextView lastUpdatedTextView;private ImageView arrowImageView;private ProgressBar progressBar;private RotateAnimation animation;private RotateAnimation reverseAnimation;// 用于保证startY的值在一个完整的touch事件中只被记录一次private boolean isRecored;private int headContentWidth;private int headContentHeight;private int startY;private int firstItemIndex;private int state;private boolean isBack;private OnRefreshListener refreshListener;private boolean isRefreshable;public MyListView(Context context) {super(context);init(context);}public MyListView(Context context, AttributeSet attrs) { super(context, attrs);init(context);}private void init(Context context) {setCacheColorHint(context.getResources().getColor(R.color.tran sparent));inflater = LayoutInflater.from(context);headView= (LinearLayout) inflater.inflate(yout.head, null);arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);arrowImageView.setMinimumWidth(70);arrowImageView.setMinimumHeight(50);progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);tipsTextview = (TextView)headView.findViewById(R.id.head_tipsTextView);lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);measureView(headView);headContentHeight = headView.getMeasuredHeight();headContentWidth = headView.getMeasuredWidth();headView.setPadding(0, -1 * headContentHeight, 0, 0);headView.invalidate();Log.v("size", "width:" + headContentWidth + " height:"+ headContentHeight);addHeaderView(headView, null, false);setOnScrollListener(this);animation = new RotateAnimation(0, -180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);animation.setInterpolator(new LinearInterpolator());animation.setDuration(250);animation.setFillAfter(true);reverseAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);reverseAnimation.setInterpolator(new LinearInterpolator());reverseAnimation.setDuration(200);reverseAnimation.setFillAfter(true);state = DONE;isRefreshable = false;}public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,int arg3) {firstItemIndex = firstVisiableItem;}public void onScrollStateChanged(AbsListView arg0, int arg1) { }public boolean onTouchEvent(MotionEvent event) {if (isRefreshable) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (firstItemIndex == 0 && !isRecored) {isRecored = true;startY = (int) event.getY();Log.v(TAG, "在down时候记录当前位置‘");}break;case MotionEvent.ACTION_UP:if (state != REFRESHING && state != LOADING) { if (state == DONE) {// 什么都不做}if (state == PULL_To_REFRESH) {state = DONE;changeHeaderViewByState();Log.v(TAG, "由下拉刷新状态,到done状态");}if (state == RELEASE_To_REFRESH) {state = REFRESHING;changeHeaderViewByState();onRefresh();Log.v(TAG, "由松开刷新状态,到done状态");}}isRecored = false;isBack = false;break;case MotionEvent.ACTION_MOVE:int tempY = (int) event.getY();if (!isRecored && firstItemIndex == 0) {Log.v(TAG, "在move时候记录下位置");isRecored = true;startY = tempY;}if(state!= REFRESHING&& isRecored&& state!= LOADING) {// 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动// 可以松手去刷新了if (state == RELEASE_To_REFRESH) {setSelection(0);// 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步if(((tempY - startY) / RATIO< headContentHeight)&& (tempY - startY) > 0) {state = PULL_To_REFRESH;changeHeaderViewByState();Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");}// 一下子推到顶了else if (tempY - startY <= 0) {state = DONE;changeHeaderViewByState();Log.v(TAG, "由松开刷新状态转变到done状态");}// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步else {// 不用进行特别的操作,只用更新paddingTop的值就行了}}// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态if (state == PULL_To_REFRESH) {setSelection(0);// 下拉到可以进入RELEASE_TO_REFRESH的状态if((tempY - startY) / RATIO>= headContentHeight) {state = RELEASE_To_REFRESH;isBack = true;changeHeaderViewByState();Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");}// 上推到顶了else if (tempY - startY <= 0) {state = DONE;changeHeaderViewByState();Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");}}// done状态下if (state == DONE) {if (tempY - startY > 0) {state = PULL_To_REFRESH;changeHeaderViewByState();}}// 更新headView的sizeif (state == PULL_To_REFRESH) {headView.setPadding(0, -1 * headContentHeight+ (tempY - startY) / RATIO, 0, 0);}// 更新headView的paddingTopif (state == RELEASE_To_REFRESH) {headView.setPadding(0, (tempY - startY) / RATIO- headContentHeight, 0, 0);}}break;}}return super.onTouchEvent(event);}// 当状态改变时候,调用该方法,以更新界面private void changeHeaderViewByState() {switch (state) {case RELEASE_To_REFRESH:arrowImageView.setVisibility(View.VISIBLE);progressBar.setVisibility(View.GONE);tipsTextview.setVisibility(View.VISIBLE);lastUpdatedTextView.setVisibility(View.VISIBLE);arrowImageView.clearAnimation();arrowImageView.startAnimation(animation);tipsTextview.setText("松开刷新");Log.v(TAG, "当前状态,松开刷新");break;case PULL_To_REFRESH:progressBar.setVisibility(View.GONE);tipsTextview.setVisibility(View.VISIBLE);lastUpdatedTextView.setVisibility(View.VISIBLE);arrowImageView.clearAnimation();arrowImageView.setVisibility(View.VISIBLE);// 是由RELEASE_To_REFRESH状态转变来的if (isBack) {isBack = false;arrowImageView.clearAnimation();arrowImageView.startAnimation(reverseAnimation);tipsTextview.setText("下拉刷新");} else {tipsTextview.setText("下拉刷新");}Log.v(TAG, "当前状态,下拉刷新");break;case REFRESHING:headView.setPadding(0, 0, 0, 0);progressBar.setVisibility(View.VISIBLE);arrowImageView.clearAnimation();arrowImageView.setVisibility(View.GONE);tipsTextview.setText("正在刷新...");lastUpdatedTextView.setVisibility(View.VISIBLE);Log.v(TAG, "当前状态,正在刷新...");break;case DONE:headView.setPadding(0, -1 * headContentHeight, 0, 0);progressBar.setVisibility(View.GONE);arrowImageView.clearAnimation();arrowImageView.setImageResource(R.drawable.arrow);tipsTextview.setText("下拉刷新");lastUpdatedTextView.setVisibility(View.VISIBLE);Log.v(TAG, "当前状态,done");break;}}public void setonRefreshListener(OnRefreshListener refreshListener) {this.refreshListener = refreshListener;isRefreshable = true;}public interface OnRefreshListener {public void onRefresh();}public void onRefreshComplete() {state = DONE;lastUpdatedTextView.setText("最近更新:"+ new Date().toLocaleString());changeHeaderViewByState();}private void onRefresh() {if (refreshListener != null) {refreshListener.onRefresh();}}// 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及heightprivate void measureView(View child) {youtParams p = child.getLayoutParams();if (p == null) {p = new youtParams(youtParams.FILL_PARENT,youtParams.WRAP_CONTENT);}int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);int lpHeight = p.height;int childHeightSpec;if (lpHeight > 0) {childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);} else {childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}child.measure(childWidthSpec, childHeightSpec);}public void setAdapter(BaseAdapter adapter) {lastUpdatedTextView.setText("最近更新:"+ new Date().toLocaleString());super.setAdapter(adapter);}}这个类到此结束了,你可以在项目中建一个类把此类拷贝进去,作为你自定义的listView 使用就可以了。

android实现下拉列表ListView

public class ListView extends Activity {/** Called when the activity is first created. */private List<;String>; list = new ArrayList<;String>;();private TextView myTextView;private Spinner mySpinner;private ArrayAdapter<;String>; adapter;private Animation au;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);//第一步:添加一个下拉列表项的list,这里添加的项就是下拉列表的菜单项list.add(";北京"; );list.add(";上海"; );list.add(";深圳"; );list.add(";南京"; );list.add(";重庆"; );myTextView = (TextView)findViewById(R.id.textview);mySpinner = (Spinner)findViewById(R.id.Spinner01);au=AnimationUtils.loadAnimation(this,R.anim.my_anim);//第二步:为下拉列表定义一个适配器,这里就用到里前面定义的list。

adapter = new ArrayAdapter<;String>;( this ,yout.simple_spinner_item, list);//第三步:为适配器设置下拉列表下拉时的菜单样式。

AndroidUI设计系列之自定义ListView仿QQ空间阻尼下拉刷新和渐变菜单栏效果(8)

AndroidUI设计系列之⾃定义ListView仿QQ空间阻尼下拉刷新和渐变菜单栏效果(8)好久没有写有关UI的博客了,刚刚翻了⼀下之前的博客,最近⼀篇有关UI的博客:,实现各种风格效果的对话框,在那篇博客写完后由于公司封闭开发封⽹以及其它原因致使博客中断⾄今,中断这么久很是惭愧,后续我会尽量把该写的都补充出来。

近来项⽬有个需求,要做个和QQ空间类似的菜单栏透明度渐变和下拉刷新带有阻尼回弹的效果。

于是花点时间动⼿试了试,基本上达到了QQ空间的效果,截图如下:通过观察QQ空间的运⾏效果,发现当往上滚动时菜单栏会随着滚动距离的增⼤其透明度组件增⼤直到完全不透明,反之逐渐透明。

当滚动到顶部后继续下拉会出现拉升效果当松⼿之后出现阻尼回弹效果。

于是就通过重写ListView模仿了QQ空间的运⾏效果。

实现QQ空间运⾏效果前需要考虑两个问题:1)、如何实现菜单栏透明度渐变通过观察QQ空间的运⾏效果可知其菜单栏的透明度是根据滚动距离⽽动态变化的,要想实现透明度的变化就需要知道的ListView的滚动距离,所以有关透明度的问题也就转化成了滚动距离的问题。

2)、如何实现阻尼拉升和回弹效果要想利⽤ListView实现阻尼效果就要求ListView⾸先滚动到了顶部,当ListView滚动到了顶部之后若继续⼿动下滑就要求其第⼀个Child变化来模拟下拉效果,当⼿指松开后该Child要回弹到初始状态。

我们先看第⼀个问题:要想实现透明度渐变就要先获取到ListView的滚动距离,通过滚动距离来计算相应的透明度。

由于ListView的复⽤机制就决定了不能通过第⼀个可见Item的getTop()⽅法来得到滚动值,所以我们可以通过HeaderView来获取滚动距离,因为Header在ListView中是不参与复⽤的。

下⾯先了解⼀下ListView添加HeaderView后的滚动流程:上图⼤致画了ListView含有HeaderView时的三个滚动状态,状态⼀可称为初始状态或者是恰好滚动到最顶部状态,此时HeaderView的getTop()值为0;状态⼆为ListView的滚动中状态,此时HeaderView没有完全滚动出ListView边界,getTop()的返回值为负数且其绝对值范围在0和HeaderView的⾼度之间;状态三表⽰的是HeaderView完全滚动出了ListView边界,若调⽤getTop()得到的返回值为负数且绝对值等于HeaderView的⾼度(此后可理解成HeaderView⼀直固定在ListView的顶部)。

Android中用SmartRefreshLayout实现ListView列表的数据刷新与。。。

Android中⽤SmartRefreshLayout实现ListView列表的数据刷新与。

这⾥⽤到的是第三⽅插件:SmartRefreshLayout效果图如下:使⽤步骤如下:1、添加远程依赖/*刷新和加载*/implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-14'implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.0-alpha-14'//没有使⽤特殊Header,可以不加这⾏2、如何在布局⽂件中使⽤,代码如下:(备注:SmartRefreshLayout分为三块:Header布局,Content布局,Footer布局。

其中,Content内容布局必须是⼀个整体。

例如,下⾯的布局包括图⽚,⽂字,列表等等,⽤⼀个ScrollView包起来。

)<?xml version="1.0" encoding="utf-8"?><LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="/apk/res-auto"android:orientation="vertical"xmlns:android="/apk/res/android"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:orientation="horizontal"android:background="@color/colorAccent"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="标题栏"android:textSize="18dp"android:textStyle="bold"android:layout_centerInParent="true"/></RelativeLayout><yout.SmartRefreshLayoutandroid:id="@ id/Main_SRLayout"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#444444"app:srlPrimaryColor="#444444"app:srlAccentColor="@android:color/white"app:srlEnablePreviewInEditMode="true"><yout.header.ClassicsHeaderandroid:layout_width="match_parent"android:layout_height="wrap_content"/><ScrollViewandroid:id="@ id/Main_scrollView"android:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:background="@color/colorWhite"><TextViewandroid:id="@ id/Main_tvRefreshInfo"android:layout_width="wrap_content"android:layout_height="wrap_content"android:visibility="gone"android:text="你好"/><ImageViewandroid:layout_width="match_parent"android:layout_height="150dp"android:scaleType="fitXY"android:src="@mipmap/corporation_detailinfo_topbg"/><com.deepreality.smartrefreshlayoutdemo.ListViewNestingandroid:id="@ id/Main_lvNewsList"android:layout_width="match_parent"android:layout_height="wrap_content"></com.deepreality.smartrefreshlayoutdemo.ListViewNesting> </LinearLayout></ScrollView><yout.footer.ClassicsFooterandroid:layout_width="match_parent"android:layout_height="wrap_content"app:srlAccentColor="@color/colorWhite"/></yout.SmartRefreshLayout></LinearLayout>3、布局⽂件知道怎么⽤了,下⾯说⼀下如何在Activity中使⽤,代码如下:其实分为以下⼏步即可:(1) 实现OnRefreshListener和OnLoadMoreListener接⼝⽅法。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档