Android 自定義 上拉加載容器

App中下拉刷新和上拉加載是很常見(jiàn)的功能组去,網(wǎng)上也有很多第三方庫(kù)可以用,為了盡快完成項(xiàng)目,一般都是集成別人的庫(kù)快速完成功能霉祸, 但有時(shí)候產(chǎn)品腦洞比較大 ,用別人的庫(kù)又沒(méi)那么靈活改起來(lái)也麻煩袱蜡, 就只能自己來(lái)了脉执。。戒劫。半夷。。
下面看一下效果:


WeChat_20200313173628.gif

自定義還是挺麻煩的迅细,不過(guò)也比較有意思巫橄,完成這個(gè)需要先了解幾個(gè)知識(shí)點(diǎn):
1.自定義ViewGroup
2.Scroller
3.事件分發(fā)體系。
下面開(kāi)始簡(jiǎn)單的實(shí)現(xiàn)一下:
1.自定義ReboundLinearLayout 繼承自 RelativeLayout 這個(gè)ViewGroup內(nèi)部放需要上拉加載的Recyclerview

public class ReboundLinearLayout extends RelativeLayout {

2.由于事件傳遞的時(shí)候RecyclerView會(huì)把事件全部消耗完茵典,所以要在ReboundLinearLayout的onInterceptTouchEvent中判斷需要攔截的事件湘换, 這里的思路是:如果RecyclerView已經(jīng)滑動(dòng)到最底部,就可以進(jìn)行上拉加載了,這時(shí)候就可以攔截手指的向上滑動(dòng)事件:

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(isSlideToBottom(reboundRecyclerView)){
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startY = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    endY = ev.getY();
                    if(endY - startY >= 0){
                        return false;
                    }else if(endY - startY < 0){
                        return true;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    break;
                default:
                    break;
            }
        }else{
            return false;
        }
        return false;
    }

3.在攔截完事件后彩倚,我們?cè)趏nTouchEvent中進(jìn)行事件的處理筹我,當(dāng)然就是使用scroller來(lái)將RecyclerView進(jìn)行移動(dòng)了:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                scrollEndY = event.getY();
                if(startY - scrollEndY <= SizeUtils.dp2px(scrollHeight)){
                    scrollTo(0, (int) (startY - scrollEndY));
                }
                break;
            case MotionEvent.ACTION_UP:
                mScroller.startScroll(0, getScrollY(),0, -getScrollY(),300);
                invalidate();
                if(onRefreshListenner != null){
                    onRefreshListenner.onRefresh();
                }
                break;
            default:
                break;
        }
        return true;
    }

這樣就可以實(shí)現(xiàn)簡(jiǎn)單的上拉加載了,加個(gè)刷新監(jiān)聽(tīng) 帆离,在刷新的時(shí)候請(qǐng)求數(shù)據(jù)蔬蕊,就完成啦。哥谷。岸夯。
下面貼一下代碼

public class ReboundLinearLayout extends RelativeLayout {

    private RecyclerView reboundRecyclerView;
    //判斷滑動(dòng)方向
    private float startY;
    private float endY;

    private float scrollEndY;

    private Scroller mScroller;
    //最大拉動(dòng)距離
    private int scrollHeight = 80;

    private OnRefreshListenner onRefreshListenner;

    public ReboundLinearLayout(Context context) {
        super(context);
    }

    public ReboundLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
    }

    public ReboundLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(isSlideToBottom(reboundRecyclerView)){
            switch (ev.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startY = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    endY = ev.getY();
                    if(endY - startY >= 0){
                        return false;
                    }else if(endY - startY < 0){
                        return true;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    break;
                default:
                    break;
            }
        }else{
            return false;
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                scrollEndY = event.getY();
                if(startY - scrollEndY <= SizeUtils.dp2px(scrollHeight)){
                    scrollTo(0, (int) (startY - scrollEndY));
                }
                break;
            case MotionEvent.ACTION_UP:
                mScroller.startScroll(0, getScrollY(),0, -getScrollY(),300);
                invalidate();
                if(onRefreshListenner != null){
                    onRefreshListenner.onRefresh();
                }
                break;
            default:
                break;
        }
        return true;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        reboundRecyclerView = (RecyclerView) getChildAt(0);
    }

    public static boolean isSlideToBottom(RecyclerView recyclerView) {
        if (recyclerView == null) return false;
        if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset()
                >= recyclerView.computeVerticalScrollRange())
            return true;
        return false;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        //第二步
        if(mScroller.computeScrollOffset()){
            //第三步
            scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            invalidate();
        }
    }

    public void setOnRefreshListenner(OnRefreshListenner onRefreshListenner) {
        this.onRefreshListenner = onRefreshListenner;
    }

    public interface OnRefreshListenner{
        void onRefresh();
    }
}

結(jié)束。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末们妥,一起剝皮案震驚了整個(gè)濱河市猜扮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌监婶,老刑警劉巖旅赢,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異惑惶,居然都是意外死亡煮盼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)集惋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人踩娘,你說(shuō)我怎么就攤上這事刮刑。” “怎么了养渴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵雷绢,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我理卑,道長(zhǎng)翘紊,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任藐唠,我火速辦了婚禮帆疟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宇立。我一直安慰自己踪宠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布妈嘹。 她就那樣靜靜地躺著柳琢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柬脸,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天他去,我揣著相機(jī)與錄音,去河邊找鬼倒堕。 笑死灾测,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涩馆。 我是一名探鬼主播行施,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼魂那!你這毒婦竟也來(lái)了蛾号?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涯雅,失蹤者是張志新(化名)和其女友劉穎鲜结,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體活逆,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡精刷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔗候。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怒允。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖锈遥,靈堂內(nèi)的尸體忽然破棺而出纫事,到底是詐尸還是另有隱情,我是刑警寧澤所灸,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布丽惶,位于F島的核電站,受9級(jí)特大地震影響爬立,放射性物質(zhì)發(fā)生泄漏钾唬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一侠驯、第九天 我趴在偏房一處隱蔽的房頂上張望抡秆。 院中可真熱鬧,春花似錦吟策、人聲如沸琅轧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乍桂。三九已至冲杀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間睹酌,已是汗流浹背权谁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憋沿,地道東北人旺芽。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像辐啄,于是被迫代替她去往敵國(guó)和親采章。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355