自定义总结2017.8.28

来源:互联网 发布:阿里云飞天有几个部门 编辑:程序博客网 时间:2024/06/05 03:20

1.自定义录播图:

1.MainActivity ViewPager的使用

public class MainActivity extends Activity implements OnPageChangeListener{    private ViewPager viewPager;    private int[] imageResIds;    private ArrayList<ImageView> imageViewList;    private LinearLayout ll_point_container;    private String[] contentDescs;    private TextView tv_desc;    private int previousSelectedPosition = 0;    boolean isRunning = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 初始化布局 View视图        initViews();        // Model数据        initData();        // Controller 控制器        initAdapter();        // 开启轮询        new Thread(){            public void run() {                isRunning = true;                while(isRunning){                    try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    // 往下跳一位                    runOnUiThread(new Runnable() {                        @Override                        public void run() {                            System.out.println("设置当前位置: " + viewPager.getCurrentItem());                            viewPager.setCurrentItem(viewPager.getCurrentItem()+1);                                                 }                    });                }            };        }.start();    }    @Override    protected void onDestroy() {        super.onDestroy();        isRunning = false;    }    private void initViews() {        viewPager = (ViewPager) findViewById(R.id.viewpager);        viewPager.setOnPageChangeListener(this);// 设置页面更新监听//      viewPager.setOffscreenPageLimit(1);// 左右各保留几个对象        ll_point_container = (LinearLayout) findViewById(R.id.ll_point_container);        tv_desc = (TextView) findViewById(R.id.tv_desc);    }    private void initData() {        // 初始化要显示的数据        // 图片资源id数组        imageResIds = new int[]{R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e};        // 文本描述        contentDescs = new String[]{                "巩俐不低俗,我就不能低俗",                "扑树又回来啦!再唱经典老歌引万人大合唱",                "揭秘北京电影如何升级",                "乐视网TV版大派送",                "热血屌丝的反杀"        };        // 初始化要展示的5个ImageView        imageViewList = new ArrayList<ImageView>();        ImageView imageView;        View pointView;        LayoutParams layoutParams;        for (int i = 0; i < imageResIds.length; i++) {            // 初始化要显示的图片对象            imageView = new ImageView(this);            imageView.setBackgroundResource(imageResIds[i]);            imageViewList.add(imageView);            // 加小白点, 指示器            pointView = new View(this);            pointView.setBackgroundResource(R.drawable.selector_bg_point);            layoutParams = new LinearLayout.LayoutParams(5, 5);            if(i != 0)                layoutParams.leftMargin = 10;            // 设置默认所有都不可用            pointView.setEnabled(false);            ll_point_container.addView(pointView, layoutParams);        }    }    private void initAdapter() {        ll_point_container.getChildAt(0).setEnabled(true);        tv_desc.setText(contentDescs[0]);        previousSelectedPosition = 0;        // 设置适配器        viewPager.setAdapter(new MyAdapter());        // 默认设置到中间的某个位置        int pos = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % imageViewList.size());        // 2147483647 / 2 = 1073741823 - (1073741823 % 5)        viewPager.setCurrentItem(5000000); // 设置到某个位置    }    class MyAdapter extends PagerAdapter{        @Override        public int getCount() {            return Integer.MAX_VALUE;        }        // 3. 指定复用的判断逻辑, 固定写法        @Override        public boolean isViewFromObject(View view, Object object) {            // 当划到新的条目, 又返回来, view是否可以被复用.            // 返回判断规则            return view == object;        }        // 1. 返回要显示的条目内容, 创建条目        @Override        public Object instantiateItem(ViewGroup container, int position) {            System.out.println("instantiateItem初始化: " + position);            // container: 容器: ViewPager            // position: 当前要显示条目的位置 0 -> 4//          newPosition = position % 5            int newPosition = position % imageViewList.size();            ImageView imageView = imageViewList.get(newPosition);            // a. 把View对象添加到container中            container.addView(imageView);            // b. 把View对象返回给框架, 适配器            return imageView; // 必须重写, 否则报异常        }        // 2. 销毁条目        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            // object 要销毁的对象            System.out.println("destroyItem销毁: " + position);            container.removeView((View)object);        }    }    @Override    public void onPageScrolled(int position, float positionOffset,            int positionOffsetPixels) {        // 滚动时调用    }    @Override    public void onPageSelected(int position) {        // 新的条目被选中时调用        System.out.println("onPageSelected: " + position);        int newPosition = position % imageViewList.size();        //设置文本        tv_desc.setText(contentDescs[newPosition]);//      for (int i = 0; i < ll_point_container.getChildCount(); i++) {//          View childAt = ll_point_container.getChildAt(position);//          childAt.setEnabled(position == i);//      }        // 把之前的禁用, 把最新的启用, 更新指示器        ll_point_container.getChildAt(previousSelectedPosition).setEnabled(false);        ll_point_container.getChildAt(newPosition).setEnabled(true);        // 记录之前的位置        previousSelectedPosition  = newPosition;    }    @Override    public void onPageScrollStateChanged(int state) {        // 滚动状态变化时调用    }}

selector_bg_point.xml

<item android:state_enabled="true" android:drawable="@drawable/shape_bg_point_enable"/><item android:state_enabled="false" android:drawable="@drawable/shape_bg_point_disable"/>


shape_bg_point_disable.xml

shape_bg_point_enable.xml

RelativeLayout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="160dp" >        <android.support.v4.view.ViewPager            android:id="@+id/viewpager"            android:layout_width="match_parent"            android:layout_height="match_parent" />        <LinearLayout            android:layout_width="match_parent"            android:layout_height="40dp"            android:padding="5dp"            android:orientation="vertical"            android:layout_alignParentBottom="true"            android:gravity="center_horizontal"            android:background="#66000000" >            <TextView                android:id="@+id/tv_desc"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:textColor="@android:color/white"                android:singleLine="true"                android:text="天王盖地虎, 天王盖地虎, 天王盖地虎, " />            <LinearLayout                 android:id="@+id/ll_point_container"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_marginTop="5dp"                android:orientation="horizontal"                ></LinearLayout>        </LinearLayout>    </RelativeLayout>

2.自定义开关



ToggleView

/**
* 自定义开关
* @author poplar
*
* Android 的界面绘制流程
* 测量 摆放 绘制
* measure -> layout -> draw
* | | |
* onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件
*
* onResume()之后执行
*
* View
* onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容)
*
* ViewGroup
* onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容)
*/
public class ToggleView extends View {

private Bitmap switchBackgroupBitmap; // 背景图片private Bitmap slideButtonBitmap; // 滑块图片private Paint paint; // 画笔private boolean mSwitchState = false; // 开关状态, 默认false  private float currentX;/** * 用于代码创建控件 * @param context */public ToggleView(Context context) {    super(context);    init();}/** * 用于在xml里使用, 可指定自定义属性 * @param context * @param attrs */public ToggleView(Context context, AttributeSet attrs) {    super(context, attrs);    init();    // 获取配置的自定义属性    String namespace = "http://schemas.android.com/apk/res/com.itheima74.toggleview";    int switchBackgroundResource = attrs.getAttributeResourceValue(namespace , "switch_background", -1);    int slideButtonResource = attrs.getAttributeResourceValue(namespace , "slide_button", -1);    mSwitchState = attrs.getAttributeBooleanValue(namespace, "switch_state", false);    setSwitchBackgroundResource(switchBackgroundResource);    setSlideButtonResource(slideButtonResource);}/** * 用于在xml里使用, 可指定自定义属性, 如果指定了样式, 则走此构造函数 * @param context * @param attrs * @param defStyle */public ToggleView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);    init();}private void init() {    paint = new Paint();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    setMeasuredDimension(switchBackgroupBitmap.getWidth(), switchBackgroupBitmap.getHeight());}// Canvas 画布, 画板. 在上边绘制的内容都会显示到界面上.@Overrideprotected void onDraw(Canvas canvas) {    // 1. 绘制背景    canvas.drawBitmap(switchBackgroupBitmap, 0, 0, paint);    // 2. 绘制滑块    if(isTouchMode){        // 根据当前用户触摸到的位置画滑块        // 让滑块向左移动自身一半大小的位置        float newLeft = currentX - slideButtonBitmap.getWidth() / 2.0f;        int maxLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();        // 限定滑块范围        if(newLeft < 0){            newLeft = 0; // 左边范围        }else if (newLeft > maxLeft) {            newLeft = maxLeft; // 右边范围        }        canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);    }else {        // 根据开关状态boolean, 直接设置图片位置        if(mSwitchState){// 开            int newLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();            canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);        }else {// 关            canvas.drawBitmap(slideButtonBitmap, 0, 0, paint);        }    }}boolean isTouchMode = false;private OnSwitchStateUpdateListener onSwitchStateUpdateListener;// 重写触摸事件, 响应用户的触摸.@Overridepublic boolean onTouchEvent(MotionEvent event) {    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:        isTouchMode = true;        System.out.println("event: ACTION_DOWN: " + event.getX());        currentX = event.getX();        break;    case MotionEvent.ACTION_MOVE:        System.out.println("event: ACTION_MOVE: " + event.getX());        currentX = event.getX();        break;    case MotionEvent.ACTION_UP:        isTouchMode = false;        System.out.println("event: ACTION_UP: " + event.getX());        currentX = event.getX();        float center = switchBackgroupBitmap.getWidth() / 2.0f;        // 根据当前按下的位置, 和控件中心的位置进行比较.         boolean state = currentX > center;        // 如果开关状态变化了, 通知界面. 里边开关状态更新了.        if(state != mSwitchState && onSwitchStateUpdateListener != null){            // 把最新的boolean, 状态传出去了            onSwitchStateUpdateListener.onStateUpdate(state);        }        mSwitchState = state;        break;    default:        break;    }    // 重绘界面    invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新    return true; // 消费了用户的触摸事件, 才可以收到其他的事件.}/** * 设置背景图 * @param switchBackground */public void setSwitchBackgroundResource(int switchBackground) {    switchBackgroupBitmap = BitmapFactory.decodeResource(getResources(), switchBackground);}/** * 设置滑块图片资源 * @param slideButton */public void setSlideButtonResource(int slideButton) {    slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);}/** * 设置开关状态 * @param b */public void setSwitchState(boolean mSwitchState) {    this.mSwitchState = mSwitchState;}public interface OnSwitchStateUpdateListener{    // 状态回调, 把当前状态传出去    void onStateUpdate(boolean state);}public void setOnSwitchStateUpdateListener(        OnSwitchStateUpdateListener onSwitchStateUpdateListener) {            this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;}

}


MainActivity

public class MainActivity extends Activity {    private ToggleView toggleView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        toggleView = (ToggleView) findViewById(R.id.toggleView);//        toggleView.setSwitchBackgroundResource(R.drawable.switch_background);//        toggleView.setSlideButtonResource(R.drawable.slide_button);//        toggleView.setSwitchState(true);//                // 设置开关更新监听        toggleView.setOnSwitchStateUpdateListener(new OnSwitchStateUpdateListener(){            @Override            public void onStateUpdate(boolean state) {                Toast.makeText(getApplicationContext(), "state: " + state, 0).show();            }        });    }

activity_main.xml

<RelativeLayout     xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:itheima="http://schemas.android.com/apk/res/com.itheima74.toggleview"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <com.itheima74.toggleview.ui.ToggleView        android:id="@+id/toggleView"        android:layout_centerInParent="true"        itheima:switch_background="@drawable/switch_background"        itheima:slide_button="@drawable/slide_button"        itheima:switch_state="false"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></RelativeLayout>


侧滑面板的案列:


SlideMenu.class

package com.example.administrator.yan55text_20170824.ui;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;public class SlideMenu extends ViewGroup {    private float downX; // 按下的x坐标    private float downY; // 按下的y坐标    private float moveX;    public static final int MAIN_STATE = 0;    public static final int MENU_STATE = 1;    private int currentState = MAIN_STATE; // 当前模式    private Scroller scroller;    public SlideMenu(Context context) {        super(context);        init();    }    public SlideMenu(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public SlideMenu(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();    }    private void init() {        // 初始化滚动器, 数值模拟器        scroller = new Scroller(getContext());    }    /**     * 测量并设置 所有子View的宽高     * widthMeasureSpec: 当前控件的宽度测量规则     * heightMeasureSpec: 当前控件的高度测量规则     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // 指定左面板的宽高        View leftMenu = getChildAt(0);        leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec);        // 指定主面板的宽高        View mainContent = getChildAt(1);        mainContent.measure(widthMeasureSpec, heightMeasureSpec);        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    /**     * changed: 当前控件的尺寸大小, 位置 是否发生了变化     * left:当前控件 左边距     * top:当前控件 顶边距     * right:当前控件 右边界     * bottom:当前控件 下边界     */    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // 摆放内容, 左面板        View leftMenu = getChildAt(0);        leftMenu.layout(-leftMenu.getMeasuredWidth(), 0, 0, b);        // 主面板        getChildAt(1).layout(l, t, r, b);    }    /**     * 处理触摸事件     */    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                downX = event.getX();                break;            case MotionEvent.ACTION_MOVE:                moveX = event.getX();                // 将要发生的偏移量/变化量                int scrollX = (int) (downX - moveX);                // 计算将要滚动到的位置, 判断是否会超出去, 超出去了.不执行scrollBy                // getScrollX() 当前滚动到的位置                int newScrollPosition = getScrollX() + scrollX;                if (newScrollPosition < -getChildAt(0).getMeasuredWidth()) { // 限定左边界                    // < -240                    scrollTo(-getChildAt(0).getMeasuredWidth(), 0);                } else if (newScrollPosition > 0) { // 限定右边界                    // > 0                    scrollTo(0, 0);                } else {                    // 让变化量生效                    scrollBy(scrollX, 0);                }                downX = moveX;                break;            case MotionEvent.ACTION_UP:                // 根据当前滚动到的位置, 和左面板的一半进行比较                int leftCenter = (int) (-getChildAt(0).getMeasuredWidth() / 2.0f);                if (getScrollX() < leftCenter) {                    // 打开, 切换成菜单面板                    currentState = MENU_STATE;                    updateCurrentContent();                } else {                    // 关闭, 切换成主面板                    currentState = MAIN_STATE;                    updateCurrentContent();                }                break;            default:                break;        }        return true; // 消费事件    }    /**     * 根据当前的状态, 执行 关闭/开启 的动画     */    private void updateCurrentContent() {        int startX = getScrollX();        int dx = 0;        if (currentState == MENU_STATE) {            dx = -getChildAt(0).getMeasuredWidth() - startX;        } else {            dx = 0 - startX;        }        int duration = Math.abs(dx * 2);         scroller.startScroll(startX, 0, dx, 0, duration);        invalidate();// 重绘界面 -> drawChild() -> computeScroll();    }    //2. 维持动画的继续    @Override    public void computeScroll() {        super.computeScroll();        if (scroller.computeScrollOffset()) { // 直到duration事件以后, 结束            // true, 动画还没有结束            // 获取当前模拟的数据, 也就是要滚动到的位置            int currX = scroller.getCurrX();            System.out.println("currX: " + currX);            scrollTo(currX, 0); // 滚过去            invalidate(); // 重绘界面-> drawChild() -> computeScroll();循环        }    }    public void open() {        currentState = MENU_STATE;        updateCurrentContent();    }    public void close() {        currentState = MAIN_STATE;        updateCurrentContent();    }    public void switchState() {        if (currentState == MAIN_STATE) {            open();        } else {            close();        }    }    public int getCurrentState() {        return currentState;    }    /**     * 拦截判断     */    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                downX = ev.getX();                downY = ev.getY();                break;            case MotionEvent.ACTION_MOVE:                float xOffset = Math.abs(ev.getX() - downX);                float yOffset = Math.abs(ev.getY() - downY);                if (xOffset > yOffset && xOffset > 5) { // 水平方向超出一定距离时,才拦截                    return true; // 拦截此次触摸事件, 界面的滚动                }                break;            case MotionEvent.ACTION_UP:                break;            default:                break;        }        return super.onInterceptTouchEvent(ev);    }}

MainActivity.class

public class MainActivity extends Activity implements OnClickListener{    private SlideMenu sm;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_main);        sm = (SlideMenu) findViewById(R.id.sm);                findViewById(R.id.ib_back).setOnClickListener(this);    }    public void onTabClick(View view){    }    @Override    public void onClick(View v) {        sm.switchState();       }}

activity_main.xmllayout_left_menu.xmllayout_main_content.xml

下拉刷新提示


public class RefreshListView extends ListView implements OnScrollListener{    private View mHeaderView; // 头布局    private float downY; // 按下的y坐标    private float moveY; // 移动后的y坐标    private int mHeaderViewHeight; // 头布局高度    public static final int PULL_TO_REFRESH = 0;// 下拉刷新    public static final int RELEASE_REFRESH = 1;// 释放刷新    public static final int REFRESHING = 2; // 刷新中    private int currentState = PULL_TO_REFRESH; // 当前刷新模式    private RotateAnimation rotateUpAnim; // 箭头向上动画    private RotateAnimation rotateDownAnim; // 箭头向下动画    private View mArrowView;        // 箭头布局    private TextView mTitleText;    // 头布局标题    private ProgressBar pb;         // 进度指示器    private TextView mLastRefreshTime; // 最后刷新时间    private OnRefreshListener mListener; // 刷新监听    private View mFooterView;       // 脚布局    private int mFooterViewHeight;  // 脚布局高度    private boolean isLoadingMore; // 是否正在加载更多    public RefreshListView(Context context) {        super(context);        init();    }    public RefreshListView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public RefreshListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();    }    /**     * 初始化头布局, 脚布局     * 滚动监听     */    private void init() {        initHeaderView();        initAnimation();        initFooterView();        setOnScrollListener(this);    }    /**     * 初始化脚布局     */    private void initFooterView() {        mFooterView = View.inflate(getContext(), R.layout.layout_footer_list, null);        mFooterView.measure(0, 0);        mFooterViewHeight = mFooterView.getMeasuredHeight();        // 隐藏脚布局        mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);        addFooterView(mFooterView);    }    /**     * 初始化头布局的动画     */    private void initAnimation() {        // 向上转, 围绕着自己的中心, 逆时针旋转0 -> -180.        rotateUpAnim = new RotateAnimation(0f, -180f,                 Animation.RELATIVE_TO_SELF, 0.5f,                 Animation.RELATIVE_TO_SELF, 0.5f);        rotateUpAnim.setDuration(300);        rotateUpAnim.setFillAfter(true); // 动画停留在结束位置        // 向下转, 围绕着自己的中心, 逆时针旋转 -180 -> -360        rotateDownAnim = new RotateAnimation(-180f, -360,                Animation.RELATIVE_TO_SELF, 0.5f,                 Animation.RELATIVE_TO_SELF, 0.5f);        rotateDownAnim.setDuration(300);        rotateDownAnim.setFillAfter(true); // 动画停留在结束位置    }    /**     * 初始化头布局     */    private void initHeaderView() {        mHeaderView = View.inflate(getContext(), R.layout.layout_header_list, null);        mArrowView = mHeaderView.findViewById(R.id.iv_arrow);        pb = (ProgressBar) mHeaderView.findViewById(R.id.pb);        mTitleText = (TextView) mHeaderView.findViewById(R.id.tv_title);        mLastRefreshTime = (TextView) mHeaderView.findViewById(R.id.tv_desc_last_refresh);        // 提前手动测量宽高        mHeaderView.measure(0, 0);// 按照设置的规则测量        mHeaderViewHeight = mHeaderView.getMeasuredHeight();        System.out.println(" measuredHeight: " + mHeaderViewHeight);        // 设置内边距, 可以隐藏当前控件 , -自身高度        mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);        // 在设置数据适配器之前执行添加 头布局/脚布局 的方法.        addHeaderView(mHeaderView);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        // 判断滑动距离, 给Header设置paddingTop        switch (ev.getAction()) {        case MotionEvent.ACTION_DOWN:            downY = ev.getY();            System.out.println("downY: " + downY);            break;        case MotionEvent.ACTION_MOVE:            moveY = ev.getY();            System.out.println("moveY: " + moveY);            // 如果是正在刷新中, 就执行父类的处理            if(currentState == REFRESHING){                return super.onTouchEvent(ev);            }            float offset = moveY - downY; // 移动的偏移量            // 只有 偏移量>0, 并且当前第一个可见条目索引是0, 才放大头部            if(offset > 0 && getFirstVisiblePosition() == 0){//          int paddingTop = -自身高度 + 偏移量                int paddingTop = (int) (- mHeaderViewHeight + offset);                mHeaderView.setPadding(0, paddingTop, 0, 0);                if(paddingTop >= 0 && currentState != RELEASE_REFRESH){// 头布局完全显示                    System.out.println("切换成释放刷新模式: " + paddingTop);                    // 切换成释放刷新模式                    currentState = RELEASE_REFRESH;                    updateHeader(); // 根据最新的状态值更新头布局内容                }else if(paddingTop < 0 && currentState != PULL_TO_REFRESH){ // 头布局不完全显示                    System.out.println("切换成下拉刷新模式: " + paddingTop);                    // 切换成下拉刷新模式                    currentState = PULL_TO_REFRESH;                    updateHeader(); // 根据最新的状态值更新头布局内容                }                return true; // 当前事件被我们处理并消费            }            break;        case MotionEvent.ACTION_UP:            // 根据刚刚设置状态            if(currentState == PULL_TO_REFRESH){//          - paddingTop < 0 不完全显示, 恢复                mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);            }else if(currentState == RELEASE_REFRESH){//          - paddingTop >= 0 完全显示, 执行正在刷新...                mHeaderView.setPadding(0, 0, 0, 0);                currentState = REFRESHING;                 updateHeader();            }            break;        default:            break;        }        return super.onTouchEvent(ev);    }    /**     * 根据状态更新头布局内容     */    private void updateHeader() {        switch (currentState) {        case PULL_TO_REFRESH: // 切换回下拉刷新            // 做动画, 改标题            mArrowView.startAnimation(rotateDownAnim);            mTitleText.setText("下拉刷新");            break;        case RELEASE_REFRESH: // 切换成释放刷新            // 做动画, 改标题            mArrowView.startAnimation(rotateUpAnim);            mTitleText.setText("释放刷新");            break;        case REFRESHING: // 刷新中...            mArrowView.clearAnimation();            mArrowView.setVisibility(View.INVISIBLE);            pb.setVisibility(View.VISIBLE);            mTitleText.setText("正在刷新中...");            if(mListener != null){                mListener.onRefresh(); // 通知调用者, 让其到网络加载更多数据.            }            break;        default:            break;        }    }    /**     * 刷新结束, 恢复界面效果     */    public void onRefreshComplete() {        if(isLoadingMore){            // 加载更多            mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);            isLoadingMore = false;        }else {            // 下拉刷新            currentState = PULL_TO_REFRESH;            mTitleText.setText("下拉刷新"); // 切换文本            mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局            pb.setVisibility(View.INVISIBLE);            mArrowView.setVisibility(View.VISIBLE);            String time = getTime();            mLastRefreshTime.setText("最后刷新时间: " + time);        }    }    private String getTime() {        long currentTimeMillis = System.currentTimeMillis();        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        return format.format(currentTimeMillis);    }    public interface OnRefreshListener{        void onRefresh(); // 下拉刷新        void onLoadMore();// 加载更多    }    public void setRefreshListener(OnRefreshListener mListener) {        this.mListener = mListener;    }//    public static int SCROLL_STATE_IDLE = 0; // 空闲//    public static int SCROLL_STATE_TOUCH_SCROLL = 1; // 触摸滑动//    public static int SCROLL_STATE_FLING = 2; // 滑翔    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        // 状态更新的时候        System.out.println("scrollState: " + scrollState);        if(isLoadingMore){            return; // 已经在加载更多.返回        }        // 最新状态是空闲状态, 并且当前界面显示了所有数据的最后一条. 加载更多        if(scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() >= (getCount() - 1)){            isLoadingMore = true;            System.out.println("scrollState: 开始加载更多");            mFooterView.setPadding(0, 0, 0, 0);            setSelection(getCount()); // 跳转到最后一条, 使其显示出加载更多.            if(mListener != null){                mListener.onLoadMore();            }        }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,            int visibleItemCount, int totalItemCount) {        // 滑动过程    }}


MainActivity.class

public class MainActivity extends Activity {    private RefreshListView listview;    private ArrayList<String> listDatas;    private MyAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题        setContentView(R.layout.activity_main);        listview = (RefreshListView) findViewById(R.id.listview);        listview.setRefreshListener(new OnRefreshListener() {            @Override            public void onRefresh() {                new Thread(){                    public void run() {                        try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        listDatas.add(0,"我是下拉刷新出来的数据!");                        runOnUiThread(new Runnable() {                            @Override                            public void run() {                                adapter.notifyDataSetChanged();                                listview.onRefreshComplete();                            }                        });                    };                }.start();            }            @Override            public void onLoadMore() {                new Thread(){                    public void run() {                        try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        listDatas.add("我是加载更多出来的数据!1");                        listDatas.add("我是加载更多出来的数据!2");                        listDatas.add("我是加载更多出来的数据!3");                        runOnUiThread(new Runnable() {                            @Override                            public void run() {                                adapter.notifyDataSetChanged();                                listview.onRefreshComplete();                            }                        });                    };                }.start();            }        });        listDatas = new ArrayList<String>();        for (int i = 0; i < 30; i++) {            listDatas.add("这是一条ListView数据: " + i);        }        // 设置数据适配器        adapter = new MyAdapter();        listview.setAdapter(adapter);    }    class MyAdapter extends BaseAdapter {        @Override        public int getCount() {            return listDatas.size();        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            TextView textView = new TextView(parent.getContext());            textView.setTextSize(18f);            textView.setText(listDatas.get(position));            return textView;        }        @Override        public Object getItem(int position) {            return listDatas.get(position);        }        @Override        public long getItemId(int position) {            return position;        }    }}


activity_main.xml

layout_footer_list.xml

layout_header_list.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal">    <FrameLayout        android:layout_margin="5dp"        android:layout_width="50dp"        android:layout_height="50dp" >        <ImageView            android:id="@+id/iv_arrow"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:src="@drawable/common_listview_headview_red_arrow" />        <ProgressBar            android:id="@+id/pb"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:indeterminateDrawable="@drawable/shape_progress"            android:visibility="invisible" />    </FrameLayout>    <LinearLayout        android:layout_margin="5dp"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center_horizontal"        android:orientation="vertical" >        <TextView            android:id="@+id/tv_title"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="5dp"            android:text="下拉刷新"            android:textColor="#F00"            android:textSize="18sp" />        <TextView            android:id="@+id/tv_desc_last_refresh"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="5dp"            android:singleLine="true"            android:text="最后刷新时间: 2015-10-11 09:20:35"            android:textColor="#666"            android:textSize="14sp" />    </LinearLayout></LinearLayout>----------