RecyclerView 整理

  • 判斷是否滑動到最后 / 前的 Item
  • 添加 HeaderView 和 FooterView
  • ScrollView 嵌套情況下的問題
  • 數(shù)據(jù)源刷新的問題
  • item 局部刷新
  • 平滑的滑動置頂
  • ItemTouchHelper

參考 :
Android RecyclerView 使用完全解析 體驗(yàn)藝術(shù)般的控件
深入理解 RecyclerView 系列之一:ItemDecoration

開篇先說明一下吁朦,現(xiàn)在 RecyclerView 想必都很熟悉幔欧,我在項(xiàng)目里也對這個控件做過一些封裝滞欠、遇到過一些問題俺亮,這里僅做記錄笋熬。因?yàn)檫@次時間還是比較多术吝,所以打算深入一點(diǎn)研究學(xué)習(xí)弄痹、內(nèi)容也比較多所以分出了幾篇勾效,鏈接在上面嘹悼。

簡單初始化

//設(shè)置布局管理器
mRecyclerView.setLayoutManager(layout);
//設(shè)置adapter
mRecyclerView.setAdapter(adapter)
//設(shè)置Item增加、移除動畫
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割線
mRecyclerView.addItemDecoration(new DividerItemDecoration(
                getActivity(), DividerItemDecoration.HORIZONTAL_LIST));
  • 監(jiān)聽 Item 的點(diǎn)擊事件
    因?yàn)?RecyclerView 沒直接的事件可以監(jiān)聽层宫,需要自己去設(shè)置杨伙,
    我選擇在 RecyclerView.Adapter 中設(shè)置:
//在繼承了 RecyclerView.Adapter  的內(nèi)部類中
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    if (holder instanceof ViewHolder){
        //設(shè)置 TextView
        holder.textView.setText(data.get(position).getTitle());
        //設(shè)置 Item 的點(diǎn)擊事件
        holder.itemLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //自己定義的一個方法,將 position 傳出去
                onItemClick(position);
            }
        });
    }
}                                                                 
//重寫的 ViewHolder萌腿,使用了 ButterKnife限匣,但邏輯上沒有變化
class ViewHolder extends RecyclerView.ViewHolder{

    @BindView(R.id.news_item_title)
    TextView newsTitle;
    @BindView(R.id.news_item_img)
    ImageView newsImg;
    @BindView(R.id.news_item_layout)
    LinearLayout newsLayout;

    public ViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }
}

Item 的布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">

    <LinearLayout
        android:id="@+id/news_item_layout"
        android:layout_width="match_parent"
        android:layout_height="110dp"
        android:layout_marginBottom="2.5dp"
        android:layout_marginTop="2.5dp"
        android:elevation="4dp"
        android:background="@drawable/news_item_bg">
        <TextView
            android:textColor="#000"
            android:id="@+id/news_item_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="17dip"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="5dp"
            />
    </LinearLayout>
</LinearLayout>

還有一種方法就是使用 addOnItemTouchListener,通過觸摸坐標(biāo)來判斷
可以參考: RecyclerView 無法添加 onItemClickListener 最佳的高效解決方案

監(jiān)聽滑動


//OnScrollListener  是繼承自 RecyclerView.OnScrollListener 的內(nèi)部類毁菱,見下文
mNewsRecyclerView.addOnScrollListener(new OnScrollListener());

監(jiān)聽是否滑動到底部
繼承 RecyclerView.OnScrollListener米死,
onScrolled 獲取 RecyclerView 的最后一個 Item 的位置锌历,
onScrollStateChanged 判斷當(dāng)前是否滑動到最后一個 Item。

/**
  * 監(jiān)聽 RecyclerView 判斷是否滑到最后一個 Item
  */
class OnScrollListener extends RecyclerView.OnScrollListener{

  private int lastVisibleItem;

