Android 自定义控件基础-ListView下拉刷新

  自定义控件学了很久了,发现学了总是忘,于是打算用博客来记录自己学习的知识点。
  今天是自定义ListView来实现下拉刷新,这些文章都是借鉴慕课网上的视频来写的.
  自定义一个控件,先是看它继承于那个控件,如果我们继承View控件的话,那得让我们写很多关于ListView的功能,这些东西我自己觉得很麻烦,而且也没有那个必要因为我们可以直接继承ListView,在listView的基础上来加一些我们需要的东西。

1.向ListView加Header布局

private void initView(Context context)
{
    mLayoutInflater = LayoutInflater.from(context);
    mHeaerView = mLayoutInflater.inflate(R.layout.header_layout, null, false);
    addHeaderView(mHeaerView);
}

2.隐藏Header布局

private void initView(Context context) {
        mLayoutInflater = LayoutInflater.from(context);
        mHeaerView = mLayoutInflater.inflate(R.layout.header_layout, null, false);
        measureView(mHeaerView);
        mHeaderViewHeight = mHeaerView.getMeasuredHeight();
        setHeaderViewHeightPadding(mHeaderViewHeight);
        Log.i("main", mHeaderViewHeight + "");
        addHeaderView(mHeaerView);
    }
    private void measureView(View view)
    {
        ViewGroup.LayoutParams lp = view.getLayoutParams();
        if(lp == null)
        {
            lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        //mHeaerView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        /**
         * width 和height里面包含的不仅仅有View的宽和高,还有View控件的测量模式
         * 测量模式的产生方式就是如下所示
         */
        int width = ViewGroup.getChildMeasureSpec(0,0,lp.width);
        int height = 0;
        int tempHeight = lp.height;
        if(tempHeight > 0)
        {
            height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
        }
        view.measure(width, height);




    }
    private void setHeaderViewHeightPadding(int padding) {
        mHeaerView.setPadding(mHeaerView.getPaddingLeft(), -padding, mHeaerView.getPaddingRight(), mHeaerView.getPaddingBottom());
        mHeaerView.invalidate();
    }

3.实现ListView的下拉刷新(一)

  要想实现ListView的下拉刷新,必须监听ListView是否滑动到最顶端,因此要实现ListView的监听接口OnScrollListener,并且要监听ListView的OnTouch事件。根据滑动的情况来判断刷新的情况。
  首先我们在定义了一个成员变量来保存ListView的状态--mState
  其次定义了几个静态常量来表示不同的状态

private final static int NONE = 0;  // 无状态
private final static int DOWN_UPDATE = 1; // 提示下拉可以刷新
private final static int UPDATE = 2; // 提示松开可以刷新
private final static int REFLASH = 3; // 更新

最后则是根据不同的滑动来更改mState的状态:

    public boolean onTouchEvent(MotionEvent ev) {
 
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                if (mFirstVisibleItem == 0) {
                    mIsRemark = true;  // mIsRemark只是一个标记,表示当前可见的第一个Item是不是所有的Item中的第一个
                    mStartY = (int) ev.getY();
                    Log.i("main", "我进来了");
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                onMove(ev);
                tempY = (int) (ev.getY() - mStartY);
                Log.i("main", "tempY = " + tempY);
                break;
            }
            case MotionEvent.ACTION_UP: {
 
                if(mState == DOWN_UPDATE)
                {
                    mState = NONE;
                }
                if(mState == UPDATE)
                {
                    mState = REFLASH;
                    mListener.reFlash();
                    Log.i("main", "我来了");
                }
                Log.i("main", "tempY11 = " + tempY);
                if(tempY <= 0 && mIsRemark)
                {
                    Log.i("main", "我进来le");
                    mState = NONE;
                }
 
                change();
                break;
            }
        }
 
 
        return super.onTouchEvent(ev);
    }
 
    private void onMove(MotionEvent ev) {
        if (mIsRemark) {
            if (ev.getY() - mStartY > 0) {
                int dy = (int) (ev.getY() - mStartY);
                if (dy > mHeaderViewHeight + 20) {
                    mState = UPDATE;
                } else {
                    mState = DOWN_UPDATE;
                }
                setHeaderViewHeightPadding(mHeaderViewHeight - dy);
                change();
            }
            return;
        }
        return;
    }
