【问题标题】:RecyclerView row item layout not keeping dimensions defined in XMLRecyclerView 行项目布局不保持 XML 中定义的尺寸
【发布时间】:2017-11-02 12:04:13
【问题描述】:

我正在创建自定义 LinearLayout 以用作 RecyclerView 中的行项目。有两个片段使用两个 RecyclerView 和两个适配器,使用 XML 定义的一个布局。在调整行项大小时,两个片段都显示出相同的异常行为,但这是可以理解的,因为它们使用相同的布局文件和几乎相同的稍作修改的适配器/片段代码。

这是布局文件 pool_layout.xml :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:orientation="vertical"
    android:paddingLeft="@dimen/betPool_padding_horizontal"
    android:paddingRight="@dimen/betPool_padding_horizontal"
    android:paddingTop="@dimen/betPool_padding_vertical"
    android:layout_margin="@dimen/courseRace_margin"
    android:id="@+id/stakepool_background">

<TextView
    android:id="@+id/stakepool_id"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone" />

<TextView
    android:id="@+id/stakepool_name"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="@dimen/betPool_text_size"
    />

</LinearLayout>

包含 LinearLayout 的高度设置为 100dp,宽度设置为 match_parent,但 RecyclerView 显示的视图具有不同的宽度,每次重绘视图时都会发生变化。

这是 LinearLayout 的父级,片段的 RecyclerView 由 XML 定义:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pools_frag"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/brb_cyan"
    tools:context="com.ineda.terminal.fragments.pools.PoolsFragment">


<!-- TODO: Update blank fragment layout -->
<android.support.v7.widget.RecyclerView
    android:id="@+id/pools_recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" />


<TextView
    android:id="@+id/overlay"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:alpha="0.5"
    android:background="@color/md_grey_200"
    android:clickable="true"
    android:gravity="center"
    android:textColor="@color/md_white_1000"
    android:visibility="gone" />


</FrameLayout>

此宽度也设置为 match_parent,它的父级(不包括在内)由具有相对布局的 main_activity XML 定义,因此视图宽度应该按照定义的片段宽度调整大小在 main_activity 减去边距等,但事实并非如此。

public class PoolsFragment extends Fragment {

    public static final String POOL_SELECTED = "com.ineda.terminal.fragments.ppol.POOL_SELECTED";

    private Context context;
    private RecyclerView mRecyclerView;
    private PoolsAdapter mAdapter;
    private List<Pool> poolList = new ArrayList<>();
    private Pool currentPool;
    private TextView overlay;

    private Pool previousSelection;


