andriod listview下拉重新整理、彈出效果

來源:互聯網
上載者:User


以前喜歡看小說的時候,在手機上下載了一些讀書軟體,軟體中有個添加書籤的功能很炫;微博中重新整理資訊列表的方式也很酷。


現在以listview下拉重新整理列表為例,說明如何添加書籤,如何通過下拉、上拉方式重新整理listview。

先貼上:

在ListView中有addHeaderView()和addFooterView()兩個方法,可以在listview的頂部和底部放置兩個不同或者相同的自訂view,作為ListView的item元素;要添加這兩個view需要在ListView.setAdapter()方法之前使用才可。頂部和底部布局搞定之後,就需要怎麼實現下拉重新整理功能了,每個View對象都具有setPadding()方法來控制view對象本身與四周其他控制項或者螢幕邊框的距離,在這裡需要用到的是與螢幕頂部的距離變化,來控制頂部view的顯示效果;在頂部view中定義了一個"箭頭"控制項,用來標識方向,使用了RotateAnimation動畫控制"箭頭"的旋轉、指向。書籤的添加,也是類似的,可以在定義好的布局檔案頂部中增加一個view,在需要添加書籤的時候,通過setPadding()來控制該view。

首先需要建立一個主ListView類布局檔案activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_height="match_parent"    android:layout_width="match_parent"    tools:context=".MainActivity" >    <ListView         android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:cacheColorHint="#00000000"        android:divider="@android:color/transparent"/></RelativeLayout>
布局檔案中只顯示了一個ListView控制項,設定ListView滑動時背景為透明,Item之前線條為透明;之後定義頂部View檔案head.xml

<?xml version="1.0" encoding="utf-8"?><!-- ListView的頭部 --><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content">    <!-- 內容 -->    <RelativeLayout        android:id="@+id/head_contentLayout"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:paddingLeft="30sp" >        <!-- 箭頭映像、進度條 -->        <FrameLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_centerVertical="true" >            <!-- 箭頭 -->            <ImageView                android:id="@+id/head_arrowImageView"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_gravity="center"                android:src="@drawable/ic_pulltorefresh_arrow" />            <!-- 進度條 -->            <ProgressBar                android:id="@+id/head_progressBar"                style="?android:attr/progressBarStyleSmall"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_gravity="center"                android:visibility="gone"                 />        </FrameLayout>        <!-- 提示、最新動向 -->        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerHorizontal="true"            android:gravity="center_horizontal"            android:orientation="vertical" >            <!-- 提示 -->            <TextView                android:id="@+id/head_tipsTextView"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="下拉重新整理"                android:textColor="#000000"                android:textSize="20sp" />            <!-- 最新動向 -->            <TextView                android:id="@+id/head_lastUpdatedTextView"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="上次更新"                android:textColor="#ff0000"                android:textSize="10sp" />        </LinearLayout>    </RelativeLayout></LinearLayout>
該布局中定義了"箭頭",重新整理提示,更新時間,進度條等內容,可按實際需求修改;之後定義底部View檔案bottom.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:gravity="center_horizontal"    android:layout_height="fill_parent"    android:layout_width="fill_parent"    android:orientation="vertical"    android:paddingBottom="13sp"    android:paddingTop="13sp" >    <TextView        android:gravity="center_horizontal"        android:id="@+id/more_id"        android:layout_height="wrap_content"        android:layout_width="fill_parent"        android:text="查看更多..."        android:textSize="25sp" />    <LinearLayout        android:id="@+id/load_id"        android:layout_height="wrap_content"        android:layout_width="wrap_content"        android:orientation="horizontal"        android:visibility="gone" >        <ProgressBar            android:layout_gravity="center_horizontal"            android:layout_height="wrap_content"            android:layout_width="match_parent" />        <TextView            android:gravity="center_vertical"            android:layout_height="fill_parent"            android:layout_marginLeft="10sp"            android:layout_width="wrap_content"            android:text="正在載入..."            android:textSize="20sp" />    </LinearLayout></LinearLayout>
現在通過MainActivity.java將頂部檔案、主檔案、底部檔案綁定在一起實現下來重新整理、彈出效果等諸多功能

