RecyclerView粘性-懸浮頭部

粘性/懸浮頭部,效果如圖

a.gif

可使用一個開源的框架完成:

https://github.com/qdxxxx/StickyHeaderDecoration

配置
1.在 (項目) 的build.gradle中導入

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

2.依賴

implementation 'com.android.support:design:27.1.1'
implementation 'com.github.qdxxxx:StickyHeaderDecoration:1.0.1'
3.使用場景
這個自定義的數(shù)據(jù)顯示的效果

        mCars = new ArrayList<>();
        mCars.add(new Car("奧迪",  "A"));
        mCars.add(new Car("阿爾法羅密歐",  "A"));
        mCars.add(new Car("阿斯頓馬丁",  "A"));
        mCars.add(new Car("ALPINA",  "A"));
        mCars.add(new Car("安凱客車",  "A"));
        mCars.add(new Car("本田", "B"));
        mCars.add(new Car("別克", "B"));
        mCars.add(new Car("奔馳",  "B"));
        mCars.add(new Car("寶馬", "B"));
        mCars.add(new Car("保時捷",  "B"));
        mCars.add(new Car("比亞迪", "B"));
        mCars.add(new Car("北京", "B"));
        mCars.add(new Car("賓利",  "B"));
        mCars.add(new Car("巴博斯",  "B"));
        mCars.add(new Car("布加迪威龍", "B"));
        mCars.add(new Car("長安", "C"));
        mCars.add(new Car("長城",  "C"));
        mCars.add(new Car("大眾", "D"));
        mCars.add(new Car("東南",  "D"));
        mCars.add(new Car("東風", "D"));
        mCars.add(new Car("DS", "D"));
        mCars.add(new Car("道奇", "D"));
        mCars.add(new Car("東風小康", "D"));
    }

    private void initView() {
        final LayoutInflater inflater = LayoutInflater.from(this);
        mRlv = (RecyclerView) findViewById(R.id.rlv);
        mRlv.setLayoutManager(new LinearLayoutManager(this));
        RlvAdapter rlvAdapter = new RlvAdapter(mCars);
        //返回頭布局的內(nèi)容
        final NormalDecoration decoration = new NormalDecoration() {
            @Override
            public String getHeaderName(int i) {
                return mCars.get(i).headerName;
            }
        };
        //自定義頭布局,可不設(shè)置
        decoration.setOnDecorationHeadDraw(new NormalDecoration.OnDecorationHeadDraw() {
            @Override
            public View getHeaderView(final int i) {
                View inflate = inflater.inflate(R.layout.item_header, null);
                TextView tv = inflate.findViewById(R.id.tv);
                tv.setText(mCars.get(i).headerName);
                return inflate;
            }
        });
        mRlv.addItemDecoration(decoration);
        //頭布局的點擊事件
        decoration.setOnHeaderClickListener(new NormalDecoration.OnHeaderClickListener() {
            @Override
            public void headerClick(int i) {
                Toast.makeText(MainActivity.this, mCars.get(i).headerName, Toast.LENGTH_SHORT).show();
                startActivity(new Intent(MainActivity.this,FlowActivity.class));
            }
        });
        mRlv.setAdapter(rlvAdapter);
    }

這個在網(wǎng)絡網(wǎng)絡請求是MVP獲取到集合后

    @Override
    public void getData(TiXi base) {
        Log.e("zhuzhu", "getData: "+base.toString() );
      //就是只獲取到請求數(shù)據(jù)里的對象name
        final List<TiXi.DataBean> data = base.getData();
        final NormalDecoration decoration = new NormalDecoration() {
            @Override
            public String getHeaderName(int i) {
                return data.get(i).getName();
            }
        };
        mRe.addItemDecoration(decoration);

        adapter.setData(data);  //這個是添加數(shù)據(jù)
    }

二:實戰(zhàn)使用

