Android中实现下拉刷新

需求:项目中的消息列表界面要求实现类似sina微博的下拉刷新;

思路:一般的消息列表为ListView类型,将list加载到adapter中,再将adapter加载到 ListView中,从而实现消息列表的展示。而下拉刷新要求给消息列表加一个头部,其中有图片(向上/向下箭头)和提示字样(下拉刷新/松开刷新),从 而我们需要做的事情:1.需要做一个head.xm来实现头部的样式定义;2.需要自定义一个继承了ListView的MsgListView,在该类中 将head加在MsgListView对象的头部;3.将原有的消息界面布局文件中的ListView改为 cn.xd.microblogging.tools.MsgListView(包名.MsgListView);4.将原有的消息界面后台代码中创建的 ListView对象改为MsgListView对象,注意消息界面Activity要继承ListActivity,并且实现其刷新监听。

说明:实现下拉刷新很简单,仅需要4个文件:MsgRcvListActivity.java(消息列表界面的后台文件,真正的刷新动作在这里完成,下拉刷新相关code下面列出),msgrcvlistactivity.xml(消息列表界面的前台文件,下拉刷新相关code下面列出),MsgListView.java(本文件拿来主义即可不用改,下拉刷新自定义的列表类,监听并执行下拉刷新、松开刷新、正在刷新、完成刷新等状态的改变,但真正的刷新动作不在这里完成,完整code下面列出),head.xml(本文件拿来主义即可不用改,下拉刷新的样式定义文件,包括向上、向下箭头,刷新状态提示等,完整code下面列出);

效果

代码

1.MsgRcvListActivity.java :

[java] view plaincopy

  1. public class MsgRcvListActivity extends ListActivity {//注意:要继承ListActivity
  2. …………//变量定义,略
  3. MsgListView list;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.msgrcvlistactivity);
  8. list=(MsgListView)findViewById(android.R.id.list);//继承ListActivity,id要写成android.R.id.list,否则报异常
  9. …………//其他代码,略
  10. //刷新监听,此处实现真正刷新
  11. list.setonRefreshListener(new OnRefreshListener() {
  12. public void onRefresh() {
  13. new AsyncTask<Void, Void, Void>() {
  14. protected Void doInBackground(Void... params) {
  15. try {
  16. Thread.sleep(1000);
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. }
  20. return null;
  21. }
  22. @Override
  23. protected void onPostExecute(Void result) {
  24. adapter.notifyDataSetChanged();
  25. new MsgLoad().execute();//刷新监听中,真正执行刷新动作
  26. list.onRefreshComplete();
  27. }
  28. }.execute(null);
  29. }
  30. });
  31. list.setItemsCanFocus(false);
  32. list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
  33. }
  34. …………//其他代码,略
  35. public class MsgLoad extends AsyncTask<Void, Void, List<MsgBean>> {
  36. …………//其他代码,略
  37. }
  38. }

2.msgrcvlistactivity.xml:

[html] view plaincopy

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <LinearLayout android:orientation="vertical"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent"
  10. android:background="#000000">
  11. //将ListView改为包名.自定义的列表类名,MsgListView.java代码见后,此代码不需改通用,下拉刷新相关即此处,其他无关
  12. <cn.xd.microblogging.tools.MsgListView
  13. android:id="@android:id/list"
  14. android:layout_height="wrap_content"
  15. android:layout_width="fill_parent"
  16. android:layout_weight="1.0"
  17. android:drawSelectorOnTop="false"
  18. android:scrollbars="vertical"
  19. android:fadingEdgeLength="0dip"
  20. android:divider="@drawable/line"
  21. android:dividerHeight="3.0dip"
  22. android:cacheColorHint="#00000000"
  23. android:paddingBottom="40dp"/>
  24. </LinearLayout>
  25. <LinearLayout
  26. android:id="@+id/msg_list_load"
  27. android:layout_width="fill_parent"
  28. android:layout_height="fill_parent" >
  29. <LinearLayout android:id="@android:id/empty"
  30. android:layout_width="fill_parent"
  31. android:layout_height="fill_parent" >
  32. <include
  33. android:id="@android:id/empty"
  34. layout="@layout/empty_loading"
  35. android:layout_width="fill_parent"
  36. android:layout_height="fill_parent" />
  37. </LinearLayout>
  38. </LinearLayout>
  39. </RelativeLayout>