  /**
    * 判斷是否滑動了最后一個 Item
    * @param recyclerView
    * @param newState
    */
  @Override
  public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
   super.onScrollStateChanged(recyclerView, newState);
   if( (newState == RecyclerView.SCROLL_STATE_IDLE)
     &&(lastVisibleItem + 1 == mRecyclerViewAdapter.getItemCount())){
    
     //newState 為 0:當(dāng)前屏幕停止?jié)L動峦筒;
     //1:屏幕在滾動且用戶仍在觸碰或手指還在屏幕上究西;
     //2:隨用戶的操作,屏幕上產(chǎn)生的慣性滑動物喷;
     
    //在這里執(zhí)行刷新/加載更多的操作
    loadMore();
}

   /**
     * 在這里獲取到 RecyclerView 的最后一個 Item 的位置
     * @param recyclerView
     * @param dx
     * @param dy
     */
   @Override
   public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition();
  }
}

特別的是卤材,當(dāng) RecyclerView 實(shí)現(xiàn)了瀑布流
就是使用了 StaggeredGridLayoutManager 的時候峦失,因?yàn)?Item 是交錯的商膊,
所以不能使用上面的方法,而是要判斷 findLastVisibleItemPosition 返回的數(shù)組的最大值宠进,上面的 onScrolled 方法要修改為:

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);

    int [] lasPositions = new int[mStaggeredGridLayoutManager.getSpanCount()];
    int [] all = mStaggeredGridLayoutManager
                      .findLastVisibleItemPositions(lasPositions);
    lastVisibleItem = findMax(all);

}

private int findMax(int[] lastPositions) {
    int max = lastPositions[0];
    for (int value : lastPositions) {
        if (value > max) {
            max = value;
        }
    }
    return max;
}

添加 HeaderView 和 FooterView

  • 在 ViewHolder 中添加 HeaderView 和 FooterView
//當(dāng)前 item 的類型,0 為頭布局,1 為底部布局
public static final int TYPE_HEADER = 0;
public static final int TYPE_FOOTER = 1;
public static final int TYPE_NORMAL = 2;
//
private View mHeaderView;
private View mFooterView;
//
public void addHeaderView(View mHeaderView) {
    this.mHeaderView = mHeaderView;
}
public void addFooterView(View mFooterView) {
    this.mFooterView = mFooterView;
}
  • 通過設(shè)置 ItemViewType 來區(qū)分 HeaderView 和 FooterView
/**
 * 為每個 Item 設(shè)置類型
 * 如果頭布局不為空,則將第一個 Item 設(shè)為頭布局
 * @param position
 * @return
 */
@Override
public int getItemViewType(int position) {
    if (mHeaderView == null && mFooterView == null)
        return TYPE_NORMAL;
    if (mHeaderView != null && position == 0)
        return TYPE_HEADER;
    if (mFooterView != null && position == getItemCount() - 1)
        return TYPE_FOOTER;

    return TYPE_NORMAL;
}

如果 mHeaderView 不為空晕拆,則將第一個 ItemView 設(shè)為 HeaderView,
如果 mFooterView 不為空材蹬,將最后一個 ItemView 設(shè)為 FooterView实幕。

  • 創(chuàng)建 ItemView
/**
 * 創(chuàng)建布局的時候如果發(fā)現(xiàn)是頭布局直接返回
 * @param parent
 * @param viewType
 * @return
 */
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (mHeaderView != null && viewType == TYPE_HEADER){
        return new ViewHolder(mHeaderView);
    }
    if (mFooterView != null && viewType == TYPE_FOOTER){
        return new ViewHolder(mFooterView);
    }
    View v = LayoutInflater.from(getActivity())
            .inflate(R.layout.news_list_item,parent,false);
    ViewHolder viewHolder = new ViewHolder(v);
    return viewHolder;
}
/**
 * 只有當(dāng)前的 Item 的類型是 normal 時才執(zhí)行
 *  realPosition = position -1 是因?yàn)?0 被頭布局占用了
 * @param holder
 * @param position
 */
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    final int realPosition;
    if (mHeaderView != null)
        realPosition = position -1;
    else
        realPosition = position;

    if (getItemViewType(position) == TYPE_NORMAL){
        if (holder instanceof ViewHolder){
            holder.newsTitle.setText(data.get(realPosition).getTitle());
            Glide.with(getActivity()).load(data.get(realPosition).getImages())
                    .into(holder.newsImg);

            //設(shè)置 Item 的點(diǎn)擊事件
            holder.newsLayout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    OnItemClick(realPosition);
                }
            });
        }
    }
}
  • 相應(yīng)的修改