以下是對粘性頭部的工具使用,因為上面的在實際情況下使用會有一些問題,(如果在網(wǎng)絡請求的數(shù)據(jù)中,每個對象是會返回一個要懸浮的屬性,如果用上面的,會把這個對象的那個屬性中的內(nèi)容全都顯示,而造成啦錯亂的問題,所以,在項目實際開發(fā)中,使用工具類比較實用)

1:使用方式其實就一行代碼,在自己要加懸浮頭的 RecyclerView 中添加:

添加的list集合,上下文對象

                 rv.addItemDecoration(new SuspensionDecoration(getContext(), mList));

2:工具類中的設(shè)置

public class SuspensionDecoration extends RecyclerView.ItemDecoration {
    private static final String TAG = SuspensionDecoration.class.getSimpleName();
    //    private int mTitleHeight;//title的高
    private static int COLOR_TITLE_BG = Color.parseColor("#EDEAEA");
    private static int COLOR_TITLE_FONT = Color.parseColor("#000000");
    private static int mTitleFontSize;//title字體大小
    ArrayList<ReMenBean.ContentsBean> classifies;
    private Paint mPaint;
    private Rect mBounds;//用于存放測量文字Rect
    private int mHeaderViewCount = 0;
    private int mTitleHeight = 0;
    private int paddingLeft;

