RecyclerView

ItemDecoration

RecyclerView.ItemDecoration注釋是這樣寫(xiě)的

 /**
     * An ItemDecoration allows the application to add a special drawing and layout offset
     * to specific item views from the adapter's data set. This can be useful for drawing dividers
     * between items, highlights, visual grouping boundaries and more.
     *
     * <p>All ItemDecorations are drawn in the order they were added, before the item
     * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()}
     * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView,
     * RecyclerView.State)}.</p>
     */

允許程序添加特殊的圖形和布局偏移量到適配器中指定的項(xiàng)目視圖,可以用于項(xiàng)目視圖之間繪制分割線折砸、高亮等等。還指出了在項(xiàng)目之前調(diào)用onDraw() 之后調(diào)用onDrawOver;
三個(gè)重要方法的重寫(xiě)

public class ItemDecoration extends RecyclerView.ItemDecoration{

    //通過(guò)該方法愕贡,在Canvas上繪制內(nèi)容济舆,在繪制Item之前調(diào)用抵怎。(如果沒(méi)有通過(guò)getItemOffsets設(shè)置偏移的話,Item的內(nèi)容會(huì)將其覆蓋)
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
    }
    //通過(guò)該方法玫坛,在RecyclerView的Canvas上繪制內(nèi)容,在Item之后調(diào)用结笨。(畫(huà)的內(nèi)容會(huì)覆蓋在item的上層)
    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
    }

    //設(shè)置偏移量
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
    }
}

常見(jiàn)的懸浮粘性頭部

ItemDecoration.png
public abstract class GroupHeadItemDecoration<T> extends RecyclerView.ItemDecoration {

    private Context mContext;
    private List<T> tags;
    private int groupHeaderHeight;
    private int groupHeaderLeftPadding;
    private Paint mPaint;
    private TextPaint mTextPaint;
    private boolean isStickHead = true;//是否是粘性頭部

    public GroupHeadItemDecoration(Context context, List<T> tags) {
        mContext = context;
        this.tags = tags;
        groupHeaderHeight = dp2px(context, 20);
        groupHeaderLeftPadding = dp2px(context,10);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.parseColor("#FFEEEEEE"));

        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(Color.parseColor("#FF999999"));
        mTextPaint.setTextSize(sp2px(context, 14));
    }

    public abstract String getTag(T t);//實(shí)現(xiàn)該抽象方法,獲得分類的頭部

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        for (int i = 0;i<parent.getChildCount();i++){
            View view = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(view);
            String tag = getTag(tags.get(position));
            //如果位置等于0 或者頭部的tag不等于上一個(gè)tag湿镀,繪制分組頭部
            if(position == 0 || !tag.equals(getTag(tags.get(position-1)))){
                drawGroupHeader(c,parent,view,tag);
            }
        }
    }

    /*
    *該方法同樣也是用來(lái)繪制的炕吸,但是它在ItemDecoration的onDraw()方法和ItemView的onDraw()完成后才執(zhí)行。
    * 所以其繪制的內(nèi)容會(huì)遮擋在RecyclerView上肠骆,因此我們可以在該方法中繪制分組索引列表中懸浮的GroupHeader算途,
    * 也就是在列表頂部隨著列表滾動(dòng)切換的GroupHeader
     */

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
        if (!isStickHead) {
            return;
        }
        if(tags.size()==0){
            return;
        }
        int position = ((LinearLayoutManager)(parent.getLayoutManager())).findFirstVisibleItemPosition();
        String tag = getTag(tags.get(position));
        View view = parent.findViewHolderForAdapterPosition(position).itemView;

        boolean flag = false;
        if((position+1)<tags.size()&&!tag.equals(getTag(tags.get(position+1)))){
            if (view.getBottom() <= groupHeaderHeight) {
                c.save();
                flag = true;
                c.translate(0, view.getHeight() + view.getTop() - groupHeaderHeight);
            }
        }
        drawSuspensionGroupHeader(c, parent, tag);

        if(flag){
            c.restore();
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);

        RecyclerView.LayoutManager manager = parent.getLayoutManager();

        //只處理線性垂直類型的列表
        if ((manager instanceof LinearLayoutManager)
                && LinearLayoutManager.VERTICAL != ((LinearLayoutManager) manager).getOrientation()) {
            return;
        }

        if(tags == null || tags.size() == 0){
            return;
        }

        int position = parent.getChildAdapterPosition(view);
        if(position == 0||!getTag(tags.get(position)).equals(getTag(tags.get(position-1)))){
            outRect.set(0,groupHeaderHeight,0,0);
        }
    
    private void drawGroupHeader(Canvas c, RecyclerView parent, View view, String tag){
        int[] params = getGroupHeaderCoordinate(parent, view);
        c.drawRect(params[0], params[1], params[2], params[3], mPaint);
        int x = params[0] + groupHeaderLeftPadding;
        int y = params[1] + (groupHeaderHeight + getTextHeight(mTextPaint, tag)) / 2;
        c.drawText(tag,x,y,mTextPaint);
    }

    public int[] getGroupHeaderCoordinate(RecyclerView parent, View view) {
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
        int left = parent.getPaddingLeft();
        int right = parent.getWidth()-parent.getPaddingRight();
        int bottom = view.getTop() - params.topMargin;
        int top = bottom - groupHeaderHeight;
        return new int[]{left,top,right,bottom};
    }


    public int[] getSuspensionGroupHeaderCoordinate(RecyclerView parent) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        int bottom = groupHeaderHeight;
        int top = 0;
        return new int[]{left, top, right, bottom};
    }

    private void drawSuspensionGroupHeader(Canvas c, RecyclerView parent, String tag) {
        int[] params = getSuspensionGroupHeaderCoordinate(parent);
        c.drawRect(params[0], params[1], params[2], params[3], mPaint);
        int x = params[0] + groupHeaderLeftPadding;
        int y = params[1] + (groupHeaderHeight + getTextHeight(mTextPaint, tag)) / 2;
        c.drawText(tag, x, y, mTextPaint);
    }

    public static int getTextHeight(TextPaint textPaint, String text) {
        Rect bounds = new Rect();
        textPaint.getTextBounds(text, 0, text.length(), bounds);
        return bounds.height();
    }