/**
 * 根據(jù)是否有設(shè)置頭布局等,判斷返回的個數(shù)
 * @return
 */
@Override
public int getItemCount() {
    if (news == null)
        return 0;
    else if (mHeaderView == null && mFooterView == null)
        return news.getStories().size();
    else if (mHeaderView == null && mFooterView != null)
        return news.getStories().size() + 1;
    else if (mHeaderView != null && mFooterView == null)
        return news.getStories().size() + 1;
    else if (mHeaderView != null && mFooterView != null)
        return news.getStories().size() + 2;

    return 0;
}
//繼承 RecyclerView.ViewHolder,使用 ButterKnife
class ViewHolder extends RecyclerView.ViewHolder{

    @BindView(R.id.news_item_title)
    TextView newsTitle;
    @BindView(R.id.news_item_img)
    ImageView newsImg;
    @BindView(R.id.news_item_layout)
    LinearLayout newsLayout;

    public ViewHolder(View itemView) {
        super(itemView);
        if (itemView == mHeaderView)
            return;
        if (itemView == mFooterView)
            return;
        ButterKnife.bind(this,itemView);
    }
}
  • 在 Activity 中調(diào)用
View banner = ......
mRecyclerViewAdapter.addHeaderView(banner);

關(guān)于滑動

  • 簡單的直接定位:
mLayoutManager.scrollToPositionWithOffset(position, 0);

缺點(diǎn)是體驗(yàn)不好堤器,沒有滑動的過程昆庇。

  • RecyclerView 的滑動方法
rv.scrollToPosition(index);
rv.scrollBy(int x, int y);

scrollToPosition() 將對應(yīng)的 item 滑動到屏幕內(nèi),當(dāng) item 變?yōu)榭梢姇r則停止滑動闸溃。
所以當(dāng)指定的 item 在當(dāng)前屏幕的下方時整吆,滑動后目標(biāo) item 會出現(xiàn)屏幕的最低下;當(dāng)指定 item 在屏幕可見時辉川,則完全沒有滑動表蝙。
很多時候這個方法是不符合我們預(yù)期的,一般是希望能將指定的 item 滑動到當(dāng)前的屏幕頂端或中間乓旗。
這時候可以配合 scrollBy() 來做一個判斷:

private void setSelectPosition(int index) {
    //當(dāng)前可見的第一項(xiàng)和最后一項(xiàng)
    int firstItem = linearLayoutManager.findFirstVisibleItemPosition();
    int lastItem = linearLayoutManager.findLastVisibleItemPosition();
    if (index <= firstItem) {
        //當(dāng)要置頂?shù)捻?xiàng)在當(dāng)前顯示的第一個項(xiàng)的前面時府蛇,直接調(diào)用沒有問題
        rv.scrollToPosition(index);
    } else if (index <= lastItem) {
        //當(dāng)要置頂?shù)捻?xiàng)已經(jīng)在屏幕上顯示時,計算需要滑動的距離
        int top = rv.getChildAt(index - firstItem).getTop();
        rv.scrollBy(0, top);
    } else {
        //當(dāng)指定的 item 在當(dāng)前顯示的最后一項(xiàng)的后面時
        //這時候一次的滑動不足以將指定 item 放到頂端
        rv.scrollToPosition(index);
        //記錄當(dāng)前需要在RecyclerView滾動監(jiān)聽里面繼續(xù)第二次滾動
        move = true;
    }
}
class RecyclerViewListener extends RecyclerView.OnScrollListener{
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            //在這里進(jìn)行第二次滾動
            if (move ){
                move = false;
                int n = mIndex - mLinearLayoutManager.findFirstVisibleItemPosition();
                if ( 0 <= n && n < mRecyclerView.getChildCount()){
                    //要移動的距離
                    int top = mRecyclerView.getChildAt(n).getTop();
                    mRecyclerView.scrollBy(0, top);
                }
            }
        }
    }