    public SuspensionDecoration(Context context, ArrayList<ReMenBean.ContentsBean> classifies) {
        super();
        this.classifies = classifies;
        mPaint = new Paint();
        mBounds = new Rect();
        //dp轉(zhuǎn)px
        mTitleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, context.getResources().getDisplayMetrics());
        paddingLeft = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, context.getResources().getDisplayMetrics());
        mTitleFontSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 13, context.getResources().getDisplayMetrics());
        mPaint.setTextSize(mTitleFontSize);
        mPaint.setAntiAlias(true);
    }


    public int getHeaderViewCount() {
        return mHeaderViewCount;
    }

    public SuspensionDecoration setHeaderViewCount(int headerViewCount) {
        mHeaderViewCount = headerViewCount;
        return this;
    }

    @Override
    public void onDrawOver(Canvas c, final RecyclerView parent, RecyclerView.State state) {//最后調(diào)用 繪制在最上層
        Log.d(TAG, "onDrawOver");
        int pos = ((LinearLayoutManager) (parent.getLayoutManager())).findFirstVisibleItemPosition();
        //這里的position不算ondraw里面添加的view
        pos -= getHeaderViewCount();
        //pos為1,size為1姆另,1>0? true
        if (classifies == null || classifies.isEmpty() || pos > classifies.size() - 1 || pos < 0) {
            Log.d(TAG, "越界----");
            return;//越界
        }

        String tag = classifies.get(pos).getDay() + DateUtils.dateToWeek(classifies.get(pos).getDay());
        ;
        View child = parent.findViewHolderForLayoutPosition(pos + getHeaderViewCount()).itemView;//出現(xiàn)一個奇怪的bug珍语,有時候child為空十籍,所以將 child = parent.getChildAt(i)傻丝。-》 parent.findViewHolderForLayoutPosition(pos).itemView

        boolean flag = false;//定義一個flag蛾扇,Canvas是否位移過的標志
        if ((pos + 1) < classifies.size()) {//防止數(shù)組越界(一般情況不會出現(xiàn))
            if (null != tag && !tag.equals(classifies.get(pos + 1).getDay())) {//當前第一個可見的Item的tag咧织,不等于其后一個item的tag囤捻,說明懸浮的View要切換了
                Log.d("zxt", "onDrawOver() called with: c = [" + child.getTop());//當getTop開始變負萧豆,它的絕對值奸披,是第一個可見的Item移出屏幕的距離,
                //這里計算第一個可見的item的剩余高度是自己的頂部的坐標+item自身的高度涮雷,剩下的就是留下來可見的部分阵面,這里的child.getTop()是一個負值
                if (child.getHeight() + child.getTop() < mTitleHeight) {//當?shù)谝粋€可見的item在屏幕中還剩的高度小于title區(qū)域的高度時,我們也該開始做懸浮Title的“交換動畫”
                    c.save();//每次繪制前 保存當前Canvas狀態(tài)洪鸭,
                    flag = true;

                    //一種頭部折疊起來的視效样刷,個人覺得也還不錯~,由于child.getHeight() + child.getTop()是在不斷地變小览爵,因此這里有種漸變的裁剪矩形的感覺
                    //可與193行 c.drawRect 比較置鼻,只有bottom參數(shù)不一樣,由于 child.getHeight() + child.getTop() < mTitleHeight拾枣,所以繪制區(qū)域是在不斷的減小沃疮,有種折疊起來的感覺
                    // c.clipRect(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getRight() - parent.getPaddingRight(), parent.getPaddingTop() + child.getHeight() + child.getTop());

                    //類似餓了么點餐時,商品列表的懸停頭部切換“動畫效果”
                    //上滑時,將canvas上移 (y為負數(shù)) ,所以后面canvas 畫出來的Rect和Text都上移了梅肤,有種切換的“動畫”感覺
                    //這里是將下面畫的懸浮的部分往上移動mTitleHeight的距離,這里平移是下面畫的懸浮title部分司蔬,
                    //這里是從0到-mTitleHeight的過程,直至整個懸浮的title消失
                    c.translate(0, child.getHeight() + child.getTop() - mTitleHeight);//其實這里移動的是
                }
            }
        }
        /**
         * 實際上這里是繪制懸浮的title部分姨蝴,永遠在頂部顯示
         */
        mPaint.setColor(COLOR_TITLE_BG);
        //這里實際上是在一個固定的位置添加一個矩形的title罷了
        c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getRight() - parent.getPaddingRight(), parent.getPaddingTop() + mTitleHeight, mPaint);
        mPaint.setColor(COLOR_TITLE_FONT);
        //將文本通過畫筆來算出它占據(jù)的空間
        mPaint.getTextBounds(tag, 0, tag.length(), mBounds);
        //這里也是算的左下角的坐標啊俊啼,到底是什么回事啊
        c.drawText(tag, child.getPaddingLeft() + paddingLeft,
                parent.getPaddingTop() + mTitleHeight - (mTitleHeight / 2 - mBounds.height() / 2),
                mPaint);
        //只有在做了切換懸浮title動畫的時候才會有該操作
        if (flag)
            c.restore();//恢復畫布到之前保存的狀態(tài)

    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市左医,隨后出現(xiàn)的幾起案子授帕,更是在濱河造成了極大的恐慌同木,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跛十,死亡現(xiàn)場離奇詭異彤路,居然都是意外死亡,警方通過查閱死者的電腦和手機芥映,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門洲尊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奈偏,你說我怎么就攤上這事坞嘀。” “怎么了惊来?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵丽涩,是天一觀的道長。 經(jīng)常有香客問我裁蚁,道長矢渊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任厘擂,我火速辦了婚禮昆淡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刽严。我一直安慰自己昂灵,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布舞萄。 她就那樣靜靜地躺著眨补,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倒脓。 梳的紋絲不亂的頭發(fā)上撑螺,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音崎弃,去河邊找鬼甘晤。 笑死,一個胖子當著我的面吹牛饲做,可吹牛的內(nèi)容都是我干的线婚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼盆均,長吁一口氣:“原來是場噩夢啊……” “哼塞弊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤游沿,失蹤者是張志新(化名)和其女友劉穎饰抒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诀黍,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡袋坑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了眯勾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咒彤。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖咒精,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旷档,我是刑警寧澤模叙,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鞋屈,受9級特大地震影響范咨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜厂庇,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一渠啊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧权旷,春花似錦替蛉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至译柏,卻和暖如春镣煮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鄙麦。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工典唇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胯府。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓介衔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親盟劫。 傳聞我的和親對象是個殘疾皇子夜牡,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容