ListView的私人订制
2016-08-30 14:38
134 查看
转载请注明出处:http://blog.csdn.net/magic_jss/article/details/52369091;
现在开发中Android RecyclerView可能用的比较多,不过ListView作为常用控件学习它的使用和扩展也是十分重要的。简单封装了一个下拉刷新和上拉加载的ListView,你是否也想有个私人订制的ListView呢?或许这篇文章能够帮到你,如有问题恳请指正!欢迎评论哦!
效果图:
由于电脑和模拟器的原因可能不太清晰及略卡顿,真机上则很清晰及流畅。
以上代码主要步骤:
初始化的时候添加HeadView、FootView。
继承ListView实现OnScrollListener接口,重写onScroll方法,因为onScroll方法在ListView滑动的时候会一直回调,因此在onScroll方法中判断是否处于ListView的顶部/底部,从而处理下拉刷新/上拉加载的展现时机。
重写onTouchEvent方法,在按下、滑动、抬起的时候动态处理HeadView、FootView的展现。
添加回调接口,设置回调方法。
注释比较清楚,不在赘述。
layout/listview_head.xml
listview_footer.xml
Adapter比较简单就不写了!
整个项目下载地址:http://download.csdn.net/detail/magic_jss/9616947;
END!
现在开发中Android RecyclerView可能用的比较多,不过ListView作为常用控件学习它的使用和扩展也是十分重要的。简单封装了一个下拉刷新和上拉加载的ListView,你是否也想有个私人订制的ListView呢?或许这篇文章能够帮到你,如有问题恳请指正!欢迎评论哦!
效果图:
由于电脑和模拟器的原因可能不太清晰及略卡顿,真机上则很清晰及流畅。
1、自定义ListView
直接上代码/** * Created by magic on 2016年5月12日.带下拉刷新/上拉加载的listview */ public class PullDownRefurbishLoadListView extends ListView implements OnScrollListener, OnClickListener { /** * head view */ private View headView; /** * head view height */ private int headViewHeight; /** * 是否可以下滑刷新 */ private boolean isPullDownRefurbish = false; /** * 文本状态描述 */ private TextView tev_status; /** * 进度条 */ private ImageView progressBar; /** * foot view */ private View footView; /** * foot view height */ private int footViewHeight; /** * 是否可以上拉加载 */ private boolean isPullHighLoad = false; /** * 底部布局 */ LinearLayout layout_listviewFoot; /** * 底部文本状态描述 */ private TextView tev_status_foot; /** * 进度条 */ ImageView progressBar_foot; /** * 按下后的初始Y位置 */ private float beginY = 0; /** * 移动的距离 */ private int moveY = 0; /** * 正常状态 */ private final static int NONE = 0; /** * 下拉/上拉状态 */ private final static int PULL = 1; /** * 释放刷新状态 */ private final static int RELEASE = 2; /** * 刷新状态 */ private final static int REFURBISH = 3; /** * 状态 */ private static int STATUS; /** * 是否允许下拉刷新 */ private boolean isRefurbishAble = true; /** * 是否允许上拉加载 */ private boolean isLoadAble = true; /** * context */ private Context context; /** * 动画 */ private RotateAnimation rotateAnimation, rotateAnimation2; /** * 接口 */ private IPullDownRefurbishLoadListView refurbishLoadListView; public PullDownRefurbishLoadListView(Context context) { super(context); init(context); } public PullDownRefurbishLoadListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public PullDownRefurbishLoadListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } /** * 添加head/foot布局 * * @param context */ private void init(Context context) { headView = LayoutInflater.from(context).inflate(R.layout.listview_head, null); this.addHeaderView(headView); // 设置滑动监听 this.setOnScrollListener(this); headView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); headViewHeight = headView.getMeasuredHeight(); // 设置headView 偏移出屏幕 headView.setPadding(0, -headViewHeight, 0, 0); tev_status = (TextView) findViewById(R.id.tev_listviewHead_status); progressBar = (ImageView) findViewById(R.id.prb_listviewHead_refurbish); footView = LayoutInflater.from(context).inflate( R.layout.listview_footer, null); this.addFooterView(footView); footView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); footViewHeight = footView.getMeasuredHeight(); layout_listviewFoot = (LinearLayout) footView .findViewById(R.id.layout_listviewFoot); tev_status_foot = (TextView) footView .findViewById(R.id.tev_listviewFoot_state); progressBar_foot = (ImageView) findViewById(R.id.prb_listviewFoot_load); tev_status_foot.setOnClickListener(this); this.context = context; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: beginY = ev.getY(); if (STATUS == REFURBISH) { // 不消耗事件 return false; } case MotionEvent.ACTION_MOVE: this.moveY = (int) (ev.getY() - beginY); if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) { if (moveY > 0) { if (moveY > headViewHeight) { STATUS = RELEASE; if (moveY >= (headViewHeight + dp2px(20, context))) { moveY = headViewHeight + dp2px(20, context); } } else if (moveY > 0 && moveY <= headViewHeight) { STATUS = PULL; } else { STATUS = NONE; } setRefurbishByStatus((int) moveY); } } if (isLoadAble && isPullHighLoad && moveY < 0) { tev_status_foot.setVisibility(View.GONE); progressBar_foot.setVisibility(View.VISIBLE); if (Math.abs(moveY) > footViewHeight) { STATUS = RELEASE; } else if (Math.abs(moveY) > 0 && Math.abs(moveY) <= footViewHeight) { STATUS = PULL; } else { STATUS = NONE; } } break; case MotionEvent.ACTION_UP: if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) { switch (STATUS) { case PULL: moveY = 0; setRefurbishByStatus(-headViewHeight); break; case RELEASE: STATUS = REFURBISH; setRefurbishByStatus((int) moveY); if (refurbishLoadListView != null) { refurbishLoadListView.refurbish(); } break; } } if (isLoadAble && isPullHighLoad && moveY < 0) { switch (STATUS) { case PULL: moveY = 0; STATUS = NONE; tev_status_foot.setVisibility(View.VISIBLE); progressBar_foot.setVisibility(View.GONE); break; case RELEASE: STATUS = REFURBISH; progressBar_foot.clearAnimation(); if (rotateAnimation2 != null) { rotateAnimation2.cancel(); } setAnimationToProgressBarFoot(); break; } } break; } return super.onTouchEvent(ev); } /** * 设置head布局的上内边距 * * @param size */ private void setHeadPaddingTop(int size) { size = size + (-headViewHeight); headView.setPadding(0, size, 0, 0); } /** * 根据状态设置刷新HeadView显示的内容 */ private void setRefurbishByStatus(int moveY) { switch (STATUS) { case NONE: tev_status.setText("下拉刷新"); progressBar.setImageResource(R.drawable.ic_ptr_pull); setHeadPaddingTop(-headViewHeight); break; case PULL: tev_status.setText("下拉刷新"); progressBar.setImageResource(R.drawable.ic_ptr_pull); setHeadPaddingTop(moveY); break; case RELEASE: tev_status.setText("释放刷新"); progressBar.setImageResource(R.drawable.ic_ptr_release); setHeadPaddingTop(moveY); break; case REFURBISH: tev_status.setText("刷新中"); progressBar.setImageResource(R.drawable.ic_ptr_loading); setHeadPaddingTop(headViewHeight); if (rotateAnimation == null) { rotateAnimation = new RotateAnimation(0.0f, 180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation.setDuration(150); rotateAnimation.setRepeatCount(-1); } progressBar.setAnimation(rotateAnimation); rotateAnimation.start(); break; } } /** * 设置对外公开接口 * * @param pullDownRefurbish */ public void setIPullDownRefurbish( IPullDownRefurbishLoadListView refurbishLoadListView) { this.refurbishLoadListView = refurbishLoadListView; } /** * 刷新完成执行 */ public void setPullDownRefurbishFinish() { moveY = 0; STATUS = NONE; setRefurbishByStatus((int) moveY); progressBar.clearAnimation(); rotateAnimation.cancel(); } /** * 加载完成执行 */ public void setPullDownLoadFinish() { moveY = 0; STATUS = NONE; progressBar_foot.clearAnimation(); rotateAnimation2.cancel(); progressBar_foot.setVisibility(View.GONE); tev_status_foot.setVisibility(View.VISIBLE); } /** * 设置是否允许下拉刷新 * * @param isRefurbishAble */ public void setRefurbishAble(boolean isRefurbishAble) { this.isRefurbishAble = isRefurbishAble; } /** * 设置是否可以上拉加载 * * @param isLoadAble */ public void setLoadAble(boolean isLoadAble) { this.isLoadAble = isLoadAble; if (!isLoadAble) { layout_listviewFoot.setVisibility(View.GONE); } } @Override public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) { // 参数: // 查看其滚动状态的视图 // firstvisibleitem -第一个可见的细胞指数(忽略如果visibleitemcount = = 0) // visibleitemcount -可见细胞数 // totalitemcount -在列表适配器项目数 // arg1为0时 列表在最顶部 isPullDownRefurbish = arg1 == 0 ? true : false; // arg1为最后一个时arg1==arg3 isPullHighLoad = (arg1 + arg2) == arg3 ? true : false; } @Override public void onScrollStateChanged(AbsListView arg0, int arg1) { } /** * dp转px */ private int dp2px(float value, Context context) { final float scale = context.getResources().getDisplayMetrics().densityDpi; return (int) (value * (scale / 160) + 0.5f); } /** * 为progressBar_foot设置动画 */ private void setAnimationToProgressBarFoot() { if (rotateAnimation2 == null) { rotateAnimation2 = new RotateAnimation(0.0f, 180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnimation2.setDuration(150); rotateAnimation2.setRepeatCount(-1); } progressBar_foot.setAnimation(rotateAnimation2); rotateAnimation2.start(); if (refurbishLoadListView != null) { refurbishLoadListView.load(); } } @Override public void onClick(View v) { // 点击查看更多 tev_status_foot.setVisibility(View.GONE); progressBar_foot.setVisibility(View.VISIBLE); setAnimationToProgressBarFoot(); } /** * 接口 */ interface IPullDownRefurbishLoadListView { /** * 刷新事件回调 */ void refurbish(); /** * 加载回调 */ void load(); } }
以上代码主要步骤:
初始化的时候添加HeadView、FootView。
继承ListView实现OnScrollListener接口,重写onScroll方法,因为onScroll方法在ListView滑动的时候会一直回调,因此在onScroll方法中判断是否处于ListView的顶部/底部,从而处理下拉刷新/上拉加载的展现时机。
重写onTouchEvent方法,在按下、滑动、抬起的时候动态处理HeadView、FootView的展现。
添加回调接口,设置回调方法。
注释比较清楚,不在赘述。
2、xml文件
主布局<?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:orientation="vertical" > <com.magic.test_listviewrefurbish.PullDownRefurbishLoadListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
layout/listview_head.xml
<?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:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical" android:paddingBottom="20dp" android:paddingTop="20dp" > <ImageView android:id="@+id/prb_listviewHead_refurbish" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_ptr_pull" /> <TextView android:id="@+id/tev_listviewHead_status" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="下拉刷新" android:textColor="#afafaf" android:textSize="12sp" /> </LinearLayout> </LinearLayout>
listview_footer.xml
<?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:descendantFocusability="blocksDescendants" android:orientation="vertical" > <LinearLayout android:id="@+id/layout_listviewFoot" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="vertical" android:paddingBottom="15dp" android:paddingTop="15dp" > <TextView android:id="@+id/tev_listviewFoot_state" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="查看更多" android:textColor="@android:color/darker_gray" /> <ImageView android:id="@+id/prb_listviewFoot_load" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_ptr_loading" android:visibility="gone" /> </LinearLayout> </LinearLayout>
3、Activity中使用
/** * Created by magic on 2016年5月12日.带下拉刷新/上拉加载的listview */ public class MainActivity extends Activity implements OnItemClickListener { PullDownRefurbishLoadListView listView; MyAdapter adapter; List<String> list = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initView(); } private void initView() { listView = (PullDownRefurbishLoadListView) findViewById(R.id.listview); list.add("a"); adapter = new MyAdapter(this, list); listView.setAdapter(adapter); listView.setOnItemClickListener(this); //设置是否可以下拉刷新,默认为true listView.setRefurbishAble(true); //设置是否可以上拉加载,默认为true listView.setLoadAble(true); listView.setIPullDownRefurbish(new IPullDownRefurbishLoadListView() { @Override public void refurbish() { new Handler().postDelayed(new Runnable() { @Override public void run() { list.add(0, "c"); adapter.notifyDataSetChanged(); listView.setPullDownRefurbishFinish(); } }, 2000); } @Override public void load() { new Handler().postDelayed(new Runnable() { @Override public void run() { list.add("b"); adapter.notifyDataSetChanged(); listView.setPullDownLoadFinish(); } }, 2000); } }); } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Toast.makeText(this, "Hello " + arg2, Toast.LENGTH_SHORT).show(); } }
Adapter比较简单就不写了!
整个项目下载地址:http://download.csdn.net/detail/magic_jss/9616947;
END!
相关文章推荐
- 办公软件WORD,给自己来个私人订制模板
- 私人订制你们看了没没啥意思
- C#软件开发实例.私人订制自己的屏幕截图工具(四)基本截图功能实现
- C#软件开发实例.私人订制自己的屏幕截图工具(十一)编辑工具栏的实现
- C#软件开发实例.私人订制自己的屏幕截图工具(六)添加配置管理功能
- 私人订制,现实版的“圆梦网站”
- 数据恢复陶工西部数据5毫米硬盘特殊接口,OEM私人订制,最薄的混合硬盘!
- C#软件开发实例.私人订制自己的屏幕截图工具——放大镜的功能代码优化
- C#软件开发实例.私人订制自己的屏幕截图工具(九)使用自定义光标,QQ截图时的光标
- 关于IT学习的老马私人订制服务
- C#软件开发实例.私人订制自己的屏幕截图工具(一)功能概览
- C#软件开发实例.私人订制自己的屏幕截图工具(二)创建项目、注册热键、显示截图主窗口
- C#软件开发实例.私人订制自己的屏幕截图工具(十)在截图中包含鼠标指针形状
- C#软件开发实例.私人订制自己的屏幕截图工具(三)托盘图标及菜单的实现
- Unity之私人订制Debug
- 真正的私人订制来了,帮你把毁掉的童年拼回来丨钛空精分小剧场
- C#软件开发实例.私人订制自己的屏幕截图工具(四)基本截图功能实现
- C#软件开发实例.私人订制自己的屏幕截图工具(七)添加放大镜的功能
- 烽火为格兰仕集团私人订制-销售管家iCube平台
- C#软件开发实例.私人订制自己的屏幕截图工具(五)针对拖拽时闪烁卡顿现象的优化