上面這個方面也是看到別人的實(shí)現(xiàn)的思路屿愚,雖然沒什么問題不過還是算是取巧的一種方法汇跨,僅記錄。
其實(shí) Stack Overflow 上已經(jīng)有了更好的答案 :RecyclerView - How to smooth scroll to top of item on a certain position?

  • 重寫 LinearLayoutManager
public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {

    public LinearLayoutManagerWithSmoothScroller(Context context) {
        super(context, VERTICAL, false);
    }

    public LinearLayoutManagerWithSmoothScroller(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    //重點(diǎn)方法
    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {

        //也就是說重點(diǎn)在于重寫 SmoothScroller,而滑動的調(diào)用為 startSmoothScroll()
        RecyclerView.SmoothScroller smoothScroller = new  TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);
        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return LinearLayoutManagerWithSmoothScroller.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference() {
            //將指定的 item 滑動至與屏幕的頂端對齊
            return SNAP_TO_START;
        }
    }
}

仔細(xì)看可以發(fā)現(xiàn)我們也可以選擇不重寫整個 LinearLayoutManager妆距,只要將 LinearSmoothScroller 的 getVerticalSnapPreference() 重寫也可以達(dá)到目的穷遂。

關(guān)于 getVerticalSnapPreference () 的源碼與注釋:

    /**
     * When scrolling towards a child view, this method defines whether we should align the top
     * or the bottom edge of the child with the parent RecyclerView.
     *
     * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
     * @see #SNAP_TO_START
     * @see #SNAP_TO_END
     * @see #SNAP_TO_ANY
     */
    protected int getVerticalSnapPreference() {
        return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
                mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
    }

返回的值決定了指定 item 的對齊方式,與頂部對齊 / 底部對齊娱据。
所以最終代碼:

//初始化過程
mLayoutManager= new LinearLayoutManager(getActivity());
mSmoothScroller = new LinearSmoothScroller(getActivity()) {
    @Override protected int getVerticalSnapPreference() {
        return LinearSmoothScroller.SNAP_TO_START;
     }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        return mLayoutManager.computeScrollVectorForPosition(targetPosition);
    }
};
mRvRetail.setLayoutManager(mLayoutManager);

//移動
mSmoothScroller.setTargetPosition(position);
mLayoutManager.startSmoothScroll(mSmoothScroller);

這樣就可以實(shí)現(xiàn)平滑的滑動了蚪黑。

與 ScrollView 嵌套時慣性滑動失效

猜測是由于滑動的時候,ScrollView 將事件分發(fā)給了 RecyclerView,所以這個時候是 rv 在滑動祠锣;
當(dāng)快速滑動并離開屏幕的時候酷窥,按預(yù)期是應(yīng)該有一段慣性般滑動、緩慢停止的過程伴网,然而這時候應(yīng)該是 ScrollView 攔截了這個 ACTION_UP 的事件蓬推,導(dǎo)致 RecyclerView 無法繼續(xù)滑動。
解決這個問題可以從 RecyclerView 入手澡腾,若 RecyclerView 不再響應(yīng)事件沸伏,將事件交給 ScrollView 即可:

mLayoutManager = new LinearLayoutManager(mContext){
    @Override
    public boolean canScrollVertically() {
        return false;
    }
};
mRv.setLayoutManager(mLayoutManager);

刷新數(shù)據(jù)源導(dǎo)致的問題

比較常見是在刪除 item 的時候,可能會出現(xiàn) item 的下標(biāo)沒有刷新动分、位置錯位的問題毅糟。
更新了數(shù)據(jù)源之后最保險的方法是調(diào)用 notifyDataSetChanged() 去刷新所有的數(shù)據(jù),問題是如果只更新了少量的數(shù)據(jù)或者想要保留刪除/添加 item 的動畫澜公,這個方法都不能滿足要求姆另。
所以我們需要調(diào)用 notifyItemRemoved(position)notifyItemInserted(position),這時候 item 的內(nèi)容已經(jīng)刷新坟乾、并且?guī)в袆赢嬓Ч75侨绻莿h除 item 的操作,上面說的下標(biāo)沒有刷新甚侣、錯位的問題就出現(xiàn)了明吩,所以接下來要調(diào)用 notifyItemRangeChanged(position, itemSize) 將可能出現(xiàn)問題的 item 都刷一遍,所以 itemSize 常取 list.size()殷费。