源碼分析

RecyclerView的itemView的一些測(cè)量小細(xì)節(jié),會(huì)通過(guò)getItemDecorInsetsForChild(child)調(diào)用裝飾物的getItemOffsets蚀腿,獲得區(qū)域大小嘴瓤,累加寬高數(shù)值,然后完成測(cè)量

 public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
           // 累加當(dāng)前ItemDecoration 4個(gè)屬性值
            widthUsed += insets.left + insets.right;
            heightUsed += insets.top + insets.bottom;

            final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),
                    getPaddingLeft() + getPaddingRight()
                            + lp.leftMargin + lp.rightMargin + widthUsed, lp.width,
                    canScrollHorizontally());
            final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(),
                    getPaddingTop() + getPaddingBottom()
                            + lp.topMargin + lp.bottomMargin + heightUsed, lp.height,
                    canScrollVertically());
            if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) {
                child.measure(widthSpec, heightSpec);
            }
        }


Rect getItemDecorInsetsForChild(View child) {
        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
        if (!lp.mInsetsDirty) {
            return lp.mDecorInsets;
        }

        if (mState.isPreLayout() && (lp.isItemChanged() || lp.isViewInvalid())) {
            // changed/invalid items should not be updated until they are rebound.
            return lp.mDecorInsets;
        }
        final Rect insets = lp.mDecorInsets;
        insets.set(0, 0, 0, 0);
        final int decorCount = mItemDecorations.size();
        for (int i = 0; i < decorCount; i++) {
            mTempRect.set(0, 0, 0, 0);
           // 獲取getItemOffsets() 中設(shè)置的值
            mItemDecorations.get(i).getItemOffsets(mTempRect, child, this, mState);
            insets.left += mTempRect.left;
            insets.top += mTempRect.top;
            insets.right += mTempRect.right;
            insets.bottom += mTempRect.bottom;
        }
        lp.mInsetsDirty = false;
        return insets;
    }

ItemTouchHelper

RecyclerView通過(guò)系統(tǒng)的API就可以實(shí)現(xiàn)拖拽排序或者刪除的效果

ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
            @Override
            public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                return 0;
            }

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

            }
        });
        helper.attachToRecyclerView(rv);

