zoukankan      html  css  js  c++  java
  • 【ListView】自定义控件:下拉刷新

    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
        
        <com.laohuai.appdemo.customui.ui.MyListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/listView" />
        
    </LinearLayout>
    View Code

    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="30dp" >
    
            <!-- 箭头图像、进度条 -->
            <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/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="@color/white"
                    android:textSize="20sp" />
    
                <!-- 最近更新 -->
                <TextView
                    android:id="@+id/head_lastUpdatedTextView"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="上次更新"
                    android:textColor="@color/gold"
                    android:textSize="10sp" />
            </LinearLayout>
        </RelativeLayout>
    
    </LinearLayout>
    View Code

    MyListView.java  自定义控件

    package com.laohuai.appdemo.customui.ui;
    
    import java.util.Date;
    
    import com.laohuai.appdemo.customui.R;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.LinearInterpolator;
    import android.view.animation.RotateAnimation;
    import android.widget.AbsListView;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    public class MyListView extends ListView implements OnScrollListener {
    
        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;
        // 实际的padding的距离与界面上偏移距离的比例
        private final static int RATIO = 3;
        private LayoutInflater inflater;
        private LinearLayout headView;
        private TextView tipsTextview;
        private TextView lastUpdatedTextView;
        private ImageView arrowImageView;
        private ProgressBar progressBar;
        private RotateAnimation animation;
        private RotateAnimation reverseAnimation;
        // 用于保证startY的值在一个完整的touch事件中只被记录一次
        private boolean isRecored;
        private int headContentWidth;
        private int headContentHeight;
        private int startY;
        private int firstItemIndex;
        private int state;
        private boolean isBack;
        private OnRefreshListener refreshListener;
        private boolean isRefreshable;
    
        public MyListView(Context context) {
            super(context);
            init(context);
        }
    
        public MyListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        private void init(Context context) {
            setCacheColorHint(context.getResources().getColor(R.color.transparent));
            inflater = LayoutInflater.from(context);
           
            headView = (LinearLayout) inflater.inflate(R.layout.head, null);
    
            arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);
            arrowImageView.setMinimumWidth(70);
            arrowImageView.setMinimumHeight(50);
            progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);
            tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
            lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);
    
            measureView(headView);
            headContentHeight = headView.getMeasuredHeight();
            headContentWidth = headView.getMeasuredWidth();
    
            headView.setPadding(0, -1 * headContentHeight, 0, 0);
            headView.invalidate();
    
            Log.v("size", "" + headContentWidth + " height:" + headContentHeight);
    
            addHeaderView(headView, null, false);
            setOnScrollListener(this);
    
            animation = new RotateAnimation(0, -180,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            animation.setInterpolator(new LinearInterpolator());
            animation.setDuration(250);
            animation.setFillAfter(true);
    
            reverseAnimation = new RotateAnimation(-180, 0,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            reverseAnimation.setInterpolator(new LinearInterpolator());
            reverseAnimation.setDuration(200);
            reverseAnimation.setFillAfter(true);
    
            state = DONE;
            isRefreshable = false;
        }
    
        public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
                int arg3) {
            firstItemIndex = firstVisiableItem;
        }
    
        public void onScrollStateChanged(AbsListView arg0, int arg1) { }
    
        public boolean onTouchEvent(MotionEvent event) {
            if (isRefreshable) {
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (firstItemIndex == 0 && !isRecored) {
                        isRecored = true;
                        startY = (int) event.getY();
                        Log.v(TAG, "在down时候记录当前位置‘");
                    }
                    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();
                            onRefresh();
    
                            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时候记录下位置");
                        isRecored = true;
                        startY = tempY;
                    }
    
                    if (state != REFRESHING && isRecored && state != LOADING) {
    
                        // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
    
                        // 可以松手去刷新了
                        if (state == RELEASE_To_REFRESH) {
    
                            setSelection(0);
    
                            // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
                            if (((tempY - startY) / RATIO < headContentHeight)
                                    && (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) {
    
                            setSelection(0);
    
                            // 下拉到可以进入RELEASE_TO_REFRESH的状态
                            if ((tempY - startY) / RATIO >= headContentHeight) {
                                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的size
                        if (state == PULL_To_REFRESH) {
                            headView.setPadding(0, -1 * headContentHeight
                                    + (tempY - startY) / RATIO, 0, 0);
    
                        }
                        // 更新headView的paddingTop
                        if (state == RELEASE_To_REFRESH) {
                            headView.setPadding(0, (tempY - startY) / RATIO
                                    - headContentHeight, 0, 0);
                        }
                    }
                    break;
                }
            }
            return super.onTouchEvent(event);
        }
    
        /** 当状态改变时候,调用该方法,以更新界面 */ 
        private void changeHeaderViewByState() {
            switch (state) {
            case RELEASE_To_REFRESH:
                arrowImageView.setVisibility(View.VISIBLE);
                progressBar.setVisibility(View.GONE);
                tipsTextview.setVisibility(View.VISIBLE);
                lastUpdatedTextView.setVisibility(View.VISIBLE);
    
                arrowImageView.clearAnimation();
                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);
                arrowImageView.clearAnimation();
                arrowImageView.setVisibility(View.VISIBLE);
                // 是由RELEASE_To_REFRESH状态转变来的
                if (isBack) {
                    isBack = false;
                    arrowImageView.clearAnimation();
                    arrowImageView.startAnimation(reverseAnimation);
                    tipsTextview.setText("下拉刷新");
                } else {
                    tipsTextview.setText("下拉刷新");
                }
                Log.v(TAG, "当前状态,下拉刷新");
                break;
    
            case REFRESHING:
                headView.setPadding(0, 0, 0, 0);
                progressBar.setVisibility(View.VISIBLE);
                arrowImageView.clearAnimation();
                arrowImageView.setVisibility(View.GONE);
                tipsTextview.setText("正在刷新...");
                lastUpdatedTextView.setVisibility(View.VISIBLE);
    
                Log.v(TAG, "当前状态,正在刷新...");
                break;
            case DONE:
                headView.setPadding(0, -1 * headContentHeight, 0, 0);
    
                progressBar.setVisibility(View.GONE);
                arrowImageView.clearAnimation();
                arrowImageView.setImageResource(R.drawable.arrow);
                tipsTextview.setText("下拉刷新");
                lastUpdatedTextView.setVisibility(View.VISIBLE);
    
                Log.v(TAG, "当前状态,done");
                break;
            }
        }
    
        public void setonRefreshListener(OnRefreshListener refreshListener) {
            this.refreshListener = refreshListener;
            isRefreshable = true;
        }
    
        public interface OnRefreshListener {
            public void onRefresh();
        }
    
        public void onRefreshComplete() {
            state = DONE;
            lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());
            changeHeaderViewByState();
        }
    
        private void onRefresh() {
            if (refreshListener != null) {
                refreshListener.onRefresh();
            }
        }
    
        // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
        private 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);
        }
    
        public void setAdapter(BaseAdapter adapter) {
            lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());
            super.setAdapter(adapter);
        }
    
    }
    View Code

    MainActivity.java

    package com.laohuai.appdemo.customui;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.laohuai.appdemo.customui.ui.MyListView;
    import com.laohuai.appdemo.customui.ui.MyListView.OnRefreshListener;
    
    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    
        private List<String> data;
        private BaseAdapter adapter;
    
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            data = new ArrayList<String>();
            data.add("a");
            data.add("b");
            data.add("c");
    
            final MyListView listView = (MyListView) findViewById(R.id.listView);
            adapter = new BaseAdapter() {
                public View getView(int position, View convertView, ViewGroup parent) {
                    TextView tv = new TextView(getApplicationContext());
                    tv.setText(data.get(position));
                    return tv;
                }
                public long getItemId(int position) {
                    return 0;
                }
                public Object getItem(int position) {
                    return null;
                }
                public int getCount() {
                    return data.size();
                }
            };
            listView.setAdapter(adapter);
    
            listView.setonRefreshListener(new OnRefreshListener() {
                public void onRefresh() {
                    new AsyncTask<Void, Void, Void>() {
                        protected Void doInBackground(Void... params) {
                            try {
                                Thread.sleep(1000);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            data.add("刷新后添加的内容");
                            return null;
                        }
                        @Override
                        protected void onPostExecute(Void result) {
                            adapter.notifyDataSetChanged();
                            listView.onRefreshComplete();
                        }
                    }.execute(null);
                }
            });
        }
    }
    View Code

    DEMO完整下载路径:http://download.csdn.net/detail/androidsj/5517515

     http://download.csdn.net/detail/androidsj/5538199

  • 相关阅读:
    动态规划-石子问题
    动态规划-最长不下降子序列
    STL 二分查找
    动态规划-最长公共子序列与最长公共子串
    动态规划-背包问题
    高精度运算模板学习
    二叉树 | 根据前序、后序生成中序
    03.动画
    02.绘制函数
    01.hello world
  • 原文地址:https://www.cnblogs.com/androidsj/p/3117534.html
Copyright © 2011-2022 走看看