item 的局部刷新

說起 RecyclerView 的局部刷新印荔,一般都是說到 notifyItemChanged(int positon) 即只刷新指定的 item 的布局,但是有時候需要針對 item 的部分控件進(jìn)行刷新详羡。
比如一個 item 里有一張圖片仍律,單調(diào)用 notifyItemChanged 的時候圖片會去重新加載,就導(dǎo)致了重復(fù)加載同樣的圖片而出現(xiàn)圖片閃爍的問題殷绍,所以這時候我們需要針對 item 去刷新改變的部分染苛、保留不變的部分鹊漠。
這里用上了

@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
  super.onBindViewHolder(holder, position, payloads);
}

notifyItemChanged(int position, Object payload)
看到這兩個方法其實(shí)方法已經(jīng)很明顯了主到,調(diào)用 notifyItemChanged()可以傳遞一個 payload 到 onBindViewHolder 方法里面,這時候就可以通過傳遞過來的數(shù)據(jù)類型去刷新不同的控件躯概,沒有刷新到的控件將會用 ViewHolder 的實(shí)例來展示登钥。

ItemTouchHelper

ItemTouchHelper 是 RecyclerView 中輔助滑動和拖拽的實(shí)用工具類,一般用來做拖拽改變排序娶靡、滑動刪除功能牧牢。

ItemTouchHelper helper = new ItemTouchHelper(callback);
helper.attachToRecyclerView(recyclerView);

ItemTouchHelper 的構(gòu)造方法需要一個傳入 ItemTouchHelper.Callback 的實(shí)例,所以重點(diǎn)就在于這個 Callback 里的幾個方法。

class TestHelperCallback extends ItemTouchHelper.Callback{

  private ItemMoveListener mListener;

  public TestHelperCallback(){}

  public TestHelperCallback(ItemMoveListener listener){
    mListener = listener;
  }

  @Override
  public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    //兩個 flags 為 0 則無法拖動
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;//允許上下滑動
    int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//允許左右滑動
    //生成并返回
    int flags = makeMovementFlags(dragFlags, swipeFlags);
    return flags;
  }

  @Override
  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    //拖拽的回調(diào)
    if (mListener != null){
      return mListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
    }
    return false;
  }


  @Override
  public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    //左右滑動的回調(diào)
    int position = viewHolder.getAdapterPosition();
    if (mListener != null){
      mListener.onItemDelete(position);
    }
  }

  @Override
  public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
    //在滑動和拖拽的過程中會被調(diào)用去繪制動畫塔鳍,重寫這里可以實(shí)現(xiàn)自己的動畫
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
         //左右滑動的同時改變 item 的透明度
         final float alpha = 1 - Math.abs(dX) / (float)viewHolder.itemView.getWidth();
         viewHolder.itemView.setAlpha(alpha);//透明度
         viewHolder.itemView.setTranslationX(dX);//滑動
     }
  }

  @Override
  public boolean isLongPressDragEnabled() {
    //是否可以長按拖拽
    return true;
  }
}

public interface ItemMoveListener {
   boolean onItemMove(int fromPosition, int toPosition);
   boolean onItemDelete(int position);
}

通過接口 ItemMoveListener 把回調(diào)放出去伯铣,接下來用 Adapter 實(shí)現(xiàn)并處理回調(diào):

class ItemMoveRecyclerAdapter extends CommonRecyclerAdapter<String> implements ItemMoveListener{

  public ItemMoveRecyclerAdapter(Context context, List dataList, int layoutId) {
    super(context, dataList, layoutId);
  }

  @Override
  public void convert(CommonRecyclerViewHolder holder, int position, String o) {
  }

  @Override
  public void onItemClick(CommonRecyclerViewHolder holder, int position, String o) {
  }