3.MsgListView.java,拷进项目基本不需改:

[java] view plaincopy

  1. package cn.xd.microblogging.tools;
  2. import java.util.Date;
  3. import cn.xd.microblogging.R;
  4. import android.content.Context;
  5. import android.util.AttributeSet;
  6. import android.util.Log;
  7. import android.view.LayoutInflater;
  8. import android.view.MotionEvent;
  9. import android.view.View;
  10. import android.view.ViewGroup;
  11. import android.view.animation.LinearInterpolator;
  12. import android.view.animation.RotateAnimation;
  13. import android.widget.AbsListView;
  14. import android.widget.BaseAdapter;
  15. import android.widget.ImageView;
  16. import android.widget.LinearLayout;
  17. import android.widget.ListView;
  18. import android.widget.AbsListView.OnScrollListener;
  19. import android.widget.ProgressBar;
  20. import android.widget.TextView;
  21. /**
  22. *
  23. * 自定义MsgListView,继承了ListView,
  24. * 但填充了listview的头部,即下拉刷新样式,并实现其功能
  25. * @author yanbo
  26. *
  27. */
  28. public class MsgListView extends ListView implements OnScrollListener {
  29. private final static int RELEASE_To_REFRESH = 0;
  30. private final static int PULL_To_REFRESH = 1;
  31. private final static int REFRESHING = 2;
  32. private final static int DONE = 3;
  33. private LayoutInflater inflater;
  34. private LinearLayout headView; // 头部
  35. private TextView tipsTextview;//下拉刷新
  36. private TextView lastUpdatedTextView;//最新更新
  37. private ImageView arrowImageView;//箭头
  38. private ProgressBar progressBar;//刷新进度条
  39. private RotateAnimation animation;//旋转特效 刷新中箭头翻转 向下变向上
  40. private RotateAnimation reverseAnimation;
  41. // 用于保证startY的值在一个完整的touch事件中只被记录一次
  42. private boolean isRecored;
  43. private int headContentWidth;//头部宽度
  44. private int headContentHeight;//头部高度
  45. private int startY;//高度起始位置,用来记录与头部距离
  46. private int firstItemIndex;//列表中首行索引,用来记录其与头部距离
  47. private int state;//下拉刷新中、松开刷新中、正在刷新中、完成刷新
  48. private boolean isBack;
  49. public OnRefreshListener refreshListener;//刷新监听
  50. private final static String TAG = "abc";
  51. public MsgListView(Context context, AttributeSet attrs) {
  52. super(context, attrs);
  53. init(context);
  54. }
  55. private void init(Context context) {
  56. inflater = LayoutInflater.from(context);
  57. headView = (LinearLayout) inflater.inflate(R.layout.head, null);//listview拼接headview
  58. arrowImageView = (ImageView) headView
  59. .findViewById(R.id.head_arrowImageView);//headview中各view
  60. arrowImageView.setMinimumWidth(50);
  61. arrowImageView.setMinimumHeight(50);
  62. progressBar = (ProgressBar) headView
  63. .findViewById(R.id.head_progressBar);//headview中各view
  64. tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);//headview中各view
  65. lastUpdatedTextView = (TextView) headView
  66. .findViewById(R.id.head_lastUpdatedTextView);//headview中各view
  67. measureView(headView);
  68. headContentHeight = headView.getMeasuredHeight();//头部高度
  69. headContentWidth = headView.getMeasuredWidth();//头部宽度
  70. headView.setPadding(0, -1 * headContentHeight, 0, 0);//setPadding(int left, int top, int right, int bottom)
  71. headView.invalidate();//Invalidate the whole view
  72. Log.v("size", "width:" + headContentWidth + " height:"
  73. + headContentHeight);
  74. addHeaderView(headView);//添加进headview
  75. setOnScrollListener(this);//滚动监听
  76. animation = new RotateAnimation(0, -180,
  77. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
  78. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  79. animation.setInterpolator(new LinearInterpolator());
  80. animation.setDuration(250);
  81. animation.setFillAfter(true);//特效animation设置
  82. reverseAnimation = new RotateAnimation(-180, 0,
  83. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
  84. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  85. reverseAnimation.setInterpolator(new LinearInterpolator());
  86. reverseAnimation.setDuration(250);
  87. reverseAnimation.setFillAfter(true);//特效reverseAnimation设置
  88. }
  89. public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,//滚动事件
  90. int arg3) {
  91. firstItemIndex = firstVisiableItem;//得到首item索引
  92. }
  93. public void onScrollStateChanged(AbsListView arg0, int arg1) {
  94. }
  95. public boolean onTouchEvent(MotionEvent event) {//触摸事件
  96. switch (event.getAction()) {
  97. case MotionEvent.ACTION_DOWN://手按下  对应下拉刷新状态
  98. if (firstItemIndex == 0 && !isRecored) {//如果首item索引为0,且尚未记录startY,则在下拉时记录之,并执行isRecored = true;
  99. startY = (int) event.getY();
  100. isRecored = true;
  101. Log.v(TAG, "在down时候记录当前位置‘");
  102. }
  103. break;
  104. case MotionEvent.ACTION_UP://手松开  对应松开刷新状态
  105. if (state != REFRESHING) {//手松开有4个状态:下拉刷新、松开刷新、正在刷新、完成刷新。如果当前不是正在刷新
  106. if (state == DONE) {//如果当前是完成刷新,什么都不做
  107. }
  108. if (state == PULL_To_REFRESH) {//如果当前是下拉刷新,状态设为完成刷新(意即下拉刷新中就松开了,实际未完成刷新),执行changeHeaderViewByState()
  109. state = DONE;
  110. changeHeaderViewByState();
  111. Log.v(TAG, "由下拉刷新状态,到done状态");
  112. }
  113. if (state == RELEASE_To_REFRESH) {//如果当前是松开刷新,状态设为正在刷新(意即松开刷新中松开手,才是真正地刷新),执行changeHeaderViewByState()
  114. state = REFRESHING;
  115. changeHeaderViewByState();
  116. onRefresh();//真正刷新,所以执行onrefresh,执行后状态设为完成刷新
  117. Log.v(TAG, "由松开刷新状态,到done状态");
  118. }
  119. }
  120. isRecored = false;//手松开,则无论怎样,可以重新记录startY,因为只要手松开就认为一次刷新已完成
  121. isBack = false;
  122. break;
  123. case MotionEvent.ACTION_MOVE://手拖动,拖动过程中不断地实时记录当前位置
  124. int tempY = (int) event.getY();
  125. if (!isRecored && firstItemIndex == 0) {//如果首item索引为0,且尚未记录startY,则在拖动时记录之,并执行isRecored = true;
  126. Log.v(TAG, "在move时候记录下位置");
  127. isRecored = true;
  128. startY = tempY;
  129. }
  130. if (state != REFRESHING && isRecored) {//如果状态不是正在刷新,且已记录startY:tempY为拖动过程中一直在变的高度,startY为拖动起始高度
  131. // 可以松手去刷新了
  132. if (state == RELEASE_To_REFRESH) {//如果状态是松开刷新
  133. // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
  134. if ((tempY - startY < headContentHeight)//如果实时高度大于起始高度,且两者之差小于头部高度,则状态设为下拉刷新
  135. && (tempY - startY) > 0) {
  136. state = PULL_To_REFRESH;
  137. changeHeaderViewByState();
  138. Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
  139. }
  140. // 一下子推到顶了
  141. else if (tempY - startY <= 0) {//如果实时高度小于等于起始高度了,则说明到顶了,状态设为完成刷新
  142. state = DONE;
  143. changeHeaderViewByState();
  144. Log.v(TAG, "由松开刷新状态转变到done状态");
  145. }
  146. // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
  147. else {//如果当前拖动过程中既没有到下拉刷新的地步,也没有到完成刷新(到顶)的地步,则保持松开刷新状态
  148. // 不用进行特别的操作,只用更新paddingTop的值就行了
  149. }
  150. }
  151. // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
  152. if (state == PULL_To_REFRESH) {//如果状态是下拉刷新
  153. // 下拉到可以进入RELEASE_TO_REFRESH的状态
  154. if (tempY - startY >= headContentHeight) {//如果实时高度与起始高度之差大于等于头部高度,则状态设为松开刷新
  155. state = RELEASE_To_REFRESH;
  156. isBack = true;
  157. changeHeaderViewByState();
  158. Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
  159. }
  160. // 上推到顶了
  161. else if (tempY - startY <= 0) {//如果实时高度小于等于起始高度了,则说明到顶了,状态设为完成刷新
  162. state = DONE;
  163. changeHeaderViewByState();
  164. Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
  165. }
  166. }
  167. // done状态下
  168. if (state == DONE) {//如果状态是完成刷新
  169. if (tempY - startY > 0) {//如果实时高度大于起始高度了,则状态设为下拉刷新
  170. state = PULL_To_REFRESH;
  171. changeHeaderViewByState();
  172. }
  173. }
  174. // 更新headView的size
  175. if (state == PULL_To_REFRESH) {//如果状态是下拉刷新,更新headview的size           ?
  176. headView.setPadding(0, -1 * headContentHeight
  177. + (tempY - startY), 0, 0);
  178. headView.invalidate();
  179. }
  180. // 更新headView的paddingTop
  181. if (state == RELEASE_To_REFRESH) {//如果状态是松开刷新,更新 headview的paddingtop      ?
  182. headView.setPadding(0, tempY - startY - headContentHeight,
  183. 0, 0);
  184. headView.invalidate();
  185. }
  186. }
  187. break;
  188. }
  189. return super.onTouchEvent(event);
  190. }
  191. // 当状态改变时候,调用该方法,以更新界面
  192. private void changeHeaderViewByState() {
  193. switch (state) {
  194. case RELEASE_To_REFRESH:
  195. arrowImageView.setVisibility(View.VISIBLE);
  196. progressBar.setVisibility(View.GONE);
  197. tipsTextview.setVisibility(View.VISIBLE);
  198. lastUpdatedTextView.setVisibility(View.VISIBLE);
  199. arrowImageView.clearAnimation();
  200. arrowImageView.startAnimation(animation);
  201. tipsTextview.setText("松开刷新");
  202. Log.v(TAG, "当前状态,松开刷新");
  203. break;
  204. case PULL_To_REFRESH:
  205. progressBar.setVisibility(View.GONE);
  206. tipsTextview.setVisibility(View.VISIBLE);
  207. lastUpdatedTextView.setVisibility(View.VISIBLE);
  208. arrowImageView.clearAnimation();
  209. arrowImageView.setVisibility(View.VISIBLE);
  210. // 是由RELEASE_To_REFRESH状态转变来的
  211. if (isBack) {
  212. isBack = false;
  213. arrowImageView.clearAnimation();
  214. arrowImageView.startAnimation(reverseAnimation);
  215. tipsTextview.setText("下拉刷新");
  216. } else {
  217. tipsTextview.setText("下拉刷新");
  218. }
  219. Log.v(TAG, "当前状态,下拉刷新");
  220. break;
  221. case REFRESHING:
  222. headView.setPadding(0, 0, 0, 0);
  223. headView.invalidate();
  224. progressBar.setVisibility(View.VISIBLE);
  225. arrowImageView.clearAnimation();
  226. arrowImageView.setVisibility(View.GONE);
  227. tipsTextview.setText("正在刷新...");
  228. lastUpdatedTextView.setVisibility(View.VISIBLE);
  229. Log.v(TAG, "当前状态,正在刷新...");
  230. break;
  231. case DONE:
  232. headView.setPadding(0, -1 * headContentHeight, 0, 0);
  233. headView.invalidate();
  234. progressBar.setVisibility(View.GONE);
  235. arrowImageView.clearAnimation();
  236. arrowImageView
  237. .setImageResource(R.drawable.ic_pulltorefresh_arrow);
  238. tipsTextview.setText("下拉刷新");
  239. lastUpdatedTextView.setVisibility(View.VISIBLE);
  240. Log.v(TAG, "当前状态,done");
  241. break;
  242. }
  243. }
  244. public void setonRefreshListener(OnRefreshListener refreshListener) {
  245. this.refreshListener = refreshListener;
  246. }
  247. public interface OnRefreshListener {
  248. public void onRefresh();
  249. }
  250. public void onRefreshComplete() {
  251. state = DONE;
  252. lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());//刷新完成时,头部提醒的刷新日期
  253. changeHeaderViewByState();
  254. }
  255. private void onRefresh() {
  256. if (refreshListener != null) {
  257. refreshListener.onRefresh();
  258. }
  259. }
  260. //此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
  261. private void measureView(View child) {
  262. ViewGroup.LayoutParams p = child.getLayoutParams();
  263. if (p == null) {
  264. p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
  265. ViewGroup.LayoutParams.WRAP_CONTENT);
  266. }
  267. int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
  268. int lpHeight = p.height;
  269. int childHeightSpec;
  270. if (lpHeight > 0) {
  271. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
  272. MeasureSpec.EXACTLY);
  273. } else {
  274. childHeightSpec = MeasureSpec.makeMeasureSpec(0,
  275. MeasureSpec.UNSPECIFIED);
  276. }
  277. child.measure(childWidthSpec, childHeightSpec);
  278. }
  279. }

