首先来介绍一下这个自定义View:

  • (1)这个自定义View的名称叫做 RefreshableListView ,继承自ListView类;
  • (2)在这个自定义View中,用户可以设置是否支持下拉刷新或上拉加载,当然也可以设置为都支持或都不支持;
  • (3)在这个自定义View中设置了下拉刷新和上拉加载的回调方法,用户可以自己编写下拉刷新和上拉加载的业务代码。

  接下来简单介绍一下这个自定义View中用到的技术点:

  • (1)为ListView添加头部和底部布局,分别调用addHeaderView() 和addFooterView() 方法;
  • (2)通过ListView的setPadding() 方法设置隐藏ListView的头部和底部布局;
  • (3)通过ListView的 post() 方法将头部布局和底部布局的测量操作post到ListView加载完成后进行;
  • (4)实现 OnScrollListener 接口,在 onScroll() 和 onScrollStateChanged() 方法中判断当前位置是否可以进行上拉或下拉操作;
  • (5)重写 onTouchEvent() 方法,通过手势操作头部布局和底部布局进行下拉刷新和上拉加载操作;
  • (6)使用 ObjectAnimator 属性动画进行头部布局中箭头的反转操作;
  • (7)定义了回调接口,让用户自己编写下拉刷新和上拉加载的业务代码;
  • (8)设置了两个标志位 isRefreshEnabled 和 isLoadEnabled ,让用户自己控制是否可以下拉刷新或上拉加载。

  下面是这个自定义View—— RefreshableListView 中的代码:

  1. import android.animation.ObjectAnimator;
  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.view.LayoutInflater;
  5. import android.view.MotionEvent;
  6. import android.view.View;
  7. import android.widget.AbsListView;
  8. import android.widget.ImageView;
  9. import android.widget.ListView;
  10. import android.widget.ProgressBar;
  11. import android.widget.TextView;
  12.  
  13. /**
  14. * 自定义的可下拉刷新或上拉加载的ListView
  15. */
  16. public class RefreshableListView extends ListView implements AbsListView.OnScrollListener {
  17. private static final int STATE_NORMAL = 0x000; // 正常状态(没有显示头部布局)
  18. private static final int STATE_PULLING = 0x001; // 正在下拉或上拉,但没有达到刷新或加载的要求的状态
  19. private static final int STATE_PREPARED = 0x002; // 达到刷新或加载的要求,松开手指就可以刷新或加载的状态
  20. private static final int STATE_REFRESHING = 0x003; // 正在刷新或加载的状态
  21.  
  22. private View headerView; // 顶部布局
  23. private ImageView arrow; // 顶部布局中的箭头
  24. private ProgressBar headerProgress; // 顶部布局中的进度条
  25. private TextView headerTip; // 顶部布局中的提示信息
  26. private int headerHeight; // 头部布局的高度
  27. private boolean isRefreshEnabled; // 是否允许下拉刷新
  28. private boolean isRefreshable; // 是否可以下拉刷新
  29.  
  30. private ProgressBar footerProgress; // 底部布局中的进度条
  31. private TextView footerTip; // 底部布局中的提示信息
  32. private int footerHeight; // 底部布局的高度
  33. private boolean isLoadEnabled; // 是否允许上拉加载
  34. private boolean isLoadable; // 是否可以上拉加载
  35.  
  36. private int firstItemIndex; // 第一个可见Item的下标
  37. private int visibleItemCount; // 页面中可见的Item的个数
  38. private int totalItemCount; // ListView中加载的Item的总个数
  39.  
  40. private int firstItemTopPadding; // 第一个Item的top值
  41. private int startY; // 记录手指按下时的Y坐标位置
  42. private int offsetY; // 记录手指拖动过程中Y坐标的偏移量
  43. private int rotateTime; // 旋转次数,用于控制箭头只旋转一次
  44. private boolean isScrollIdle; // 滑动动作是否是停止的
  45.  
  46. private OnRefreshListener onRefreshListener;
  47.  
  48. public RefreshableListView(Context context) {
  49. super(context);
  50. initView(context);
  51. }
  52.  
  53. public RefreshableListView(Context context, AttributeSet attrs) {
  54. super(context, attrs);
  55. initView(context);
  56. }
  57.  
  58. public RefreshableListView(Context context, AttributeSet attrs, int defStyleAttr) {
  59. super(context, attrs, defStyleAttr);
  60. initView(context);
  61. }
  62.  
  63. /**
  64. * 初始化界面,添加顶部布局文件到ListView中
  65. */
  66. private void initView(Context context) {
  67. // 初始化头部布局及布局中的控件
  68. headerView = LayoutInflater.from(context).inflate(R.layout.sideworks_rlv_header, this, false);
  69. arrow = (ImageView) headerView.findViewById(R.id.rlv_header_iv_arrow);
  70. headerProgress = (ProgressBar) headerView.findViewById(R.id.rlv_header_progress_progressbar);
  71. headerTip = (TextView) headerView.findViewById(R.id.rlv_header_tv_tip);
  72. // 初始化底部布局及布局中的控件
  73. View footerView = LayoutInflater.from(context).inflate(R.layout.sideworks_rlv_footer, this, false);
  74. footerProgress = (ProgressBar) footerView.findViewById(R.id.rlv_footer_progress_progressbar);
  75. footerTip = (TextView) footerView.findViewById(R.id.rlv_footer_tv_tip);
  76. // 此时视图刚刚开始初始化,如果直接获取测量值会返回0,因此需要将这个操作post到初始化之后进行
  77. this.post(new Runnable() {
  78. @Override
  79. public void run() {
  80. headerHeight = headerView.getMeasuredHeight();
  81. // 布局文件中,头部布局100dp,底部布局60dp,因此偷个懒,用*0.6的方法得到底部布局的高度
  82. footerHeight = (int) (headerHeight * 0.6);
  83. setViewPadding(-headerHeight, -footerHeight);
  84. }
  85. });
  86. this.addHeaderView(headerView);
  87. this.addFooterView(footerView);
  88. this.setOnScrollListener(this);
  89. }
  90.  
  91. /**
  92. * 设置RefreshableListView的上下边距(用于隐藏头部和底部布局)
  93. */
  94. private void setViewPadding(int topPadding, int bottomPadding) {
  95. this.setPadding(headerView.getPaddingLeft(), topPadding, headerView.getPaddingRight(), bottomPadding);
  96. }
  97.  
  98. @Override
  99. public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  100. this.firstItemIndex = firstVisibleItem;
  101. this.visibleItemCount = visibleItemCount;
  102. this.totalItemCount = totalItemCount;
  103. View firstView = this.getChildAt(firstVisibleItem);
  104. if (firstView != null) {
  105. this.firstItemTopPadding = firstView.getTop();
  106. }
  107. }
  108.  
  109. @Override
  110. public void onScrollStateChanged(AbsListView view, int scrollState) {
  111. isScrollIdle = scrollState == OnScrollListener.SCROLL_STATE_IDLE;
  112. }
  113.  
  114. /**
  115. * 监听手指操作的事件(按下、滑动、抬起)
  116. */
  117. @Override
  118. public boolean onTouchEvent(MotionEvent ev) {
  119. switch (ev.getAction()) {
  120. // 手指按下时,判断是否可以下拉刷新或上拉加载
  121. case MotionEvent.ACTION_DOWN:
  122. isRefreshable = false;
  123. if (isRefreshEnabled && firstItemIndex == 0 && firstItemTopPadding == -headerHeight) {
  124. isRefreshable = true;
  125. } else if (isLoadEnabled && isScrollIdle && firstItemIndex + visibleItemCount == totalItemCount) {
  126. isLoadable = true;
  127. }
  128. startY = (int) ev.getY();
  129. break;
  130. // 手指移动时,判断是否在下拉刷新或上拉加载,如果是,则动态改变头部布局或底部布局的状态
  131. case MotionEvent.ACTION_MOVE:
  132. offsetY = (int) ev.getY() - startY;
  133. if (isRefreshEnabled && isRefreshable && offsetY > 0) {
  134. setViewPadding(-headerHeight + offsetY, -footerHeight);
  135. if (offsetY >= headerHeight) {
  136. setCurrentState(STATE_PREPARED);
  137. } else {
  138. setCurrentState(STATE_PULLING);
  139. }
  140. } else if (isLoadEnabled && isLoadable && offsetY < 0) {
  141. setViewPadding(-headerHeight, -footerHeight - offsetY);
  142. if (offsetY <= -footerHeight) {
  143. setCurrentState(STATE_PREPARED);
  144. } else {
  145. setCurrentState(STATE_PULLING);
  146. }
  147. }
  148. break;
  149. // 手指抬起时,判断是否下拉或上拉到可以刷新或加载的程度,如果达到程度,则进行刷新或加载
  150. case MotionEvent.ACTION_UP:
  151. if (isRefreshEnabled && isRefreshable && offsetY > 0) {
  152. if (offsetY <= headerHeight) {
  153. setViewPadding(-headerHeight, -footerHeight);
  154. setCurrentState(STATE_NORMAL);
  155. } else {
  156. setViewPadding(0, -footerHeight);
  157. setCurrentState(STATE_REFRESHING);
  158. onRefreshListener.onRefreshing(); // 调用接口的回调方法
  159. }
  160. } else if (isLoadEnabled && isLoadable && offsetY < 0) {
  161. if (offsetY >= -footerHeight) {
  162. setViewPadding(-headerHeight, -footerHeight);
  163. setCurrentState(STATE_NORMAL);
  164. } else {
  165. setViewPadding(-headerHeight, 0);
  166. setCurrentState(STATE_REFRESHING);
  167. onRefreshListener.onLoading(); // 调用接口的回调方法
  168. }
  169. }
  170. isRefreshable = false;
  171. isLoadable = false;
  172. break;
  173. }
  174. return super.onTouchEvent(ev);
  175. }
  176.  
  177. /**
  178. * 根据当前的状态进行相应的处理
  179. */
  180. private void setCurrentState(int state) {
  181. switch (state) {
  182. // 普通状态:头部布局和尾部布局都隐藏,头部布局中显示箭头不显示进度条,底部布局中不显示进度条
  183. case STATE_NORMAL:
  184. headerProgress.setVisibility(View.GONE);
  185. arrow.setVisibility(View.VISIBLE);
  186. footerProgress.setVisibility(View.GONE);
  187. break;
  188. // 正在下拉后上拉,但没有达到刷新或加载的要求的状态:
  189. // 如果是下拉,则将头部布局中的箭头指向调整为指下,同时改变文本;
  190. // 如果是上拉,则改变文本
  191. case STATE_PULLING:
  192. if (isRefreshEnabled && isRefreshable) {
  193. if (rotateTime == 1) {
  194. ObjectAnimator toUpAnim = ObjectAnimator.ofFloat(arrow, "rotation", 180f, 0f);
  195. toUpAnim.setDuration(200);
  196. toUpAnim.start();
  197. rotateTime--;
  198. }
  199. headerTip.setText("下拉可以刷新");
  200. } else if (isLoadEnabled && isLoadable) {
  201. footerTip.setText("上拉加载更多");
  202. }
  203. break;
  204. // 下拉或上拉达到刷新或加载的条件,但还没有松手的状态:
  205. // 如果是下拉,则将头部布局中的箭头指向调整为指上,同时改变文本;
  206. // 如果是上拉,则改变文本
  207. case STATE_PREPARED:
  208. if (isRefreshEnabled && isRefreshable) {
  209. if (rotateTime == 0) {
  210. ObjectAnimator toUpAnim = ObjectAnimator.ofFloat(arrow, "rotation", 0f, 180f);
  211. toUpAnim.setDuration(200);
  212. toUpAnim.start();
  213. rotateTime++;
  214. }
  215. headerTip.setText("松开手指刷新");
  216. } else if (isLoadEnabled && isLoadable) {
  217. footerTip.setText("松开手指加载");
  218. }
  219. break;
  220. // 正在刷新或加载的状态:
  221. // 如果是下拉,则隐藏头部布局中的箭头,显示头部布局中的进度条,改变文本;
  222. // 如果是上拉,则显示底部布局中的进度条,改变文本
  223. case STATE_REFRESHING:
  224. if (isRefreshEnabled && isRefreshable) {
  225. arrow.setVisibility(View.GONE);
  226. headerProgress.setVisibility(View.VISIBLE);
  227. if (rotateTime == 1) {
  228. ObjectAnimator toUpAnim = ObjectAnimator.ofFloat(arrow, "rotation", 180f, 0f);
  229. toUpAnim.setDuration(200);
  230. toUpAnim.start();
  231. rotateTime--;
  232. }
  233. headerTip.setText("正在刷新......");
  234. } else if (isLoadEnabled && isLoadable) {
  235. footerProgress.setVisibility(View.VISIBLE);
  236. footerTip.setText("正在加载......");
  237. }
  238. break;
  239. }
  240. }
  241.  
  242. /**
  243. * 刷新结束后必须调用这个方法来重置一些参数
  244. */
  245. public void onRefreshComplete() {
  246. setViewPadding(-headerHeight, -footerHeight);
  247. setCurrentState(STATE_NORMAL);
  248. }
  249.  
  250. /**
  251. * 设置是否允许下拉刷新和上拉加载
  252. */
  253. public void setEnables(boolean isRefreshEnabled, boolean isLoadEnabled) {
  254. this.isRefreshEnabled = isRefreshEnabled;
  255. this.isLoadEnabled = isLoadEnabled;
  256. }
  257.  
  258. /**
  259. * 监听下拉刷新的接口
  260. */
  261. interface OnRefreshListener {
  262. void onRefreshing(); // 在下拉刷新的时候回调的方法
  263.  
  264. void onLoading(); // 在上拉加载的时候回调的方法
  265. }
  266.  
  267. public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
  268. this.onRefreshListener = onRefreshListener;
  269. }
  270. }

  头部布局文件 sideworks_rlv_header.xml 中的代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="100.0dip"
  5. android:background="#DEDEDE"
  6. android:gravity="center"
  7. android:orientation="horizontal">
  8.  
  9. <RelativeLayout
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content">
  12.  
  13. <ImageView
  14. android:id="@+id/rlv_header_iv_arrow"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:layout_centerInParent="true"
  18. android:contentDescription="@string/app_name"
  19. android:src="@mipmap/img_rlv_arrow" />
  20.  
  21. <ProgressBar
  22. android:id="@+id/rlv_header_progress_progressbar"
  23. android:layout_width="35.0dip"
  24. android:layout_height="35.0dip"
  25. android:layout_centerInParent="true"
  26. android:visibility="gone" />
  27. </RelativeLayout>
  28.  
  29. <TextView
  30. android:id="@+id/rlv_header_tv_tip"
  31. android:layout_width="wrap_content"
  32. android:layout_height="100.0dip"
  33. android:layout_marginLeft="10.0dip"
  34. android:gravity="center"
  35. android:text="下拉可以刷新"
  36. android:textColor="#444444"
  37. android:textSize="16.0sp"
  38. android:textStyle="bold" />
  39.  
  40. </LinearLayout>

  底部布局文件 sideworks_rlv_footer.xml 中的代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content">
  5.  
  6. <LinearLayout
  7. android:id="@+id/rlv_footer_ly_content"
  8. android:layout_width="match_parent"
  9. android:layout_height="60.0dip"
  10. android:background="#DEDEDE"
  11. android:gravity="center"
  12. android:orientation="horizontal">
  13.  
  14. <ProgressBar
  15. android:id="@+id/rlv_footer_progress_progressbar"
  16. android:layout_width="30.0dip"
  17. android:layout_height="30.0dip"
  18. android:visibility="gone" />
  19.  
  20. <TextView
  21. android:id="@+id/rlv_footer_tv_tip"
  22. android:layout_width="wrap_content"
  23. android:layout_height="60.0dip"
  24. android:layout_marginLeft="10.0dip"
  25. android:gravity="center"
  26. android:text="上拉加载更多"
  27. android:textColor="#444444"
  28. android:textSize="16.0sp"
  29. android:textStyle="bold" />
  30. </LinearLayout>
  31.  
  32. </LinearLayout>

  控件中每一条数据的布局文件 listitem_rlv_listview.xml 中的代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="90.0dip"
  5. android:background="@android:color/white">
  6.  
  7. <ImageView
  8. android:id="@+id/rlv_listitem_iv_image"
  9. android:layout_width="65.0dip"
  10. android:layout_height="65.0dip"
  11. android:layout_centerVertical="true"
  12. android:layout_marginLeft="10.0dip"
  13. android:contentDescription="@string/app_name"
  14. android:src="@mipmap/img_rlv_listitem_image" />
  15.  
  16. <TextView
  17. android:id="@+id/rlv_listitem_tv_name"
  18. android:layout_width="wrap_content"
  19. android:layout_height="90.0dip"
  20. android:layout_centerVertical="true"
  21. android:layout_marginLeft="10.0dip"
  22. android:layout_toRightOf="@id/rlv_listitem_iv_image"
  23. android:gravity="center"
  24. android:textColor="@android:color/black"
  25. android:textSize="16.0sp" />
  26.  
  27. <Button
  28. android:id="@+id/rlv_listitem_btn_download"
  29. android:layout_width="wrap_content"
  30. android:layout_height="wrap_content"
  31. android:layout_alignParentRight="true"
  32. android:layout_centerVertical="true"
  33. android:layout_marginRight="10.0dip"
  34. android:text="Download" />
  35.  
  36. </RelativeLayout>

  适配器类文件 ListViewAdapter.java 中的代码:

  1. import android.content.Context;
  2. import android.view.LayoutInflater;
  3. import android.view.View;
  4. import android.view.ViewGroup;
  5. import android.widget.BaseAdapter;
  6. import android.widget.Button;
  7. import android.widget.ImageView;
  8. import android.widget.TextView;
  9. import android.widget.Toast;
  10.  
  11. import java.util.List;
  12.  
  13. /**
  14. * ListView的数据适配器
  15. */
  16. public class ListViewAdapter extends BaseAdapter {
  17. private Context context;
  18. private List<String> nameList;
  19.  
  20. public ListViewAdapter(Context context, List<String> nameList) {
  21. this.context = context;
  22. this.nameList = nameList;
  23. }
  24.  
  25. @Override
  26. public int getCount() {
  27. return nameList.size();
  28. }
  29.  
  30. @Override
  31. public Object getItem(int position) {
  32. return nameList.get(position);
  33. }
  34.  
  35. @Override
  36. public long getItemId(int position) {
  37. return position;
  38. }
  39.  
  40. @Override
  41. public View getView(final int position, View convertView, ViewGroup parent) {
  42. ViewHolder holder = null;
  43. if (convertView == null) {
  44. convertView = LayoutInflater.from(context).inflate(R.layout.listitem_rlv_listview, parent, false);
  45. holder = new ViewHolder();
  46. holder.image = (ImageView) convertView.findViewById(R.id.rlv_listitem_iv_image);
  47. holder.name = (TextView) convertView.findViewById(R.id.rlv_listitem_tv_name);
  48. holder.download = (Button) convertView.findViewById(R.id.rlv_listitem_btn_download);
  49. convertView.setTag(holder);
  50. } else {
  51. holder = (ViewHolder) convertView.getTag();
  52. }
  53. holder.image.setImageResource(R.mipmap.ic_launcher);
  54. holder.name.setText(nameList.get(position));
  55. holder.download.setOnClickListener(new View.OnClickListener() {
  56. @Override
  57. public void onClick(View v) {
  58. Toast.makeText(context, nameList.get(position) + " Clicked!", Toast.LENGTH_SHORT).show();
  59. }
  60. });
  61. return convertView;
  62. }
  63.  
  64. private static class ViewHolder {
  65. ImageView image;
  66. TextView name;
  67. Button download;
  68. }
  69. }

  主界面的JAVA文件 MainActivity.java 中的代码:

  1. import android.os.Handler;
  2. import android.os.Message;
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.os.Bundle;
  5.  
  6. import java.util.ArrayList;
  7. import java.util.List;
  8.  
  9. public class MainActivity extends AppCompatActivity {
  10. private RefreshableListView listview; // 自定义ListView控件
  11.  
  12. private List<String> nameList; // RefreshableListView控件中显示的数据的数据集
  13. private ListViewAdapter adapter; // RefreshableListView控件的适配器
  14.  
  15. // Handler更新UI界面
  16. private Handler refreshHandler = new Handler() {
  17. @Override
  18. public void handleMessage(Message msg) {
  19. switch (msg.what) {
  20. // 下拉刷新的回调,在列表的最前面插入一条数据
  21. case 0:
  22. nameList.add(0, "新加入的名称!!");
  23. break;
  24. // 上拉加载的回调,在列表的最后添加一条数据
  25. case 1:
  26. nameList.add("新加入的名称!!");
  27. break;
  28. }
  29. // ListView的数据适配器更新数据集
  30. adapter.notifyDataSetChanged();
  31. // 必须调用这个方法,重置头部布局或底部布局的视图
  32. listview.onRefreshComplete();
  33. }
  34. };
  35.  
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. setContentView(R.layout.activity_main);
  40. }
  41.  
  42. @Override
  43. protected void onResume() {
  44. super.onResume();
  45. // 通过ID找到我们的自定义控件RefreshableListView
  46. listview = (RefreshableListView) this.findViewById(R.id.rlv_lv_listview);
  47. // 初始化RefreshableListView控件中显示的数据集
  48. initNameList();
  49. // 创建RefreshableListView的数据适配器
  50. adapter = new ListViewAdapter(MainActivity.this, nameList);
  51. // 为RefreshableListView适配数据
  52. listview.setAdapter(adapter);
  53. // 设置是否可以下拉刷新或上拉加载,这里设置的是可以下拉刷新,不可以上拉加载
  54. listview.setEnables(true, false);
  55. // 设置RefreshableListView的回调
  56. listview.setOnRefreshListener(new RefreshableListView.OnRefreshListener() {
  57. // 下拉刷新的回调方法,在这个方法中停留2秒后发送一条消息给Handler
  58. @Override
  59. public void onRefreshing() {
  60. new Thread(new Runnable() {
  61. @Override
  62. public void run() {
  63. try {
  64. Thread.sleep(2000);
  65. } catch (InterruptedException e) {
  66. e.printStackTrace();
  67. }
  68. refreshHandler.sendEmptyMessage(0);
  69. }
  70. }).start();
  71. }
  72.  
  73. // 上拉加载的回调方法,在这个方法中停留2秒后发送一条消息给Handler
  74. @Override
  75. public void onLoading() {
  76. new Thread(new Runnable() {
  77. @Override
  78. public void run() {
  79. try {
  80. Thread.sleep(2000);
  81. } catch (InterruptedException e) {
  82. e.printStackTrace();
  83. }
  84. refreshHandler.sendEmptyMessage(1);
  85. }
  86. }).start();
  87. }
  88. });
  89. }
  90.  
  91. /**
  92. * 初始化RefreshableListView控件中显示的数据集
  93. */
  94. private void initNameList() {
  95. nameList = new ArrayList<>();
  96. for (int i = 0; i < 15; i++) {
  97. nameList.add("APP名称" + (i + 1));
  98. }
  99. }
  100. }

  最后上一张效果图(这张效果图是同时支持下拉刷新和上拉加载功能的),如下:

【Android - 自定义View】之自定义可下拉刷新或上拉加载的ListView的更多相关文章

  1. Android如何定制一个下拉刷新,上滑加载更多的容器

    前言 下拉刷新和上滑加载更多,是一种比较常用的列表数据交互方式. android提供了原生的下拉刷新容器 SwipeRefreshLayout,可惜样式不能定制. 于是打算自己实现一个专用的.但是下拉 ...

  2. Android之下拉刷新,上啦加载的实现(一)

    转载地址http://blog.csdn.net/leehong2005/article/details/12567757#t5 前段时间项目中用到了下拉刷新功能,之前在网上也找到过类似的demo,但 ...

  3. Android打造(ListView、GridView等)通用的下拉刷新、上拉自动加载的组件

    原文 http://blog.csdn.net/bboyfeiyu/article/details/39253051       前言 下 拉刷新组件在开发中使用率是非常高的,基本上联网的APP都会采 ...

  4. Android XListView下拉刷新、上拉载入更多

    source code: https://github.com/Maxwin-z/XListView-Android 提供了两个接口: a) IXListViewListener:  触发下拉刷新.上 ...

  5. SVPullToRefresh​ 下拉刷新,上拉加载

    https://github.com/Sephiroth87/ODRefreshControl 类似刷新控件,类似qq动画的那种刷新. 一.下载第三方库 https://github.com/samv ...

  6. DCloud-MUI:下拉刷新、上拉加载

    ylbtech-DCloud-MUI:下拉刷新.上拉加载 1. 下拉刷新返回顶部 0. http://dev.dcloud.net.cn/mui/pulldown/ 1. 概述 为实现下拉刷新功能,大 ...

  7. iOS-SVPullToRefresh​下拉刷新,上拉加载(转)

    https://github.com/Sephiroth87/ODRefreshControl 类似刷新控件,类似qq动画的那种刷新. 一.下载第三方库 https://github.com/samv ...

  8. iOS MJRefresh下拉刷新(上拉加载)使用详解

    下拉刷新控件目前比较火的有好几种,本人用过MJRefresh 和 SVPullToRefresh,相对而言,前者比后者可定制化.拓展新都更高一点. 因此本文着重讲一下MJRefresh的简单用法. 导 ...

  9. ListView下拉刷新、上拉载入更多之封装改进

    在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...

