RecyclerView行项目布局不保持在XML中定义的维度

时间:2017-11-02 12:04:13

标签: android xml android-layout android-recyclerview

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

这是布局文件pool_layout.xml:

void create_borders(char **map, int nb_elem)
{
    printf("nb_elem : %d\n", nb_elem);
    for (int i = 0 ; i < nb_elem ; i++) //THIS dosnt work and stop once i = 1
        // int i = 0;                    //ALL the commentes are part of the other
        // int j = 0;                    //solution that i found which is working
        // while (j < nb_elem)
    {
        int newx = -1;
        int newy = -1;
        while (newx <= letter_infos[i].width + 1 ||
               newy <= letter_infos[i].height + 1)
        {
            if (letter_infos[i].square_p1.y - 1 >= 0 &&
                newx <= letter_infos[i].width + 1)
                map[letter_infos[i].square_p1.y - 1][letter_infos[i].square_p1.x + newx] = '@';
            if (letter_infos[i].square_p1.x - 1 >= 0 &&
                newy <= letter_infos[i].height + 1)
                    map[letter_infos[i].square_p1.y +
                        newy][letter_infos[i].square_p1.x - 1] = '@';
            if (letter_infos[i].square_p2.y + 1 < strlen (map[0]) &&
                newx <= letter_infos[i].width + 1)
                map[letter_infos[i].square_p2.y + 1][letter_infos[i].square_p2.x - newx] = '@';
            if (letter_infos[i].square_p2.x + 1 < my_tablen (map) &&
                newy <= letter_infos[i].height + 1)
                map[letter_infos[i].square_p2.y - newy][letter_infos[i].square_p2.x + 1] = '@';
            newx++;
            newy++;
        }
        printf ("i = %d\n", i);
        i++;
        //j++;
    }
}

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

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

<?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>

此宽度也设置为match_parent,并且它的父(未包含)由具有相对布局的main_activity XML定义,因此视图宽度的大小为main_activity中定义的片段减去边距等,但它不是。

<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>

片段代码,如果你认为它是相关的,但我怀疑它不是。

适配器代码:

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);

}

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

这里最后是Custom LinearLayout本身,虽然如果问题我会感到惊讶:

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;
    }

我有其他自定义LinearLayouts可以正常工作,并且可以通过更改包含布局的宽度和高度值来正确调整,但是这个不适用于任何原因。

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

Expected and actual

1 个答案:

答案 0 :(得分: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