ListView下拉刷新上拉加载更多实现
这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉):
1
2
3
4
5
接下来再看一下工程文件;
首先,实现这种效果需要重写ListView控件,工程中的RefreshListView即继承了ListView,并实现了OnScrollListener接口,头部和脚部和主界面其实是连在一起的,只是在RefreshListView中没让它显示出来,只有当特定条件比如下拉上拉时才会显示,这些动作执行完毕后又会重新隐藏,先来看一下RefreshListView代码:
/**
* @author baiyuliang
*/
public class RefreshListView extends ListView implements OnScrollListener {
private int downY; // 按下时y轴的偏移量
private View headerView; // 头布局
private int headerViewHeight; // 头布局的高度
private int firstVisibleItemPosition; // 滚动时界面显示在顶部的item的position
private DisplayMode currentState = DisplayMode.Pull_Down; // 头布局当前的状态, 缺省值为下拉状态
private Animation upAnim,downAnim,loadAnim; // 向上旋转的动画,向下旋转的动画,刷新数据时load动画
private ImageView ivArrow; // 头布局的箭头
private TextView tvState; // 头布局刷新状态
private ImageView loading_img_header,loading_img_footer; // 头布局和脚布局的进度条
private TextView tvLastUpdateTime; // 头布局的最后刷新时间
private OnRefreshListener mOnRefreshListener;
private boolean isScroll2Bottom = false; // 是否滚动到底部
private View footerView; // 脚布局
private int footerViewHeight; // 脚布局的高度
private boolean isLoadMoving = false; // 是否正在加载更多中
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeader();
initFooter();
this.setOnScrollListener(this);
}
/**
* 初始化脚布局
*/
private void initFooter() {
footerView = LayoutInflater.from(getContext()).inflate(R.layout.activity_listview_refresh_footer, null);
loading_img_footer=(ImageView) footerView.findViewById(R.id.pb_listview_footer_progress);
measureView(footerView); // 测量一下脚布局的高度
footerViewHeight = footerView.getMeasuredHeight();
footerView.setPadding(0, -footerViewHeight, 0, 0); // 隐藏脚布局
this.addFooterView(footerView);
}
/**
* 初始化头布局
*/
private void initHeader() {
//头部
headerView = LayoutInflater.from(getContext()).inflate(R.layout.activity_listview_refresh_header, null);
ivArrow = (ImageView) headerView.findViewById(R.id.iv_listview_header_down_arrow);
loading_img_header = (ImageView) headerView.findViewById(R.id.pb_listview_header_progress);
tvState = (TextView) headerView.findViewById(R.id.tv_listview_header_state);
tvLastUpdateTime = (TextView) headerView.findViewById(R.id.tv_listview_header_last_update_time);
ivArrow.setMinimumWidth(50);
tvLastUpdateTime.setText("上次刷新时间: " + getLastUpdateTime());
measureView(headerView);
headerViewHeight = headerView.getMeasuredHeight();
Log.i("RefreshListView", "头布局的高度: " + headerViewHeight);
headerView.setPadding(0, -headerViewHeight, 0, 0); // 隐藏头布局
this.addHeaderView(headerView);
initAnimation();
}
/**
* 获得最后刷新的时间
* @return
*/
private String getLastUpdateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
/**
* 初始下拉刷新时箭头动画
*/
private void initAnimation() {
//向上
upAnim = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
upAnim.setDuration(500);
upAnim.setFillAfter(true);
//向下
downAnim = new RotateAnimation(-180, -360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
downAnim.setDuration(500);
downAnim.setFillAfter(true);
//刷新数据时load动画
loadAnim=new RotateAnimation(0, 359, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
loadAnim.setDuration(2000);
loadAnim.setInterpolator(new LinearInterpolator());
loadAnim.setFillAfter(true);
loadAnim.setRepeatCount(-1);
}
/**
* 测量给定的View的宽和高, 测量之后, 可以得到view的宽和高
* @param child
*/
private void measureView(View child) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
if (lp == null) {
lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
int lpHeight = lp.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if(currentState == DisplayMode.Refreshing) {
// 当前的状态是正在刷新中, 不执行下拉操作
break;
}
int moveY = (int) ev.getY(); // 移动中的y轴的偏移量
int diffY = moveY - downY;
int paddingTop = -headerViewHeight + (diffY / 2);
if(firstVisibleItemPosition == 0&& paddingTop > -headerViewHeight) {
/**
* paddingTop > 0 完全显示
* currentState == DisplayMode.Pull_Down 当是在下拉状态时
*/
if(paddingTop > 0&& currentState == DisplayMode.Pull_Down) { // 完全显示, 进入到刷新状态
Log.i("RefreshListView", "松开刷新");
currentState = DisplayMode.Release_Refresh; // 把当前的状态改为松开刷新
refreshHeaderViewState();
} else if(paddingTop < 0&& currentState == DisplayMode.Release_Refresh) { // 没有完全显示, 进入到下拉状态
Log.i("RefreshListView", "下拉刷新");
currentState = DisplayMode.Pull_Down;
refreshHeaderViewState();
}
headerView.setPadding(0, paddingTop, 0, 0);
return true;
}
break;
case MotionEvent.ACTION_UP:
downY = -1;
if(currentState == DisplayMode.Pull_Down) { // 松开时, 当前显示的状态为下拉状态, 执行隐藏headerView的操作
headerView.setPadding(0, -headerViewHeight, 0, 0);
} else if(currentState == DisplayMode.Release_Refresh) { // 松开时, 当前显示的状态为松开刷新状态, 执行刷新的操作
headerView.setPadding(0, 0, 0, 0);
currentState = DisplayMode.Refreshing;
refreshHeaderViewState();
if(mOnRefreshListener != null) {
mOnRefreshListener.onRefresh();
}
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 当刷新任务执行完毕时, 回调此方法, 去刷新界面
*/
public void onRefreshFinish() {
if(isLoadMoving) { // 隐藏脚布局
loading_img_footer.clearAnimation();
isLoadMoving = false;
isScroll2Bottom = false;
footerView.setPadding(0, -footerViewHeight, 0, 0);
} else { // 隐藏头布局
headerView.setPadding(0, -headerViewHeight, 0, 0);
loading_img_header.clearAnimation();
loading_img_header.setVisibility(View.GONE);
ivArrow.setVisibility(View.VISIBLE);
tvState.setText("下拉刷新");
tvLastUpdateTime.setText("上次刷新时间: " + getLastUpdateTime());
currentState = DisplayMode.Pull_Down;
}
}
/**
* 刷新头布局的状态
*/
private void refreshHeaderViewState() {
if(currentState == DisplayMode.Pull_Down) { // 当前进入下拉状态
ivArrow.startAnimation(downAnim);
tvState.setText("下拉刷新");
} else if(currentState == DisplayMode.Release_Refresh) { //当前进入松开刷新状态
ivArrow.startAnimation(upAnim);
tvState.setText("释放立即刷新");
} else if(currentState == DisplayMode.Refreshing) { //当前进入正在刷新中
ivArrow.clearAnimation();
ivArrow.setVisibility(View.GONE);
loading_img_header.setVisibility(View.VISIBLE);
loading_img_header.startAnimation(loadAnim);
tvState.setText("正在获取新内容");
}
}
/**
* 刷新头布局的状态
* 当ListView滚动状态改变时回调
* SCROLL_STATE_IDLE // 当ListView滚动停止时
* SCROLL_STATE_TOUCH_SCROLL // 当ListView触摸滚动时
* SCROLL_STATE_FLING // 快速的滚动(手指快速的触摸移动)
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState == OnScrollListener.SCROLL_STATE_IDLE || scrollState == OnScrollListener.SCROLL_STATE_FLING) {
if(isScroll2Bottom && !isLoadMoving) { // 滚动到底部
// 加载更多
loading_img_footer.startAnimation(loadAnim);
footerView.setPadding(0, 0, 0, 0);
this.setSelection(this.getCount()); // 滚动到ListView的底部
isLoadMoving = true;
if(mOnRefreshListener != null) {
mOnRefreshListener.onLoadMoring();
}
}
}
}
/**
* 当ListView滚动时触发
* firstVisibleItem 屏幕上显示的第一个Item的position
* visibleItemCount 当前屏幕显示的总个数
* totalItemCount ListView的总条数
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
firstVisibleItemPosition = firstVisibleItem;
Log.i("RefreshListView", "onScroll: " + firstVisibleItem + ", " + visibleItemCount + ", " + totalItemCount);
if((firstVisibleItem + visibleItemCount) >= totalItemCount&& totalItemCount > 0) {
Log.i("RefreshListView", "加载更多");
isScroll2Bottom = true;
} else {
isScroll2Bottom = false;
}
}
/**
* @author andong
* 下拉头部的几种显示状态
*/
public enum DisplayMode {
Pull_Down, // 下拉刷新的状态
Release_Refresh, // 松开刷新的状态
Refreshing // 正在刷新中的状态
}
/**
* 设置刷新的监听事件
* @param listener
*/
public void setOnRefreshListener(OnRefreshListener listener) {
this.mOnRefreshListener = listener;
}
}
代码看上去比较复杂,大家可以慢慢研究,主要就是设置监听了几个动作,触摸屏幕,向下滑动,离开屏幕,下上滑动等等,根据不同动作执行相应操作,比如下拉时,头部布局便会显示出来,而当头部拉伸超过一定尺度后,箭头会执行一个动画,又指向下变为指向上,头部布局中的Textview空间内容也会发生相应变化,当松开手指时,又会出现一个动画如上图标记额地方,其实是一张图片,设置了旋转动画而已,而上拉加载更多是同样的道理,而且在动作执行完毕时,仍会有一个监听,主要是销毁动画和隐藏头部或脚部布局。
图中listview的效果是需要写一个自定义的适配器,这个我想大家都明白,也都会想到的吧,就不用我多说了,看代码:
/**
* @author baiyuliang
*/
public class MyAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> listDate;
private static LayoutInflater inflater=null;
public MyAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
listDate=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return listDate.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.list_item, null);
TextView username = (TextView) vi.findViewById(R.id.username); // 用户头像
TextView creatdate=(TextView) vi.findViewById(R.id.creatdate);//时间
TextView mood=(TextView) vi.findViewById(R.id.mood);//心情内容
HashMap<String, String> map = new HashMap<String, String>();
map = listDate.get(position);
//设置ListView的相关控件
username.setText(map.get("username"));
creatdate.setText(map.get("creatdate"));
mood.setText(map.get("mood"));
return vi;
}
}
接下来我们看一下,主界面main.xml布局代码:
<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=".MainActivity" >
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="45dip"
android:text="下拉刷新上拉加载"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:gravity="center"
android:background="@drawable/tab_footer_bg"
/>
<com.baiyuliang.pullrefresh.RefreshListView
android:id="@+id/refresh_listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/title"/>
</RelativeLayout>
很简单,就是一个标题栏和我们重写的ListView,listview中每个条目的布局list_item布局如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp" >
<RelativeLayout
android:id="@+id/headimg"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true" >
<ImageView
android:id="@+id/head_img"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:src="@drawable/head_img"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/name_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/headimg" >
<TextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="baiyuliang"
android:textColor="#00008B"
android:textSize="20sp" />
<TextView
android:id="@+id/creatdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/username"
android:layout_below="@+id/username"
android:layout_marginLeft="2dp"
android:text="今天12:00"
android:textSize="12sp" />
</RelativeLayout>
</RelativeLayout>
<TextView
android:id="@+id/mood"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="3dp"
android:text="今天心情不错,出来冒个泡!"
android:textColor="#000000"
android:textSize="15sp" />
<ImageView
android:id="@+id/mood_img"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp" />
<RelativeLayout
android:id="@+id/phonetype"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp" >
<ImageView
android:id="@+id/phone_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginRight="2dp"
android:src="@drawable/phone_type" />
<TextView
android:id="@+id/phone_type_hanzi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/phone_type"
android:text="Android" />
<ImageView
android:id="@+id/zan_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:layout_toLeftOf="@+id/zan_hanzi"
android:src="@drawable/qz_detail_icon_praise" />
<TextView
android:id="@+id/zan_hanzi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="2dp"
android:layout_marginRight="10dp"
android:layout_toLeftOf="@+id/pinglun_img"
android:text="赞"
android:textSize="12sp" />
<ImageView
android:id="@+id/pinglun_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:layout_toLeftOf="@+id/pinglun_hanzi"
android:src="@drawable/qz_detail_icon_comment" />
<TextView
android:id="@+id/pinglun_hanzi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="评论"
android:textSize="12sp" />
</RelativeLayout>
</LinearLayout>
再看MainActivity:
/**
* @author baiyuliang
*/
public class MainActivity extends Activity {
private MyAdapter mAdapter;
private ArrayList<HashMap<String, String>> listItem;//生成动态数组,加入数据
private RefreshListView mRefreshListView;
private HashMap<String, String> map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
initData();
}
public void initView() {
mRefreshListView = (RefreshListView)findViewById(R.id.refresh_listview);
listItem = new ArrayList<HashMap<String, String>>();
}
private void initData() {
for (int i = 0; i < 10; i++) {
map=new HashMap<String, String>();
map.put("username", "baiyuliang"+(i+1));
map.put("mood", "今天心情不错哈!!!");
map.put("creatdate", new SimpleDateFormat("HH:mm:ss").format(new Date()));
listItem.add(map);
}
mAdapter = new MyAdapter(this, listItem);
mRefreshListView.setAdapter(mAdapter);
mRefreshListView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
// 异步查询数据
new AsyncTask<Void, Void, Void>(){
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(1000);
map=new HashMap<String, String>();
map.put("username", "new");
map.put("mood", "我是被下拉刷新出来的");
map.put("creatdate", new SimpleDateFormat("HH:mm:ss").format(new Date()));
listItem.add(0,map);
return null;
}
protected void onPostExecute(Void result) {
mAdapter.notifyDataSetChanged();
// 隐藏头布局
mRefreshListView.onRefreshFinish();
}
}.execute(new Void[]{});
}
@Override
public void onLoadMoring() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(2000);
for (int i = 0; i < 10; i++) {
map=new HashMap<String, String>();
map.put("username", "baiyuliang");
map.put("mood", "上拉刷新出来的数据"+(i+1));
map.put("creatdate", new SimpleDateFormat("HH:mm:ss").format(new Date()));
listItem.add(map);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mAdapter.notifyDataSetChanged();
mRefreshListView.onRefreshFinish();
}
}.execute(new Void[]{});
}
});
}
}
这个跟普通的listView适配一样,我想大家都知道该怎么做,主要就是我们重写的RefreshListView中包含了两个监听,下拉刷新和上拉加载需要在这里实现,对listview的更新我们需用到notifyDataSetChanged()方法,这个也不需要我多说,我想大家都应该知道,最后我们看一下,头部布局:
<?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="wrap_content"
android:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:padding="5dp">
<ImageView
android:id="@+id/iv_listview_header_down_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/common_listview_headview_red_arrow" />
<ImageView
android:id="@+id/pb_listview_header_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/refresh_loading"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="@+id/tv_listview_header_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="@android:color/darker_gray"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_listview_header_last_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:text="最后刷新时间: 1990-09-09 09:00:00"
android:textColor="@android:color/darker_gray"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
和脚部布局:
<?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="wrap_content"
android:background="#FFFFFF"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp" >
<ImageView
android:id="@+id/pb_listview_footer_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/refresh_loading"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="加载更多..."
android:textColor="@android:color/darker_gray"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
其实就这么多,是不是很简单,主要就是我们重写的ListView控件,如果看不明白,大家可以在下面下载我的源码研究:
http://download.csdn.net/detail/baiyuliang2013/7000317
ListView下拉刷新上拉加载更多实现的更多相关文章
- Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表
本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...
- SwipeRefreshLayout实现下拉刷新上滑加载
1. 效果图 2.RefreshLayout.java package myapplication.com.myapplication; import android.content.Context; ...
- Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView
在弄android刷新的时候,可算是耗费了一番功夫,最后发觉有现成的控件,并且非常好用,这里记录一下. 原文是 https://blog.csdn.net/huangxin112/article/de ...
- juery下拉刷新,div加载更多元素并添加点击事件(二)
buffer.append("<div class='col-xs-3 "+companyId+"' style='padding-left: 10px; padd ...
- 移动端下拉刷新上拉加载-mescroll.js插件
最近无意间看到有这么一个上拉刷新下拉加载的插件 -- mescroll.js,个人感觉挺好用的,官网地址是:http://www.mescroll.com 然后我就看了一下文档,简单的写了一个小dem ...
- Android如何定制一个下拉刷新,上滑加载更多的容器
前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉 ...
- ListView实现Item上下拖动交换位置 并且实现下拉刷新 上拉加载更多
ListView实现Item上下拖动交换位置 并且实现下拉刷新 上拉加载更多 package com.example.ListViewDragItem; import android.app.Ac ...
- listview下拉刷新上拉加载扩展(三)-仿最新版美团外卖
本篇是基于上篇listview下拉刷新上拉加载扩展(二)-仿美团外卖改造而来,主要调整了headview的布局,并加了两个背景动画,看似高大上,其实很简单: as源码地址:http://downloa ...
- listview下拉刷新上拉加载扩展(二)-仿美团外卖
经过前几篇的listview下拉刷新上拉加载讲解,相信你对其实现机制有了一个深刻的认识了吧,那么这篇文章我们来实现一个高级的listview下拉刷新上拉加载-仿新版美团外卖的袋鼠动画: 项目结构: 是 ...
随机推荐
- arc的安装
安装: # sudo apt-get install php5 php5-curl # ubuntu 系统 # sudo yum install php5 # centos 系统 # cd ...
- 深入解析浏览器的幕后工作原理(三) 呈现树和 DOM 树的关系
呈现树和 DOM 树的关系 呈现器是和 DOM 元素相对应的,但并非一一对应.非可视化的 DOM 元素不会插入呈现树中,例如"head"元素.如果元素的 display 属性值为& ...
- ES6 new syntax of Rest and Spread Operators
Rest and Spread Operators.md Why we need rest and spread operators? var showCollections = function(i ...
- 使用Keras对交通标志进行分类
# 使用Keras对交通标志进行分类 一.概述 本文主要记录的在使用Keras过程中,实现交通标志分类,数据集使用的是. 文本主要使用的环境为: Python3.5.2 Tensorflow 1.7 ...
- 计蒜客模拟赛5 D2T1 成绩统计
又到了一年一度的新生入学季了,清华和北大的计算机系同学都参加了同一场开学考试(因为两校兄弟情谊深厚嘛,来一场联考还是很正常的). 不幸的是,正当老师要统计大家的成绩时,世界上的所有计算机全部瘫痪了. ...
- 伊布(ib)
[问题描述]ib 被困在了一个美术馆里,她需要收集美术馆内的每种颜料才能获得逃出美术馆的钥匙美术馆由 n*m 的房间构成,每个房间里有一种颜料,解锁进入后就可以收集.有的房间不能解锁,如果解锁的话会直 ...
- 【BZOJ2809】【APIO2012】派遣
Background 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿. Description 在这个帮派里,有一名忍者被称之为Master.除了Master以外,每名忍者 ...
- C++Primer学习——类型转换
无符号之间的运算 当一个是无符号类型,另外一个是带符号类型: 如果无符号不小于带符号,那么带符号转换成无符号. 如果无符号小于带符号,当无符号类型的所有值都能存到带符号中时,则无符号转换成带符号,否则 ...
- poj 3070 Fibonacci 矩阵快速幂
Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. F ...
- bzoj3930[CQOI2015]选数 容斥原理
3930: [CQOI2015]选数 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1383 Solved: 669[Submit][Status] ...