    public PoolsFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        context = getContext();
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.pools_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mAdapter = new PoolsAdapter(poolList, context);
        overlay = view.findViewById(R.id.overlay);
        overlay.setOnClickListener(new View.OnClickListener() {


        mRecyclerView = (RecyclerView)     view.findViewById(R.id.pools_recyclerView);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setAdapter(mAdapter);

}

片段代码,以防您认为它相关但我怀疑它不相关。

适配器代码:

public class PoolsAdapter extends RecyclerView.Adapter<PoolsAdapter.holder> {
    private static OnPoolClickListener OnPoolClickListener;
    private List<Pool> pools;
    private Context context;
    private View previousSelectedPool;
    private Pool currentPool;
    private boolean initialised;

    public PoolsAdapter(List<Pool> list, Context context) {
        this.pools = list;
        this.context = context;
    }


@Override
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new holder(new StakePoolButton(context));
}

@Override
public void onBindViewHolder(final holder holder, final int position) {

    currentPool = pools.get(position);
    holder.button.getButtonText().setText(pools.get(position).code);

    if (!initialised) {
        if (position == 0) {
            OnPoolClickListener.onPoolClick(currentPool);
        }
        initialised = true;
    }

    if(currentPool.getStates() == null){
        currentPool.setStates(ButtonStates.UNSELECTED);
    }

    switch (currentPool.getStates()){
        case UNSELECTED:
            holder.button.colourAsDeselected();
            break;
        case SELECTED:
            holder.button.colourAsSelected();
            break;
    }

    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    holder.button.setLayoutParams(params);
    }


public class holder extends RecyclerView.ViewHolder implements View.OnClickListener {

    StakePoolButton button;

    public holder(StakePoolButton view) {
        super(view);
        view.setOnClickListener(this);
        button = view;
    }

我强制布局在适配器级别调整自身大小,因为这是一种让它至少看起来不错的 hacky 方式,但这不会长期有效,特别是如果应用程序要进入多个设备或需要调整大小等。这是通过 LinearLayout.LayoutParams 在布局膨胀后强制布局宽度为 wrap_content 完成的。如果我然后进入 XML 并使自定义布局的高度更小,则其中包含的文本不会缩小以匹配,这意味着事情不合时宜。

这终于是自定义线性布局本身,虽然如果是问题我会感到惊讶:

public class StakePoolButton extends LinearLayout {     //button used for both the stake and pool fragments.

    private TextView buttonText;
    private LinearLayout stakePoolBackground;
    private Context context;

    boolean stake;  //false means pool

    private Typeface font;

    public StakePoolButton(Context context) {
        super(context);
        init(context);
    }

    public StakePoolButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public StakePoolButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public void init(Context context){

        LayoutInflater.from(getContext()).inflate(
            R.layout.pool_layout, this);

        this.context = context;

        this.font = Typeface.createFromAsset(context.getAssets(), "fonts/Cabin_Regular.ttf");

        buttonText = findViewById(R.id.stakepool_name);
        buttonText.setTypeface(font);
        stakePoolBackground = findViewById(R.id.stakepool_background);

    }

        public void setData(Pool pool){
        buttonText.setText(pool.code);

        this.stake = false;
    }

    public void setData(Stake stake){
        buttonText.setText(String.valueOf("£" + stake.getStake()));

        this.stake = true;

    }

我有其他自定义 LinearLayouts 可以完美运行,并且可以通过更改包含布局的宽度和高度值进行适当调整,但无论出于何种原因,这个都不起作用。

edit:在左边我们有预期的行为,这是通过在通货膨胀后设置 LayoutParams 来强制的。在右边,我们有在通货膨胀后没有被强迫的行为。宽度都是可变的,并且每次重新加载视图时都会改变。

【问题讨论】:

  • 发布预期和实际的屏幕截图。
  • @azizbekian 完成 :)
  • 作为测试,尝试将两个 RecyclerView 放入一个 Fragment。 RecyclerView 的布局父级应该是 LinearLayout,方向设置为水平。给两个 RecyclerView 的权重“0.5dp”以强制它们各自占据屏幕的一半。看看你是否得到了你期望的恒定宽度尺寸。另外作为旁注,当您必须在宽度和高度与 match_parent 匹配的 LinearLayout 内查看时,您将无法看到任何其他同级视图。
  • 您是否尝试将适配器中 holder.button 的 WRAP 更改为 MATCH 布局参数?
  • @HareshChhelana 更改换行以匹配使视图的高度 = 整个屏幕的高度,因此一次只显示一个视图。 layoutParams 中设置的宽度已经设置为 Match_Parent,所以这不是问题。我想重申,我不想在适配器级别设置 layoutParams。维度已经并且应该在 XML 中定义

标签: android xml android-layout android-recyclerview


【解决方案1】:

我认为这种宽度变化的问题是因为你必须在你的 recyclerview 中再添加一个设置。

所以在你的 PoolsFragment 中

添加这个

mRecyclerView.setHasFixedSize(true);

在这行代码之后

mRecyclerView.setLayoutManager(layoutManager);

编辑 2

根据 Drew 在this 中的回答,似乎最好像这样手动提供参数

所以在你的适配器类中

//update this according to the answer I linked
@Override
public holder onCreateViewHolder(ViewGroup parent, int viewType) {

 View itemview=new StakePoolButton(parent.getContext());
  RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, //width
ViewGroup.LayoutParams.WRAP_CONTENT);//height
        itemView.setLayoutParams(lp);//override default layout params


return new holder(itemview);
 }

如您所见,高度为 wrap_content,但您可以将其更改为 100dp,宽度应保持 match_parent

【讨论】:

  • 遗憾的是,这并没有改变。感谢您的建议
  • 这会在膨胀的布局、TextView 等上引发大量空对象引用
  • @Richardweber32 好的,请等待删除错误并等待我更新我的答案
  • @Richardweber32 查看第二次更新,检查我添加的链接是否与您的问题很接近。
  • @svi.data EDIT 2 为我完成了这项工作。但是,当我看到 EDIT 2 时,我并没有费心尝试使用 mRecyclerView.setHasFixedSize(true),因为我认为它可以在几乎所有情况下提供防故障解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-19
  • 2011-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多