随机推荐

  1. ansible模块之command、shell、script、file、copy、fetch

    前戏 ansible 批量在远程主机上执行命令 openpyxl 操作excel表格 puppet ansible slatstack ansible epel源 第一步: 下载epel源 wget ...

  2. DRF之认证组件、权限组件、频率组件使用方法总结

    认证组件格式: from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions ...

  3. jwt token

    1 ,session 认证机制: ,用户登录,传递用户名和密码给客户端 ,服务器进行用户名和密码的校验,如果校验成功,将用户保存到session ,将sessionid通过cookie返回给客服端,客 ...

  4. JNI技术实现--Java调C/C++

    废话不多说,首先我们来看Java调用C/C++步骤: 1.编写Java代码,在代码中使用native关键字标明该方法是调用本地库,不需要实现. 2.使用javah -jni 命令,生成对应的头文件,此 ...

  5. C++学习笔记13_操作MySql

    1. 链接Mysql #include <winsock.h>#include "mysql.h"#include <stdlib.h>#include & ...

  6. C++学习笔记2_函数.函数指针.函数模板

    1. 内联函数void printAB(int a,int b){ cout<<(a)<<(b)<<endl;}int main(void){ for(int i= ...

  7. Covenant cc 用法

    新出现的cc框架,之前看hack the box有人用过,不过还是用cs比较多, 这里把之前的笔记搬运过来 ---   设置covenant git clone --recurse-submodule ...

  8. CSPS模拟 95

    T_T flag彻底倒了 虽然打一开始就没觉得能实现过 可是我好桑心T_T skyh那个没素质的还一直bb T_T

  9. 【转】python之property属性

    1. 什么是property属性 一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法 # ############### 定义 ############### class Foo: def ...

  10. 【自然语言处理】利用LDA对希拉里邮件进行主题分析

    首先是读取数据集,并将csv中ExtractedBodyText为空的给去除掉 import pandas as pd import re import os dir_path=os.path.dir ...