  @Override
  public boolean onItemMove(int fromPosition, int toPosition) {
    //交換數(shù)據(jù)
    Collections.swap(mDataList, fromPosition, toPosition);
    //刷新
    notifyItemMoved(fromPosition, toPosition);
    notifyItemRangeChanged(Math.min(fromPosition,toPosition),getItemCount());
    return true;
  }

  @Override
  public boolean onItemDelete(int position) {
    mDataList.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position,getItemCount());
    return false;
  }
}

CommonRecyclerAdapter 是項(xiàng)目封裝的 Adapter,這里不是重點(diǎn)轮纫。
onItemMove()中依次調(diào)用了 notifyItemMoved()notifyItemRangeChanged()腔寡,防止在移動過后 item 的下標(biāo)錯亂。
onItemDelete () 中同理掌唾。
上面代碼基本就是拖拽排序和滑動刪除的代碼放前,因?yàn)楹芎唵尉蜎]有多分析,因?yàn)橐婚_始是想用 ItemTouchHelper 仿照 QQ 的側(cè)滑按鈕糯彬,但是看了一圈發(fā)現(xiàn)好像沒辦法用 ItemTouchHelper 實(shí)現(xiàn)凭语。

clipToPadding 屬性

android:clipToPadding 屬性決定子 View 是否可以在 父布局的 padding 中繪制。
在 RecyclerView 中子 View 即 item撩扒,該屬性為false 時似扔,RecyclerView 的 padding 會被 item 遮住。
比如我們在 RecyclerView 的底部上懸浮一個按鈕搓谆,按鈕會擋住下方的 item虫几,clipToPadding + paddingBottom 可以實(shí)現(xiàn)在 RecyclerView 拉倒底部的時候?yàn)閼腋“粹o留出空間。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挽拔,一起剝皮案震驚了整個濱河市辆脸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌螃诅,老刑警劉巖啡氢,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異术裸,居然都是意外死亡倘是,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門袭艺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搀崭,“玉大人,你說我怎么就攤上這事猾编×龆茫” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵答倡,是天一觀的道長轰传。 經(jīng)常有香客問我,道長瘪撇,這世上最難降的妖魔是什么获茬? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任港庄,我火速辦了婚禮,結(jié)果婚禮上恕曲,老公的妹妹穿的比我還像新娘鹏氧。我一直安慰自己,他們只是感情好佩谣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布度帮。 她就那樣靜靜地躺著,像睡著了一般稿存。 火紅的嫁衣襯著肌膚如雪笨篷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天瓣履,我揣著相機(jī)與錄音率翅,去河邊找鬼。 笑死袖迎,一個胖子當(dāng)著我的面吹牛冕臭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播燕锥,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辜贵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了归形?” 一聲冷哼從身側(cè)響起托慨,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暇榴,沒想到半個月后厚棵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔼紧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年婆硬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奸例。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡彬犯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出查吊,到底是詐尸還是另有隱情谐区,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布菩貌,位于F島的核電站卢佣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏箭阶。R本人自食惡果不足惜虚茶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仇参。 院中可真熱鬧嘹叫,春花似錦、人聲如沸诈乒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怕磨。三九已至喂饥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肠鲫,已是汗流浹背员帮。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留导饲,地道東北人捞高。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像渣锦,于是被迫代替她去往敵國和親硝岗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

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

  • 【Android 控件 RecyclerView】 概述 RecyclerView是什么 從Android 5.0...
    Rtia閱讀 307,522評論 27 439
  • 又到了更新博文的時間了袋毙,最近在看一本很不錯的心理學(xué)書籍型檀,名字叫做 《拖延心理學(xué)》,封面長下面這樣子 書的內(nèi)容主要是...
    ec95b5891948閱讀 57,482評論 38 472
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,162評論 25 707
  • ListView作為一個流布局控件是一個比較老的資格了听盖。RecyclerView作為Desgin設(shè)計里面的一個新空...
    mouekz閱讀 500評論 0 1
  • 事實(shí)證明媳溺,感情其實(shí)很脆弱月幌,甚至是不堪一擊,唯有努力才最安心悬蔽。 她是我大學(xué)里要好的朋友扯躺,但是最近遇到了感情的滑鐵...
    不將就iii閱讀 452評論 0 0