實(shí)現(xiàn) ItemTouchHelper.Callback 接口后有三個(gè)方法需要重寫(xiě)
1.getMovementFlags:設(shè)置滑動(dòng)類型的標(biāo)記
需要設(shè)置兩種類型的 flag 莉钙,即 dragFlags 和 swipeFlags廓脆,拖拽標(biāo)記和滑動(dòng)標(biāo)記
最后需要調(diào)用 makeMovementFlags(dragFlags, swipeFlags) 方法來(lái)合成返回
2.onMove: 當(dāng)用戶拖拽列表某個(gè) item 時(shí)會(huì)回調(diào)。很明顯磁玉,拖拽排序的代碼應(yīng)該在這個(gè)方法中實(shí)現(xiàn)停忿。
3.onSwiped:當(dāng)用戶滑動(dòng)列表某個(gè) item 時(shí)會(huì)回調(diào)。所以側(cè)滑刪除的代碼應(yīng)該在這個(gè)方法中實(shí)現(xiàn)蚊伞。

ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
            //通過(guò)返回值來(lái)設(shè)置是否處理某次拖曳或者滑動(dòng)事件
            @Override
            public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                if(recyclerView.getLayoutManager() instanceof GridLayoutManager){
                    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN
                             | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                    int swipeFlags = 0;
                    return makeMovementFlags(dragFlags,swipeFlags);
                }else {
                    int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN;
                    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
                    return makeMovementFlags(dragFlags,swipeFlags);
                }

            }

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                int fromposition = viewHolder.getAdapterPosition();
                int toposition = target.getAdapterPosition();

                if(fromposition < toposition){
                    for(int i = fromposition;i<toposition;i++){
                        Collections.swap(list,i,i+1);
                    }
                }else {
                    for(int i = fromposition;i > toposition;i--){
                        Collections.swap(list,i,i-1);
                    }
                }
                mAdapter.notifyItemMoved(fromposition,toposition);
                return true;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                //滑動(dòng)刪除的回調(diào) 只要是linearlayoutmanager的時(shí)候

                int adapterPosition = viewHolder.getAdapterPosition();
                mAdapter.notifyItemRemoved(adapterPosition);
                list.remove(adapterPosition);
                //同時(shí)也不要忘了修改一下 getMovementFlags() 方法席赂,以便能夠相應(yīng)滑動(dòng)事件 
                //int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;

            }

            //我們發(fā)現(xiàn)還有一些不完美的地方:比如當(dāng)用戶在拖拽排序的時(shí)候,可以改變當(dāng)前拖拽 item 的透明度时迫,這樣就可以和其他 item 區(qū)分開(kāi)來(lái)了颅停。
            // 那么,我們需要去重寫(xiě) onSelectedChanged
           @Override
            public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
                //當(dāng)長(zhǎng)按 item 剛開(kāi)始拖曳的時(shí)候調(diào)用
                if(actionState!=ItemTouchHelper.ACTION_STATE_IDLE){//拖拽或刪除結(jié)束
                    viewHolder.itemView.setBackgroundColor(Color.YELLOW);
                }
                super.onSelectedChanged(viewHolder, actionState);
            }


            @Override
            public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                //當(dāng)完成拖曳手指松開(kāi)的時(shí)候調(diào)用
                super.clearView(recyclerView, viewHolder);
                viewHolder.itemView.setBackgroundColor(getResources().getColor(R.color.colorAccent));
            }
}

SnapHelper

RecyclerView在24.2.0版本中新增了SnapHelper這個(gè)輔助類掠拳,用于輔助RecyclerView在滾動(dòng)結(jié)束時(shí)將Item對(duì)齊到某個(gè)位置癞揉。特別是列表橫向滑動(dòng)時(shí),很多時(shí)候不會(huì)讓列表滑到任意位置溺欧,而是會(huì)有一定的規(guī)則限制喊熟,這時(shí)候就可以通過(guò)SnapHelper來(lái)定義對(duì)齊規(guī)則了。

LinearSnapHelper&PagerSnapHelper是抽象類SnapHelper的具體實(shí)現(xiàn)姐刁。
LinearSnapHelper 可以滑動(dòng)多頁(yè)
PagerSnapHelper 每次只能滑動(dòng)一頁(yè)

代碼比較簡(jiǎn)單

LinearSnapHelper linearSnapHelper = new LinearSnapHelper();
linearSnapHelper.attachToRecyclerView(mRv)

源碼分析

SnapHelper是一個(gè)抽象類