4.head.xml,拷进项目基本不需改:

[html] view plaincopy

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <!-- ListView的头部 -->
    3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    4. android:id="@+id/head_rootLayout"
    5. android:layout_width="fill_parent"
    6. android:layout_height="wrap_content" >
    7. <!-- 内容 -->
    8. <RelativeLayout
    9. xmlns:android="http://schemas.android.com/apk/res/android"
    10. android:id="@+id/head_contentLayout"
    11. android:layout_width="fill_parent"
    12. android:layout_height="wrap_content"
    13. android:paddingLeft="30dp" >
    14. <!-- 箭头图像、进度条 -->
    15. <FrameLayout
    16. android:layout_width="wrap_content"
    17. android:layout_height="wrap_content"
    18. android:layout_alignParentLeft="true"
    19. android:layout_centerVertical="true" >
    20. <!-- 箭头 -->
    21. <ImageView
    22. android:id="@+id/head_arrowImageView"
    23. android:layout_width="wrap_content"
    24. android:layout_height="wrap_content"
    25. android:layout_gravity="center"
    26. android:src="@drawable/ic_pulltorefresh_arrow"
    27. android:contentDescription="@string/app_name"/>
    28. <!-- 进度条 -->
    29. <ProgressBar
    30. android:id="@+id/head_progressBar"
    31. style="?android:attr/progressBarStyleSmall"
    32. android:layout_width="wrap_content"
    33. android:layout_height="wrap_content"
    34. android:layout_gravity="center"
    35. android:visibility="gone" />
    36. </FrameLayout>
    37. <!-- 提示、最近更新 -->
    38. <LinearLayout
    39. android:layout_width="wrap_content"
    40. android:layout_height="wrap_content"
    41. android:layout_centerHorizontal="true"
    42. android:gravity="center_horizontal"
    43. android:orientation="vertical" >
    44. <!-- 提示 -->
    45. <TextView
    46. android:id="@+id/head_tipsTextView"
    47. android:layout_width="wrap_content"
    48. android:layout_height="wrap_content"
    49. android:text="@string/pulltorefresh"
    50. android:textColor="#ffffff"
    51. android:textSize="20sp" />
    52. <!-- 最近更新 -->
    53. <TextView
    54. android:id="@+id/head_lastUpdatedTextView"
    55. android:layout_width="wrap_content"
    56. android:layout_height="wrap_content"
    57. android:text="@string/lastupdate"
    58. android:textColor="#cc6600"
    59. android:textSize="10sp" />
    60. </LinearLayout>
    61. </RelativeLayout>
    62. </LinearLayout>

