歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android模仿QQ空間的下拉更新的功能實現

Android模仿QQ空間的下拉更新的功能實現

日期:2017/3/1 10:14:07   编辑:Linux編程
看看今天模仿的QQ空間的下拉更新個應用吧

首先看看布局

1.main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical" >
  6. <EditText
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:drawableLeft="@drawable/write"
  10. android:lines="1"
  11. android:padding="5px"
  12. android:singleLine="true"
  13. android:text="寫說說" />
  14. <TabHost
  15. android:id="@+id/tabhost"
  16. android:background="@drawable/bg"
  17. android:layout_width="match_parent"
  18. android:layout_height="match_parent" >
  19. <LinearLayout
  20. android:id="@+id/linearLayout1"
  21. android:layout_width="match_parent"
  22. android:layout_height="match_parent"
  23. android:orientation="vertical" >
  24. <TabWidget
  25. android:id="@android:id/tabs"
  26. android:layout_width="match_parent"
  27. android:layout_height="wrap_content" >
  28. </TabWidget>
  29. <FrameLayout
  30. android:id="@android:id/tabcontent"
  31. android:layout_width="match_parent"
  32. android:layout_height="match_parent" >
  33. <LinearLayout
  34. android:id="@+id/tab1"
  35. android:layout_width="match_parent"
  36. android:layout_height="match_parent"
  37. >
  38. <com.wang.MyListView
  39. android:id="@+id/listView"
  40. android:layout_width="fill_parent"
  41. android:layout_height="fill_parent"
  42. />
  43. </LinearLayout>
  44. <LinearLayout
  45. android:id="@+id/tab2"
  46. android:layout_width="match_parent"
  47. android:layout_height="match_parent"
  48. >
  49. </LinearLayout>
  50. <LinearLayout
  51. android:id="@+id/tab3"
  52. android:layout_width="match_parent"
  53. android:layout_height="match_parent"
  54. >
  55. </LinearLayout>
  56. </FrameLayout>
  57. </LinearLayout>
  58. </TabHost>
  59. </LinearLayout>
2.list的條目布局list_item.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. android:gravity="center_vertical"
  6. android:orientation="horizontal" >
  7. <ImageView
  8. android:id="@+id/imageView_item"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:layout_marginLeft="5dp"
  12. android:src="@drawable/icon" />
  13. <TextView
  14. android:id="@+id/textView_item"
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:layout_marginLeft="10dp"
  18. android:textColor="#FFFFFF"
  19. />
  20. </LinearLayout>
3. 刷新布局refresh.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content" >
  5. <RelativeLayout
  6. android:id="@+id/head_contentLayout"
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:paddingLeft="30dp" >
  10. <FrameLayout
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"
  13. android:layout_alignParentLeft="true"
  14. android:layout_centerVertical="true" >
  15. <ImageView
  16. android:id="@+id/head_arrowImageView"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:layout_gravity="center"
  20. android:src="@drawable/down" />
  21. <ProgressBar
  22. android:id="@+id/head_progressBar"
  23. style="?android:attr/progressBarStyleSmall"
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"
  26. android:layout_gravity="center"
  27. android:visibility="gone" />
  28. </FrameLayout>
  29. <LinearLayout
  30. android:layout_width="wrap_content"
  31. android:layout_height="wrap_content"
  32. android:layout_centerHorizontal="true"
  33. android:gravity="center_horizontal"
  34. android:orientation="vertical" >
  35. <TextView
  36. android:id="@+id/head_tipsTextView"
  37. android:layout_width="wrap_content"
  38. android:layout_height="wrap_content"
  39. android:text="下拉可以刷新"
  40. android:textSize="15dp" />
  41. <TextView
  42. android:id="@+id/head_lastUpdatedTextView"
  43. android:layout_width="wrap_content"
  44. android:layout_height="wrap_content"
  45. android:text="上次更新時間:"
  46. android:textSize="12dp" />
  47. </LinearLayout>
  48. </RelativeLayout>
  49. </LinearLayout>
