RecyclerView 动态调整高度, 调整item高度

1. RecyclerView 高度动态调整 

solution ( RecyclerView的高度控制都在 LayoutManager 中)


LinearLayoutManager exceptionLayoutManager = new LinearLayoutManager(this){

            @Override
            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {

                    View view = recycler.getViewForPosition(0);
                    if (view != null) {
                        measureChild(view, widthSpec, heightSpec);
                        //int measuredWidth = View.MeasureSpec.getSize(widthSpec);
                        int measuredHeight = view.getMeasuredHeight();
                        int showHeight = measuredHeight * state.getItemCount();
                        if(state.getItemCount() >= 5){
                            showHeight = measuredHeight * 5;
                        }
                        setMeasuredDimension(widthSpec, showHeight);
                    }
            }
};

exceptionLayoutManager.setAutoMeasureEnabled(false);
exceptionListRecyclerview.setHasFixedSize(false);
exceptionListRecyclerview.setLayoutManager(exceptionLayoutManager);
exceptionListRecyclerview.setItemAnimator(new DefaultItemAnimator());

https://my.oschina.net/buobao/blog/651279

1.1
mLayoutManager.setAutoMeasureEnabled(false)
mList.setHasFixedSize(false)

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec,int heightSpec) {
    View view = recycler.getViewForPosition(0);
    measureChild(view, widthSpec, heightSpec);
    int measuredWidth = View.MeasureSpec.getSize(widthSpec);
    int measuredHeight = view.getMeasuredHeight();
    setMeasuredDimension(measuredWidth, measuredHeight);
}

1.2这里获取了view的高度,也就是item布局的高度,所以item的布局需要设定固定的高度,否则获取为0。其次,
这两个设置不能少,否则报错,这里和RecyclerView.onMeasure中的调用顺序有关,源码:

protected void onMeasure(int widthSpec, int heightSpec) {
    if (mLayout == null) {
        defaultOnMeasure(widthSpec, heightSpec);
        return;
    }
    if (mLayout.mAutoMeasure) {     //这里为true会进入该分支
        final int widthMode = MeasureSpec.getMode(widthSpec);
        final int heightMode = MeasureSpec.getMode(heightSpec);
        final boolean skipMeasure = widthMode == MeasureSpec.EXACTLY
                && heightMode == MeasureSpec.EXACTLY;
        mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);   //在调用mLayout的onMeasure方法时(被自定义复写的方法),mState.mItemCount为0,造成越界异常
        if (skipMeasure || mAdapter == null) {
            return;
        }
        if (mState.mLayoutStep == State.STEP_START) {
            dispatchLayoutStep1();
        }
        // set dimensions in 2nd step. Pre-layout should happen with old dimensions for
        // consistency
        mLayout.setMeasureSpecs(widthSpec, heightSpec);
        mState.mIsMeasuring = true;
        dispatchLayoutStep2();

        // now we can get the width and height from the children.
        mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);

        // if RecyclerView has non-exact width and height and if there is at least one child
        // which also has non-exact width & height, we have to re-measure.
        if (mLayout.shouldMeasureTwice()) {
            mLayout.setMeasureSpecs(
                    MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
            mState.mIsMeasuring = true;
            dispatchLayoutStep2();
            // now we can get the width and height from the children.
            mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
        }
    } else {
        if (mHasFixedSize) {   //这里不设置为false会造成与上面相同的问题
            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
            return;
        }
        // custom onMeasure
        if (mAdapterUpdateDuringMeasure) {
            eatRequestLayout();
            processAdapterUpdatesAndSetAnimationFlags();

            if (mState.mRunPredictiveAnimations) {
                mState.mInPreLayout = true;
            } else {
                // consume remaining updates to provide a consistent state with the layout pass.
                mAdapterHelper.consumeUpdatesInOnePass();
                mState.mInPreLayout = false;
            }
            mAdapterUpdateDuringMeasure = false;
            resumeRequestLayout(false);
        }

        if (mAdapter != null) {
            mState.mItemCount = mAdapter.getItemCount();
        } else {
            mState.mItemCount = 0;
        }
        eatRequestLayout();
        mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);   //在这里调用时mState.mItemCount才会有值,这与mLayout中获取当前item布局的方式有关:View view = recycler.getViewForPosition(0);
        resumeRequestLayout(false);
        mState.mInPreLayout = false; // clear
    }
}

2. 关于RecyclerView的宽高调整 https://blog.csdn.net/crazyman2010/article/details/54315109

设置ItemView的间隔高宽

重写ItemDecoration的getItemOffsets函数即可:

recycleview.addItemDecoration(new RecyclerView.ItemDecoration() {
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.set(4, 4, 4, 4);//设置itemView中内容相对边框左,上,右,下距离
    }
});

3. ItemView适应RecyclerView

RecyclerView大小固定的情况下,根据RecyclerView的宽高设置ItemView的宽高,以达到recyclerview刚好显示N行/列数据的目的: 
在原理是先计算出RecyclerView的宽高,然后在Adapter的onCreateViewHolder中设置view的高度: 
比如一个垂直列表,希望recyclerview刚好显示三行,这样写:

@Override
public ClubServiceAdapter.ServiceItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(布局文件, parent, false);
    view.getLayoutParams().height = mRecyclerViewHeight/3;
    return new ServiceItemViewHolder(view);
}

 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空白的泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值