Android中实现下拉刷新

时间: 2024-09-29 16:36:45

Android中实现下拉刷新的相关文章

Android中ListView下拉刷新的实现

ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: [java] view plain copy package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import androi

【转载】Android中ListView下拉刷新的实现

在网上看到一个下拉刷新的例子,很的很棒,转载和更多的人分享学习 原文:http://blog.csdn.net/loongggdroid/article/details/9385535 ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: [java] view plaincopy package net.loonggg.listview; import jav

android中listView下拉刷新

Android的ListView是应用最广的一个组件,功能强大,扩展性灵活(不局限于ListView本身一个类),前面的文章有介绍分组,拖拽,3D立体,游标,圆角,而今天我们要介绍的是另外一个扩展ListView:下拉刷新的ListView.    下拉刷新界面最初流行于iphone应用界面,如图:     然后在Android中也逐渐被应用,比如微博,资讯类.    所以,今天要实现的结果应该也是类似的,先贴出最终完成效果,如下图,接下来我们一步一步实现. 1. 流程分析    下拉刷新最主要

Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新

 <Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新> 下拉刷新在如今移动开发中应用如此广泛和普遍,以至于谷歌干脆在SDK中给予支持.在android-support-v4包中,谷歌增加了SwipeRefreshLayout,该组件提供基础的下拉刷新表现能力和开放出来供开发者调用的基本接口.现在给出一个简单的代码例子加以说明. 代码工程简要说明:以一个SwipeRefreshLayout包裹ListView,SwipeRefreshLayout接管List

