Android 自定義控件基礎-ListView下拉刷新

??自定義控件學了很久了者祖,發(fā)現學了總是忘,于是打算用博客來記錄自己學習的知識點屁商。
??今天是自定義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的下拉刷新僻族,必須監(jiān)聽ListView是否滑動到最頂端,因此要實現ListView的監(jiān)聽接口OnScrollListener屡谐,并且要監(jiān)聽ListView的OnTouch事件述么。根據滑動的情況來判斷刷新的情況。
??首先我們在定義了一個成員變量來保存ListView的狀態(tài)--mState
??其次定義了幾個靜態(tài)常量來表示不同的狀態(tài)

private final static int NONE = 0;  // 無狀態(tài)
private final static int DOWN_UPDATE = 1; // 提示下拉可以刷新
private final static int UPDATE = 2; // 提示松開可以刷新
private final static int REFLASH = 3; // 更新

最后則是根據不同的滑動來更改mState的狀態(tài):

    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方法主要是用來處理不同狀態(tài)下的事件<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的下拉刷新(二)

??經過上面的過程度秘,是可以下拉的,處理不同狀態(tài)下的事件。還有一個問題就是刷新剑梳,也就是加載新的數據唆貌。加載刷新的操作肯定必須在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);
   }
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末追逮,一起剝皮案震驚了整個濱河市酪刀,隨后出現的幾起案子,更是在濱河造成了極大的恐慌钮孵,老刑警劉巖骂倘,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異巴席,居然都是意外死亡历涝,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門漾唉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荧库,“玉大人,你說我怎么就攤上這事毡证〉绲” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵料睛,是天一觀的道長丐箩。 經常有香客問我,道長恤煞,這世上最難降的妖魔是什么屎勘? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮居扒,結果婚禮上概漱,老公的妹妹穿的比我還像新娘。我一直安慰自己喜喂,他們只是感情好瓤摧,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著玉吁,像睡著了一般照弥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上进副,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天这揣,我揣著相機與錄音,去河邊找鬼。 笑死给赞,一個胖子當著我的面吹牛机打,可吹牛的內容都是我干的。 我是一名探鬼主播片迅,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼残邀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了柑蛇?” 一聲冷哼從身側響起罐旗,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唯蝶,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體遗嗽,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡粘我,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了痹换。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征字。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖娇豫,靈堂內的尸體忽然破棺而出匙姜,到底是詐尸還是另有隱情,我是刑警寧澤冯痢,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布氮昧,位于F島的核電站,受9級特大地震影響浦楣,放射性物質發(fā)生泄漏袖肥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一振劳、第九天 我趴在偏房一處隱蔽的房頂上張望椎组。 院中可真熱鬧,春花似錦历恐、人聲如沸寸癌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒸苇。三九已至,卻和暖如春哮洽,著一層夾襖步出監(jiān)牢的瞬間填渠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留氛什,地道東北人莺葫。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像枪眉,于是被迫代替她去往敵國和親捺檬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容