public abstract class SnapHelper extends RecyclerView.OnFlingListener{
        /**
     * Override this method to snap to a particular point within the target view or the container
     * view on any axis.
     * <p>
     * This method is called when the {@link SnapHelper} has intercepted a fling and it needs
     * to know the exact distance required to scroll by in order to snap to the target view.
     *
     * @param layoutManager the {@link RecyclerView.LayoutManager} associated with the attached
     *                      {@link RecyclerView}
     * @param targetView the target view that is chosen as the view to snap
     *
     * @return the output coordinates the put the result into. out[0] is the distance
     * on horizontal axis and out[1] is the distance on vertical axis.
     */
    @SuppressWarnings("WeakerAccess")
    @Nullable
    public abstract int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager,
            @NonNull View targetView);

    /**
     * Override this method to provide a particular target view for snapping.
     * <p>
     * This method is called when the {@link SnapHelper} is ready to start snapping and requires
     * a target view to snap to. It will be explicitly called when the scroll state becomes idle
     * after a scroll. It will also be called when the {@link SnapHelper} is preparing to snap
     * after a fling and requires a reference view from the current set of child views.
     * <p>
     * If this method returns {@code null}, SnapHelper will not snap to any view.
     *
     * @param layoutManager the {@link RecyclerView.LayoutManager} associated with the attached
     *                      {@link RecyclerView}
     *
     * @return the target view to which to snap on fling or end of scroll
     */
    @SuppressWarnings("WeakerAccess")
    @Nullable
    public abstract View findSnapView(LayoutManager layoutManager);

    /**
     * Override to provide a particular adapter target position for snapping.
     *
     * @param layoutManager the {@link RecyclerView.LayoutManager} associated with the attached
     *                      {@link RecyclerView}
     * @param velocityX fling velocity on the horizontal axis
     * @param velocityY fling velocity on the vertical axis
     *
     * @return the target adapter position to you want to snap or {@link RecyclerView#NO_POSITION}
     *         if no snapping should happen
     */
    public abstract int findTargetSnapPosition(LayoutManager layoutManager, int velocityX,
            int velocityY);
}

三個(gè)主要的抽象方法

findTargetSnapPosition

該方法會(huì)根據(jù)觸發(fā)Fling操作的速率(參數(shù)velocityX和參數(shù)velocityY)來(lái)找到RecyclerView需要滾動(dòng)到哪個(gè)位置芥牌,該位置對(duì)應(yīng)的ItemView就是那個(gè)需要進(jìn)行對(duì)齊的列表項(xiàng)。我們把這個(gè)位置稱為targetSnapPosition聂使,對(duì)應(yīng)的View稱為targetSnapView壁拉。如果找不到targetSnapPosition拐叉,就返回RecyclerView.NO_POSITION。

findSnapView

該方法會(huì)找到當(dāng)前l(fā)ayoutManager上最接近對(duì)齊位置的那個(gè)view扇商,該view稱為SanpView,對(duì)應(yīng)的position稱為SnapPosition宿礁。如果返回null案铺,就表示沒(méi)有需要對(duì)齊的View,也就不會(huì)做滾動(dòng)對(duì)齊調(diào)整梆靖。

calculateDistanceToFinalSnap

這個(gè)方法會(huì)計(jì)算第二個(gè)參數(shù)對(duì)應(yīng)的ItemView當(dāng)前的坐標(biāo)與需要對(duì)齊的坐標(biāo)之間的距離控汉。該方法返回一個(gè)大小為2的int數(shù)組,分別對(duì)應(yīng)x軸和y軸方向上的距離返吻。

SnapHelper實(shí)現(xiàn)了OnFlingListener這個(gè)接口姑子,該接口中的onFling()方法會(huì)在RecyclerView觸發(fā)Fling操作時(shí)調(diào)用。在onFling()方法中判斷當(dāng)前方向上的速率是否足夠做滾動(dòng)操作测僵,如果速率足夠大就調(diào)用snapFromFling()方法實(shí)現(xiàn)滾動(dòng)相關(guān)的邏輯街佑。在snapFromFling()方法中會(huì)創(chuàng)建一個(gè)SmoothScroller,并且根據(jù)速率計(jì)算出滾動(dòng)停止時(shí)的位置捍靠,將該位置設(shè)置給SmoothScroller并啟動(dòng)滾動(dòng)沐旨。而滾動(dòng)的操作都是由SmoothScroller全權(quán)負(fù)責(zé),它可以控制Item的滾動(dòng)速度(剛開(kāi)始是勻速)榨婆,并且在滾動(dòng)到targetSnapView被layout時(shí)變換滾動(dòng)速度(轉(zhuǎn)換成減速)磁携,以讓滾動(dòng)效果更加真實(shí)。