package com.example.pulldownrefresh;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.LayoutInflater;import android.view.Menu;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.View.MeasureSpec;import android.view.View.OnTouchListener;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.view.animation.TranslateAnimation;import android.widget.Button;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.SimpleAdapter;import android.widget.TextView;/** *  * @author tr * @time 2014-2-28 * @description 下拉重新整理列表 */public class MainActivity extends Activity  implements OnTouchListener{/**listview執行個體對象*/private ListView mListView;private int headViewWidth, headViewHeight;// 實際的padding的距離與介面上位移距離的比例private final static int RATIO = 3;/**旋轉動畫*/private RotateAnimation animation,reverseAnimation;/**旋轉對象*/private ImageView head_arrowImageView;private float startY;private View headView;private SimpleAdapter adapter;    private List<Map<String,Object>> data;    private static final String TAG = "listview";private final static int RELEASE_To_REFRESH = 0;private final static int PULL_To_REFRESH = 1;private final static int REFRESHING = 2;private final static int DONE = 3;private final static int LOADING = 4;// 用於保證startY的值在一個完整的touch事件中只被記錄一次private boolean isRecored;private int firstItemIndex;private int state;private boolean isBack;private TextView tipsTextview;private TextView lastUpdatedTextView;private ProgressBar progressBar;    //查看更多    private TextView moreTextView;    //正在載入進度條    private LinearLayout loadProgressBar;    //分頁載入的資料的數量    private int pageSize=10;    private final int pageType=1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mListView = (ListView) findViewById(R.id.listview);mListView.setOnTouchListener(this);LayoutInflater layoutInflater = getLayoutInflater();animation = new RotateAnimation(0, 180,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);animation.setFillAfter(true);animation.setDuration(200);animation.setInterpolator(new LinearInterpolator());reverseAnimation = new RotateAnimation(180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);reverseAnimation.setFillAfter(true);reverseAnimation.setDuration(200);reverseAnimation.setInterpolator(new LinearInterpolator());headView = layoutInflater.from(this).inflate(R.layout.head, null);progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);data = initValue(1,15);adapter = new SimpleAdapter(this, data, android.R.layout.simple_expandable_list_item_2, new String[] {"title","text"}, new int[] {android.R.id.text1,android.R.id.text2});head_arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);head_arrowImageView.setMinimumHeight(50);head_arrowImageView.setMinimumWidth(70);measureView(headView);addPageMore();headViewWidth = headView.getMeasuredWidth();headViewHeight = headView.getMeasuredHeight();headView.setPadding(0, -1*headViewHeight, 0, 0);headView.invalidate();mListView.addHeaderView(headView, null, false);mListView.setAdapter(adapter);}    /**     * 在ListView中添加"載入更多"     */    private void addPageMore(){        View view=LayoutInflater.from(this).inflate(R.layout.bottom, null);        moreTextView=(TextView)view.findViewById(R.id.more_id);        loadProgressBar=(LinearLayout)view.findViewById(R.id.load_id);        moreTextView.setOnClickListener(new Button.OnClickListener() {            @Override            public void onClick(View v) {                //隱藏"載入更多"                moreTextView.setVisibility(View.GONE);                //顯示進度條                loadProgressBar.setVisibility(View.VISIBLE);    new refreshTask().execute();            }        });        mListView.addFooterView(view);    }        /**     * 載入下一頁的資料     * @param pageStart     * @param pageSize     */    private void chageListView(int pageStart,int pageSize){        List<Map<String,Object>> data=initValue(pageStart,pageSize);        for (Map<String, Object> map : data) {            this.data.add(map);        }        data=null;    }// 此方法直接照搬自網路上的一個下拉重新整理的demo,此處是“估計”headView的width以及heightprivate void measureView(View child) {ViewGroup.LayoutParams p = child.getLayoutParams();if (p == null) {p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);}int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);int lpHeight = p.height;int childHeightSpec;if (lpHeight > 0) {childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);} else {childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}child.measure(childWidthSpec, childHeightSpec);}    /**     * 類比資料分頁載入,     * @param pageStart  起始數     * @param pageSize   每頁顯示數目     * @return     */    public static List<Map<String,Object>> initValue(int pageStart,int pageSize){        Map<String,Object> map;        List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();        for(int i=0;i<pageSize;i++){            map=new HashMap<String,Object>();            map.put("text", "定義listview列表");            map.put("title", "第"+pageStart+"項");            ++pageStart;            list.add(map);        }        return list;    }@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (firstItemIndex == 0 && !isRecored) {isRecored = true;startY = (int) event.getY();Log.v(TAG, "在down時候記錄當前位置‘"+startY);}break;case MotionEvent.ACTION_UP:if (state != REFRESHING && state != LOADING) {if (state == DONE) {// 什麼都不做}if (state == PULL_To_REFRESH) {state = DONE;changeHeaderViewByState();Log.v(TAG, "由下拉重新整理狀態,到done狀態");}if (state == RELEASE_To_REFRESH) {state = REFRESHING;changeHeaderViewByState();Log.v(TAG, "由鬆開重新整理狀態,到done狀態");}}isRecored = false;isBack = false;break;case MotionEvent.ACTION_MOVE:int tempY = (int) event.getY();if (!isRecored && firstItemIndex == 0) {Log.v(TAG, "在move時候記錄下位置"+tempY);isRecored = true;startY = tempY;}if (state != REFRESHING && isRecored && state != LOADING) {// 保證在設定padding的過程中,當前的位置一直是在head,否則如果當列表超出螢幕的話,當在上推的時候,列表會同時進行滾動// 可以鬆手去重新整理了if (state == RELEASE_To_REFRESH) {mListView.setSelection(0);// 往上推了,推到了螢幕足夠掩蓋head的程度,但是還沒有推到全部掩蓋的地步if (((tempY - startY) / RATIO < headViewHeight)&& (tempY - startY) > 0) {state = PULL_To_REFRESH;changeHeaderViewByState();Log.v(TAG, "由鬆開重新整理狀態轉變到下拉重新整理狀態");}// 一下子推到頂了else if (tempY - startY <= 0) {state = DONE;changeHeaderViewByState();Log.v(TAG, "由鬆開重新整理狀態轉變到done狀態");}// 往下拉了,或者還沒有上推到螢幕頂部掩蓋head的地步else {// 不用進行特別的操作,只用更新paddingTop的值就行了}}// 還沒有到達顯示鬆開重新整理的時候,DONE或者是PULL_To_REFRESH狀態if (state == PULL_To_REFRESH) {// 下拉到可以進入RELEASE_TO_REFRESH的狀態if ((tempY - startY) / RATIO >= headViewHeight) {state = RELEASE_To_REFRESH;isBack = true;changeHeaderViewByState();Log.v(TAG, "由done或者下拉重新整理狀態轉變到鬆開重新整理");}// 上推到頂了else if (tempY - startY <= 0) {state = DONE;changeHeaderViewByState();Log.v(TAG, "由DOne或者下拉重新整理狀態轉變到done狀態");}}// done狀態下if (state == DONE) {if (tempY - startY > 0) {state = PULL_To_REFRESH;changeHeaderViewByState();}}// 更新headView的sizeif (state == PULL_To_REFRESH) {headView.setPadding(0, (int)(-1 * headViewHeight+ (tempY - startY) / RATIO), 0, 0);System.out.println("top_distance0:"+(-1 * headViewHeight + (tempY - startY) / RATIO));}// 更新headView的paddingTopif (state == RELEASE_To_REFRESH) {headView.setPadding(0, (int)((tempY - startY) / RATIO- headViewHeight), 0, 0);}}break;}return false;}// 當狀態改變時候,調用該方法,以更新介面private void changeHeaderViewByState() {switch (state) {case RELEASE_To_REFRESH:head_arrowImageView.setVisibility(View.VISIBLE);progressBar.setVisibility(View.GONE);tipsTextview.setVisibility(View.VISIBLE);lastUpdatedTextView.setVisibility(View.VISIBLE);head_arrowImageView.clearAnimation();head_arrowImageView.startAnimation(animation);tipsTextview.setText("鬆開重新整理");Log.v(TAG, "目前狀態,鬆開重新整理");break;case PULL_To_REFRESH:progressBar.setVisibility(View.GONE);tipsTextview.setVisibility(View.VISIBLE);lastUpdatedTextView.setVisibility(View.VISIBLE);head_arrowImageView.clearAnimation();head_arrowImageView.setVisibility(View.VISIBLE);// 是由RELEASE_To_REFRESH狀態轉變來的if (isBack) {isBack = false;head_arrowImageView.clearAnimation();head_arrowImageView.startAnimation(reverseAnimation);tipsTextview.setText("下拉重新整理");} else {tipsTextview.setText("下拉重新整理");}Log.v(TAG, "目前狀態,下拉重新整理");break;case REFRESHING:headView.setPadding(0, 0, 0, 0);progressBar.setVisibility(View.VISIBLE);head_arrowImageView.clearAnimation();head_arrowImageView.setVisibility(View.GONE);tipsTextview.setText("正在重新整理...");lastUpdatedTextView.setVisibility(View.VISIBLE);lastUpdatedTextView.setVisibility(View.GONE);Log.v(TAG, "目前狀態,正在重新整理...");new refreshTask().execute();break;case DONE:headView.setPadding(0, -1 * headViewHeight, 0, 0);progressBar.setVisibility(View.GONE);head_arrowImageView.clearAnimation();head_arrowImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow);tipsTextview.setText("下拉重新整理");lastUpdatedTextView.setVisibility(View.VISIBLE);Log.v(TAG, "目前狀態,done");break;}}class refreshTask extends AsyncTask<Void, Void, Void>{@Overrideprotected Void doInBackground(Void... params) {// TODO Auto-generated method stub//需要在載入過程中做的事情try{Thread.sleep(3000);}catch(Exception e){e.printStackTrace();}            //載入類比資料:下一頁資料, 在正常情況下,上面的休眠是不需要,直接使用下面這句代碼載入相關資料            chageListView(data.size()+1,pageSize);return null;}@Overrideprotected void onProgressUpdate(Void... values) {// TODO Auto-generated method stubsuper.onProgressUpdate(values);//進度更新}@Overrideprotected void onPostExecute(Void result) {// TODO Auto-generated method stubsuper.onPostExecute(result);//載入完成之後,應該做什麼樣的操作            //通知適配器,發現改變操作            adapter.notifyDataSetChanged();onRefreshComplete();            //再次顯示"載入更多"            moreTextView.setVisibility(View.VISIBLE);            //再次隱藏“進度條”            loadProgressBar.setVisibility(View.GONE);}}/**重新整理完成,還原介面各種狀態,修改更新時間*/public void onRefreshComplete() {state = DONE;//更新最新重新整理時間lastUpdatedTextView.setText("最新動向:" + new Date().toLocaleString());changeHeaderViewByState();}}
書籤功能,可按照類似原理開發,之後有時間將提供源碼。

原始碼,點擊下載


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.