/**<br> *change方法主要是用来处理不同状态下的事件<br> *<br> */
    private void change() {
        initChildView();
        RotateAnimation ani = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        ani.setDuration(500);
        ani.setFillAfter(true);
        RotateAnimation ani1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        ani1.setDuration(500);
        ani1.setFillAfter(true);
        if (mState == UPDATE)
        {
            mProgressBar.setVisibility(View.GONE);
            mImageView.setVisibility(View.VISIBLE);
            mImageView.clearAnimation();
            mImageView.setAnimation(ani);
            mTextViewFlash.setText("松开可以刷新!");
            mTextViewTime.setVisibility(View.VISIBLE);
            mTextViewTime.setText("上次更新的时间:" + mUpdateTime);
        }
        if (mState == DOWN_UPDATE)
        {
            mProgressBar.setVisibility(View.GONE);
            mImageView.setVisibility(View.VISIBLE);
            mTextViewTime.setVisibility(View.VISIBLE);
            mImageView.clearAnimation();
            mImageView.setAnimation(ani1);
            mTextViewFlash.setText("下拉可以刷新");
            mTextViewTime.setText("上次更新的时间:" + mUpdateTime);
        }
        if (mState == REFLASH)
        {
            setHeaderViewHeightPadding(10);
            mProgressBar.setVisibility(View.VISIBLE);
            mImageView.setVisibility(View.GONE);
            mTextViewTime.setVisibility(View.GONE);
            mTextViewFlash.setText("正在刷新...");
            mImageView.clearAnimation();
        }
        if(mState == NONE)
        {
            Log.i("main", "workspace");
            setHeaderViewHeightPadding(mHeaderViewHeight);
            mIsRemark = false;
            mProgressBar.setVisibility(View.GONE);
            mImageView.setVisibility(View.VISIBLE);
            mImageView.setAnimation(ani1);
        }
    }
    private void initChildView()
    {
        if(mTextViewFlash == null)
        {
            mTextViewFlash = (TextView) mHeaerView.findViewById(R.id.id_textView_Flash);
        }
        if(mTextViewTime == null)
        {
            mTextViewTime = (TextView) mHeaerView.findViewById(R.id.id_textView_Time);
        }
        if(mImageView == null)
        {
            mImageView = (ImageView) mHeaerView.findViewById(R.id.id_imagView);
        }
        if(mProgressBar == null)
        {
            mProgressBar = (ProgressBar) mHeaerView.findViewById(R.id.id_progressbar);
        }
    }

4.实现ListView的下拉刷新(二)

  经过上面的过程,是可以下拉的,处理不同状态下的事件。还有一个问题就是刷新,也就是加载新的数据。加载刷新的操作肯定必须在UI线程中,因此ListView中必须得有一个回调接口,用来MinaActivity来实现,并且来进行一些操作。

回调接口:

public void setOnFlashListener(FlashListener listener)
{
    this.mListener = listener;
}
 
public interface  FlashListener
{
    void reFlash();
}

回调接口的调用:

if(mState == UPDATE)
{
    mState = REFLASH;
    mListener.reFlash();
    Log.i("main", "我来了");
}

MainActivity中回调接口的实现和接口方法的实现:

mListView.setOnFlashListener(new FlashListView.FlashListener() {
            @Override
            public void reFlash() {
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        addDatas();
                        loadDatas();
                        mListView.reFalshComplete();
                    }
                }, 5000);
            }
        });
private void addDatas()
   {
       int i = mDatas.size();
       for(int j = i; j < i + 10; j++)
       {
           mDatas.add(new Bean("Title" + j, "Content" + j, R.mipmap.ic_launcher));
       }
       myAdapter.dataChange(mDatas);
   }
   private void loadDatas()
   {
       mListView.setAdapter(myAdapter);
   }
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容