4.看看主活動實現的過程PullrefreshDemoActivity.xml
  1. package com.wang;
  2. import java.util.LinkedList;
  3. import com.wang.MyListView.OnRefreshListener;
  4. import android.app.Activity;
  5. import android.content.res.Resources;
  6. import android.os.AsyncTask;
  7. import android.os.Bundle;
  8. import android.view.LayoutInflater;
  9. import android.view.View;
  10. import android.view.ViewGroup;
  11. import android.view.Window;
  12. import android.view.WindowManager;
  13. import android.widget.BaseAdapter;
  14. import android.widget.TabHost;
  15. import android.widget.TextView;
  16. public class PullrefreshDemoActivity extends Activity {
  17. private LinkedList<String> data;
  18. private BaseAdapter adapter;
  19. public void onCreate(Bundle savedInstanceState) {
  20. // 去除標題欄
  21. requestWindowFeature(Window.FEATURE_NO_TITLE);
  22. // 設置全屏,取消狀態欄
  23. this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  24. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.main);
  27. TabHost tabhost=(TabHost)findViewById(R.id.tabhost);
  28. tabhost.setup();
  29. tabhost.addTab(tabhost.newTabSpec("tab1").setIndicator("好友動態").setContent(R.id.tab1));
  30. tabhost.addTab(tabhost.newTabSpec("tab2").setIndicator("我的動態").setContent(R.id.tab2));
  31. tabhost.addTab(tabhost.newTabSpec("tab3").setIndicator("我的應用").setContent(R.id.tab3));
  32. data = new LinkedList<String>();
  33. for (int i = 30; i < 40; i++) {
  34. // 輸出list——item上的數據
  35. data.add(String.valueOf("暑假第" + i + "天,我們一直很宅,想家ing ..."));
  36. }
  37. final MyListView listView = (MyListView) findViewById(R.id.listView);
  38. adapter = new BaseAdapter() {
  39. // 得到一個視圖,顯示在指定位置上的數據在數據集,可以創建一個視圖從XML布局文件
  40. public View getView(int position, View convertView, ViewGroup parent) {
  41. // 上下文全局應用程序對象
  42. convertView = LayoutInflater.from(getApplicationContext())
  43. .inflate(R.layout.list_item, null);
  44. // 實例化組件
  45. TextView textView = (TextView) convertView
  46. .findViewById(R.id.textView_item);
  47. // 設置文本本內容
  48. textView.setText(data.get(position));
  49. return convertView;
  50. }
  51. // 得到行相關聯id列表中指定的位置。
  52. public long getItemId(int position) {
  53. return position;
  54. }
  55. // 獲得相關的數據項中的指定位置的數據集
  56. public Object getItem(int position) {
  57. return data.get(position);
  58. }
  59. // 獲得項目在數據集適配器的個數。
  60. public int getCount() {
  61. return data.size();
  62. }
  63. };
  64. listView.setAdapter(adapter);
  65. listView.setonRefreshListener(new OnRefreshListener() {
  66. public void onRefresh() {
  67. new AsyncTask<Void, Void, Void>() {
  68. // ...b表示多個參數
  69. protected Void doInBackground(Void... params) {
  70. try {
  71. //
  72. Thread.sleep(1000);
  73. } catch (Exception e) {
  74. e.printStackTrace();
  75. }
  76. // 增加一條數據到list中
  77. data.addFirst("刷新後內容:每天都是新的一天!!!,親!要努力奮斗哦!!!");
  78. return null;
  79. }
  80. protected void onPostExecute(Void result) {
  81. adapter.notifyDataSetChanged();
  82. listView.onRefreshComplete();
  83. }
  84. }.execute(null);
  85. }
  86. });
  87. }
  88. }