Android UI- PullToRrefresh自定义下拉刷新动画

Android UI- PullToRrefresh自定义下拉刷新动画 如果觉得本文不错,麻烦投一票,2014年博客之星投票地址:http://vote.blog.csdn.net/blogstar2014/details?username=wwj_748#content 本篇博文要给大家分享的是如何使用修改开源项目PullToRrefresh下拉刷新的动画,来满足我们开发当中特定的需求,我们比较常见的一种下拉刷新样式可能是以下这种: 就是下拉列表的时候两个箭头上下翻转,更改日期文本和刷新状态,

Android自定义ListView下拉刷新

实现的目标是本地有数据并没有刷新.下拉数据及时刷新数据. 我在网上找了某位写的MyListView,这个东西的下拉核心部分还是没有弄明白.非常感谢这位作者. XML布局文件源代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

Android中自定义下拉样式Spinner

Android中自定义下拉样式Spinner 本文继续介绍android自定义控件系列,自定义Spinner控件的使用. 实现思路 1.定义下拉控件布局(ListView及子控件布局) 2.自定义SpinerPopWindow类 3.定义填充数据的Adapter 效果图 一.定义控件布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http:/

android控件 下拉刷新pulltorefresh

外国人写的下拉刷新控件,我把他下载下来放在网盘,有时候访问不了github 支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.GridView.(Horizontal )ScrollView.Fragment上下左右拉动刷新,比下面johannilsson那个只支持ListView的强大的多.并且他实现的下拉刷新ListView在item不足一屏情况下也不会显示刷新提示,体验更好. 国内网盘地址:http://www.400gb.c

android中自定义下拉框(转)

android自带的下拉框好用不?我觉得有时候好用,有时候难有,项目规定这样的效果,自带的控件实现不了,那么只有我们自己来老老实实滴写一个新的了,其实最基本的下拉框就像一些资料填写时,点击的时候出现在编辑框的下面,然后又很多选项的下拉框,可是我在网上找了一下,没有这种下拉框额,就自己写了一个,看效果图先: ,这个是资料填写的一部分界面,三个下拉框,选择故乡所在地: 点击之后弹出下拉框,选择下面的选项: 三个下拉框时关联的,第一个决定了第二数据内容,第二个决定了第三个数据内容,如果三个全部选好之后