讓你明明白白的使用RecyclerView——SnapHelper詳解

DiffUtil

它主要是為了配合 RecyclerView 使用良风,通過(guò)比對(duì)新谊迄、舊兩個(gè)數(shù)據(jù)集的差異,生成舊數(shù)據(jù)到新數(shù)據(jù)的最小變動(dòng)烟央,然后對(duì)有變動(dòng)的數(shù)據(jù)項(xiàng)统诺,進(jìn)行局部刷新。

需要關(guān)注的是兩個(gè)類DiffUtil.Callback,DiffUtil.DiffResult
基本的使用方法是

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(mDiffCallback);
diffResult.dispatchUpdatesTo(mAdapter);

代碼上可已看出更多的是diffcallback的實(shí)現(xiàn),四個(gè)重寫(xiě)方法

  @Override
            public int getOldListSize() {
                return 0;//舊數(shù)據(jù)集的size
            }

            @Override
            public int getNewListSize() {
                return 0;//新數(shù)據(jù)集的size
            }

            @Override
            public boolean areItemsTheSame(int i, int i1) {
                return false;//同一個(gè)Item
            }

            @Override
            public boolean areContentsTheSame(int i, int i1) {
                return false;//如果是通一個(gè)Item吊档,此方法用于判斷是否同一個(gè) Item 的內(nèi)容也相同篙议。
            }

不過(guò),需要注意是子線程中去計(jì)算oldlist與newlist的差異

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市怠硼,隨后出現(xiàn)的幾起案子鬼贱,更是在濱河造成了極大的恐慌,老刑警劉巖香璃,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件这难,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡葡秒,警方通過(guò)查閱死者的電腦和手機(jī)姻乓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門嵌溢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蹋岩,你說(shuō)我怎么就攤上這事赖草。” “怎么了剪个?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵秧骑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我扣囊,道長(zhǎng)乎折,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任侵歇,我火速辦了婚禮骂澄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惕虑。我一直安慰自己坟冲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布枷遂。 她就那樣靜靜地躺著樱衷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酒唉。 梳的紋絲不亂的頭發(fā)上矩桂,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音痪伦,去河邊找鬼侄榴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛网沾,可吹牛的內(nèi)容都是我干的癞蚕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辉哥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桦山!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起醋旦,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恒水,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后饲齐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體钉凌,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年捂人,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了御雕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矢沿。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酸纲,靈堂內(nèi)的尸體忽然破棺而出捣鲸,到底是詐尸還是另有隱情,我是刑警寧澤闽坡,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布摄狱,位于F島的核電站,受9級(jí)特大地震影響无午,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祝谚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一宪迟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧交惯,春花似錦次泽、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至只锻,卻和暖如春玖像,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背齐饮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工捐寥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祖驱。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓握恳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親捺僻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乡洼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 主要是在使用 RecyclerView 過(guò)程中遇到的細(xì)碎問(wèn)題和解決方案。 簡(jiǎn)單使用 LinearLayoutMan...
    三流之路閱讀 3,850評(píng)論 0 5
  • 很久沒(méi)有寫(xiě)Android控件了匕坯,正好最近項(xiàng)目有個(gè)自定義控件的需求束昵,整理了下做個(gè)總結(jié),主要是實(shí)現(xiàn)類似于抖音翻頁(yè)的效果...
    juexingzhe閱讀 1,310評(píng)論 1 5
  • 基本使用RecyclerView的基本使用并不復(fù)雜醒颖,只需要提供一個(gè)RecyclerView.Apdater的實(shí)現(xiàn)用...
    龐哈哈哈12138閱讀 5,972評(píng)論 2 46
  • 本文所講RecyclerView 是來(lái)自support 庫(kù) 26 版本妻怎,本文主要來(lái)源于自身開(kāi)發(fā)及組內(nèi)同事遇到問(wèn)...
    freddyyao閱讀 18,033評(píng)論 6 86
  • #幸福是需要修出來(lái)的~每天進(jìn)步1%~幸福實(shí)修08班~11賈春芬-杭州#20170824(67/99) 【幸福三朵玫...
    chfenj閱讀 113評(píng)論 0 1