5.接著是列表實現個過程MyListView.xml
  1. package com.wang;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Date;
  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. public class MyListView extends ListView implements OnScrollListener {
  22. private static final String TAG = "listview";
  23. private final static int RELEASE_To_REFRESH = 0;
  24. private final static int PULL_To_REFRESH = 1;
  25. private final static int REFRESHING = 2;
  26. private final static int DONE = 3;
  27. private final static int LOADING = 4;
  28. // 實際的padding的距離與界面上偏移距離的比例
  29. private final static int RATIO = 3;
  30. private LayoutInflater inflater;
  31. private LinearLayout headView;
  32. private TextView tipsTextview;
  33. private TextView lastUpdatedTextView;
  34. private ImageView arrowImageView;
  35. private ProgressBar progressBar;
  36. private RotateAnimation animation;
  37. private RotateAnimation reverseAnimation;
  38. // 用於保證startY的值在一個完整的touch事件中只被記錄一次
  39. private boolean isRecored;
  40. private int headContentWidth;
  41. private int headContentHeight;
  42. private int startY;
  43. private int firstItemIndex;
  44. private int state;
  45. private boolean isBack;
  46. private OnRefreshListener refreshListener;
  47. private boolean isRefreshable;
  48. public MyListView(Context context) {
  49. super(context);
  50. // 調用下面初始化的函數
  51. init(context);
  52. }
  53. public MyListView(Context context, AttributeSet attrs) {
  54. super(context, attrs);
  55. // 調用下面初始化的函數
  56. init(context);
  57. }
  58. private void init(Context context) {
  59. // 獲得LayoutInflater從給定的上下文。
  60. inflater = LayoutInflater.from(context);
  61. // 實例化布局XML文件轉換成相應的視圖對象。
  62. headView = (LinearLayout) inflater.inflate(R.layout.refresh, null);
  63. arrowImageView = (ImageView) headView
  64. .findViewById(R.id.head_arrowImageView);
  65. // 設置最小寬度 和高度
  66. arrowImageView.setMinimumWidth(70);
  67. arrowImageView.setMinimumHeight(50);
  68. // 實例化布局XML文件轉換成相應的視圖對象。
  69. progressBar = (ProgressBar) headView
  70. .findViewById(R.id.head_progressBar);
  71. tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
  72. lastUpdatedTextView = (TextView) headView
  73. .findViewById(R.id.head_lastUpdatedTextView);
  74. // 調用下拉刷新的方法
  75. measureView(headView);
  76. // d得到原始高度和寬度
  77. headContentHeight = headView.getMeasuredHeight();
  78. headContentWidth = headView.getMeasuredWidth();
  79. // 設置填充。視圖可能添加的空間要求顯示滾動條,這取決於風格和知名度的滾動條
  80. headView.setPadding(0, -1 * headContentHeight, 0, 0);
  81. headView.invalidate();
  82. // 標簽用來識別一個日志消息的來源。標識類或活動日志調用發生
  83. Log.v("size", "width:" + headContentWidth + " height:"
  84. + headContentHeight);
  85. // 添加一個固定視圖出現在列表的頂部
  86. addHeaderView(headView, null, false);
  87. // 設置監聽事件
  88. setOnScrollListener(this);
  89. // 動畫效果實現下拉和松開時候圖片的 180度 旋轉 注意0, -180,和他是有區別的 -180, 0,
  90. animation = new RotateAnimation(0, -180,
  91. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
  92. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  93. // 設置加速度曲線為這個動畫。默認值為一個線性插值。
  94. animation.setInterpolator(new LinearInterpolator());
  95. animation.setDuration(300);
  96. // 如果fillAfter是真的,轉換,該動畫執行完成時將會持續下去
  97. animation.setFillAfter(true);
  98. reverseAnimation = new RotateAnimation(-180, 0,
  99. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
  100. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  101. // 設置加速度曲線為這個動畫。默認值為一個線性插值。
  102. reverseAnimation.setInterpolator(new LinearInterpolator());
  103. reverseAnimation.setDuration(300);
  104. // 如果fillAfter是真的,轉換,該動畫執行完成時將會持續下去
  105. reverseAnimation.setFillAfter(true);
  106. // 設置狀態
  107. state = DONE;
  108. // 設置不可刷新狀態
  109. isRefreshable = false;
  110. }
  111. // 回調方法時要調用的列表或網格已經滾動。這將完成之後調用的滾動方法
  112. public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
  113. int arg3) {
  114. firstItemIndex = firstVisiableItem;
  115. }
  116. /*
  117. * 回調方法調用而列表視圖或網格視圖被滾動。 如果這個視圖被滾動,將調用此方法在接下來的一局畫卷的呈現 *
  118. */
  119. public void onScrollStateChanged(AbsListView arg0, int arg1) {
  120. }
  121. // 觸摸事件監聽
  122. public boolean onTouchEvent(MotionEvent event) {
  123. // 判斷是否可以刷新
  124. if (isRefreshable) {
  125. // 根據動作相應不同的方法
  126. switch (event.getAction()) {
  127. // 當按住屏幕向下拉屏幕的時候
  128. case MotionEvent.ACTION_DOWN:
  129. if (firstItemIndex == 0 && !isRecored) {
  130. isRecored = true;
  131. startY = (int) event.getY();
  132. Log.v(TAG, "在下拉的時候記錄當前位置‘");
  133. }
  134. break;
  135. // 當按住屏幕向上松屏幕的時候
  136. case MotionEvent.ACTION_UP:
  137. if (state != REFRESHING && state != LOADING) {
  138. if (state == DONE) {
  139. }
  140. if (state == PULL_To_REFRESH) {
  141. state = DONE;
  142. changeHeaderViewByState();
  143. Log.v(TAG, "由下拉刷新狀態,到done狀態");
  144. }
  145. if (state == RELEASE_To_REFRESH) {
  146. state = REFRESHING;
  147. changeHeaderViewByState();
  148. onRefresh();
  149. Log.v(TAG, "由松開刷新狀態,到done狀態");
  150. }
  151. }
  152. isRecored = false;
  153. isBack = false;
  154. break;
  155. // 當按住屏幕移動時候
  156. case MotionEvent.ACTION_MOVE:
  157. int tempY = (int) event.getY();
  158. if (!isRecored && firstItemIndex == 0) {
  159. Log.v(TAG, "在move時候記錄下位置");
  160. isRecored = true;
  161. startY = tempY;
  162. }
  163. if (state != REFRESHING && isRecored && state != LOADING) {
  164. /***
  165. * , 當前的位置一直是在head,否則如果當列表超出屏幕的話, 當在上推的時候,列表會同時進行滾動
  166. */
  167. // 可以松手去刷新了
  168. if (state == RELEASE_To_REFRESH) {
  169. setSelection(0);
  170. // 往上推了,推到了屏幕足夠掩蓋head的程度,但是還沒有推到全部掩蓋的地步
  171. if (((tempY - startY) / RATIO < headContentHeight)
  172. && (tempY - startY) > 0) {
  173. state = PULL_To_REFRESH;
  174. changeHeaderViewByState();
  175. Log.v(TAG, "由松開刷新狀態轉變到下拉刷新狀態");
  176. }
  177. // 一下子推到頂了
  178. else if (tempY - startY <= 0) {
  179. state = DONE;
  180. // 調用改變時候的方法,更新UI
  181. changeHeaderViewByState();
  182. Log.v(TAG, "由松開刷新狀態轉變到done狀態");
  183. } else {
  184. }
  185. }
  186. // 還沒有到達顯示松開刷新的時候
  187. if (state == PULL_To_REFRESH) {
  188. setSelection(0);
  189. // 下拉到可以進入RELEASE_TO_REFRESH的狀態
  190. if ((tempY - startY) / RATIO >= headContentHeight) {
  191. state = RELEASE_To_REFRESH;
  192. isBack = true;
  193. // 調用改變時候的方法,更新UI
  194. changeHeaderViewByState();
  195. Log.v(TAG, "由done或者下拉刷新狀態轉變到松開刷新");
  196. }
  197. // 上推到頂了
  198. else if (tempY - startY <= 0) {
  199. state = DONE;
  200. // 調用改變時候的方法,更新UI
  201. changeHeaderViewByState();
  202. Log.v(TAG, "由DOne或者下拉刷新狀態轉變到done狀態");
  203. }
  204. }
  205. // done狀態下
  206. if (state == DONE) {
  207. if (tempY - startY > 0) {
  208. state = PULL_To_REFRESH;
  209. // 調用改變時候的方法,更新UI
  210. changeHeaderViewByState();
  211. }
  212. }
  213. // 更新headView的size
  214. if (state == PULL_To_REFRESH) {
  215. headView.setPadding(0, -1 * headContentHeight
  216. + (tempY - startY) / RATIO, 0, 0);
  217. }
  218. // 更新headView的paddingTop
  219. if (state == RELEASE_To_REFRESH) {
  220. headView.setPadding(0, (tempY - startY) / RATIO
  221. - headContentHeight, 0, 0);
  222. }
  223. }
  224. break;
  225. }
  226. }
  227. return super.onTouchEvent(event);
  228. }
  229. // 當狀態改變時候,調用該方法,以更新界面
  230. private void changeHeaderViewByState() {
  231. // 根據當前的狀態進行判斷
  232. switch (state) {
  233. // 下拉時候,松開既可刷新
  234. case RELEASE_To_REFRESH:
  235. // 設置視圖 VISIBLE 可見 ,GONE 不可見
  236. arrowImageView.setVisibility(View.VISIBLE);
  237. progressBar.setVisibility(View.GONE);
  238. tipsTextview.setVisibility(View.VISIBLE);
  239. lastUpdatedTextView.setVisibility(View.VISIBLE);
  240. // 現在開始指定的動畫。
  241. arrowImageView.clearAnimation();
  242. arrowImageView.startAnimation(animation);
  243. tipsTextview.setText("松開既可刷新");
  244. Log.v(TAG, "當前狀態,松開即可刷新");
  245. break;
  246. // 開始時候,下拉刷新
  247. case PULL_To_REFRESH:
  248. // 設置視圖 VISIBLE 可見 ,GONE 不可見
  249. progressBar.setVisibility(View.GONE);
  250. tipsTextview.setVisibility(View.VISIBLE);
  251. lastUpdatedTextView.setVisibility(View.VISIBLE);
  252. // 現在開始指定的動畫。
  253. arrowImageView.clearAnimation();
  254. arrowImageView.setVisibility(View.VISIBLE);
  255. if (isBack) {
  256. isBack = false;
  257. // 現在開始指定的動畫。
  258. arrowImageView.clearAnimation();
  259. arrowImageView.startAnimation(reverseAnimation);
  260. tipsTextview.setText("下拉刷新");
  261. } else {
  262. tipsTextview.setText("下拉刷新");
  263. }
  264. Log.v(TAG, "當前狀態,下拉刷新");
  265. break;
  266. case REFRESHING:
  267. headView.setPadding(0, 0, 0, 0);
  268. // 設置視圖 VISIBLE 可見 ,GONE 不可見
  269. progressBar.setVisibility(View.VISIBLE);
  270. // 現在開始指定的動畫。
  271. arrowImageView.clearAnimation();
  272. arrowImageView.setVisibility(View.GONE);
  273. tipsTextview.setText("正在刷新...");
  274. lastUpdatedTextView.setVisibility(View.VISIBLE);
  275. Log.v(TAG, "當前狀態,正在刷新...");
  276. break;
  277. case DONE:
  278. // 設置填充。視圖可能添加的空間要求顯示滾動條
  279. headView.setPadding(0, -1 * headContentHeight, 0, 0);
  280. // 設置視圖 VISIBLE 可見 ,GONE 不可見
  281. progressBar.setVisibility(View.GONE);
  282. // 現在開始指定的動畫。
  283. arrowImageView.clearAnimation();
  284. arrowImageView.setImageResource(R.drawable.down);
  285. tipsTextview.setText("下拉刷新");
  286. lastUpdatedTextView.setVisibility(View.VISIBLE);
  287. Log.v(TAG, "當前狀態");
  288. break;
  289. }
  290. }
  291. public void setonRefreshListener(OnRefreshListener refreshListener) {
  292. this.refreshListener = refreshListener;
  293. isRefreshable = true;
  294. }
  295. public interface OnRefreshListener {
  296. public void onRefresh();
  297. }
  298. // 設置更新時間
  299. public void onRefreshComplete() {
  300. state = DONE;
  301. //
  302. SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
  303. String date = format.format(new Date());
  304. lastUpdatedTextView.setText("最近更新:" + date);
  305. changeHeaderViewByState();
  306. }
  307. private void onRefresh() {
  308. if (refreshListener != null) {
  309. refreshListener.onRefresh();
  310. }
  311. }
  312. // 下拉刷新的
  313. private void measureView(View child) {
  314. // v這組布局參數寬度和高度
  315. ViewGroup.LayoutParams p = child.getLayoutParams();
  316. if (p == null) {
  317. // 創建一個新組布局參數指定的寬度(填充)和高度(包裹)。
  318. p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
  319. ViewGroup.LayoutParams.WRAP_CONTENT);
  320. }
  321. // d得到childWidthSpec(高度或寬度)的子視圖
  322. int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
  323. int lpHeight = p.height;
  324. int childHeightSpec;
  325. if (lpHeight > 0) {
  326. // 創建一個測量規范基於所提供的大小和模式
  327. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
  328. MeasureSpec.EXACTLY);
  329. } else {
  330. childHeightSpec = MeasureSpec.makeMeasureSpec(0,
  331. MeasureSpec.UNSPECIFIED);
  332. }
  333. // 找出一個視圖應該多大。父供應約束信息在寬度和高度參數
  334. child.measure(childWidthSpec, childHeightSpec);
  335. }
  336. public void setAdapter(BaseAdapter adapter) {
  337. // 設置最近刷新的時間
  338. SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
  339. String date = format.format(new Date());
  340. lastUpdatedTextView.setText("最近更新:" + date);
  341. super.setAdapter(adapter);
  342. }
  343. }

6.接著就可以看到運行結果了,運行結果如下:

Copyright © Linux教程網 All Rights Reserved