芯片组中的多行芯片

7

我正在从我的API获取一个包含25个国家标签的列表,例如:德国、英格兰、法国、意大利等等...

我希望每行有两行,每行有10个chips。如果下一次获取到了30个标签,我想要三行每行有10个chips等等...

目前我还没有找到任何可以满足这个需求的工具。我已经快速查看了Flexbox-Layout,但它似乎不符合我的需要。我目前拥有下面的代码,但我考虑使用Recyclerview来实现这样的逻辑。

片段

viewModel.videoSelected.observe(viewLifecycleOwner, object : Observer<VideoPage> {
            override fun onChanged(videoPage: VideoPage?) {
                videoPage?.tags ?: return
                val chipGroup = binding.chipGroup
                val chipGroupInflater = LayoutInflater.from(chipGroup.context)
                val children = videoPage.tags.map { tagName ->
                    val chip = chipGroupInflater.inflate(R.layout.chip_video_tag, chipGroup, false) as Chip
                    chip.text = tagName
                    chip.tag = tagName
                    chip.setOnClickListener {
                        Toast.makeText(context, tagName, Toast.LENGTH_SHORT).show()
                    }

                    chip
                }

                for (chip in children) {
                    chipGroup.addView(chip)
                }
            }
        })

结果是一行有25个芯片。我该如何使它分成多行?


1
不确定为什么您认为Flexbox LayoutManager不能满足您的需求,因为它可以精确控制何时开始新行。您是否考虑过在11、21等芯片上使用layout_wrapBefore标志? - Andrew
这正是我需要的,我一定走得太快了。是否可能在不使用库的情况下本地实现同样的功能? - Biscuit
是的,即使不使用库,也是可能的。因为该库使用标准工具进行操作,您只需要实现自己的布局管理器或扩展现有的布局管理器即可。但是,使用flexbox会更容易些。 - Andrew
2个回答

2
如评论所述,您可以在芯片11、21等上使用具有layout_wrapBefore标志的Flexbox LayoutManager 或者,如果重新格式化数据,则也可以使用标准recyclerview。
要使用标准recyclerview,您需要将数据排列在2D数据结构中,这可以是ArrayList的Arraylists或Arrays或一组POJO类
在外部ArrayList中将是行,在内部ArrayList中将显示要在行中显示的项目。
因此,RecyclerView项只是一个水平线性布局,用于生成行,您可以从内部ArrayList添加您的Chips
示例使用生成的2D结构
MainActivity
public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private RAdapter adapter;
    private ArrayList<ArrayList<String>> rowsArrayList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycler);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);

        rowsArrayList = new ArrayList<>();
        for (int i = 1; i <= 3; i++) {
            ArrayList<String> row = new ArrayList<>();
            for (int j = 1; j <= 10; j++) {
                row.add(String.valueOf(j));
            }
            rowsArrayList.add(row);
        }

        adapter = new RAdapter(this, rowsArrayList);
        recyclerView.setAdapter(adapter);
    }
}

RAdapter

public class RAdapter extends RecyclerView.Adapter<RAdapter.RHolder>{

    class RHolder extends RecyclerView.ViewHolder {
        private LinearLayout line;

        public RHolder(View itemView) {
            super(itemView);
            line = itemView.findViewById(R.id.line);
        }
    }

    private Context context;
    private ArrayList<ArrayList<String>> rowsArrayList;

    public RAdapter(Context context, ArrayList<ArrayList<String>> rowsArrayList) {
        this.context = context;
        this.rowsArrayList = rowsArrayList;
    }

    @Override
    public RHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
        return new RHolder(view);
    }

    @Override
    public void onBindViewHolder(RHolder holder, int position) {
        // Because we might be recycling the LinearLayout that might have had chips added to it already
        holder.line.removeAllViews();
        ArrayList<String> row = rowsArrayList.get(position);
        for (String text: row) {
            Chip chip = new Chip(context);
            chip.setText(text);
            holder.line.addView(chip);
        }
    }

    @Override
    public int getItemCount() {
        return rowsArrayList.size();
    }

}

row_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/line">

</LinearLayout>


这将产生
屏幕截图

更新:
通过更多的数学计算,您可以在不重新排列数据的情况下完成它。

显示25个项目以涵盖不完整的行用例

MainActivity

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private RAdapter adapter;
    private ArrayList<String> itemsArrayList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycler);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);

        itemsArrayList = new ArrayList<>();
        for (int i = 1; i <= 25; i++) {
            itemsArrayList.add(String.valueOf(i));
        }

        adapter = new RAdapter(this, itemsArrayList);
        recyclerView.setAdapter(adapter);
    }
}

RAdapter

public class RAdapter extends RecyclerView.Adapter<RAdapter.RHolder>{

    class RHolder extends RecyclerView.ViewHolder {
        private LinearLayout line;

        public RHolder(View itemView) {
            super(itemView);
            line = itemView.findViewById(R.id.line);
        }
    }

    private Context context;
    private ArrayList<String> itemsArrayList;
    private int itemsPerRow = 10;

    public RAdapter(Context context, ArrayList<String> itemsArrayList) {
        this.context = context;
        this.itemsArrayList = itemsArrayList;
    }

    @Override
    public RHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
        return new RHolder(view);
    }

    @Override
    public void onBindViewHolder(RHolder holder, int position) {
        // Because we might be recycling the LinearLayout that might have had chips added to it already
        holder.line.removeAllViews();
        int adjustedPosition = position + 1;
        int rangeEnd = Math.min(itemsArrayList.size(), adjustedPosition * itemsPerRow);
        int rangeStart = Math.max((position * itemsPerRow) + 1, rangeEnd - itemsPerRow);
        for (int i = rangeStart; i <= rangeEnd; i++) {
            int arrayPositionAdjusted = i - 1;
            Chip chip = new Chip(context);
            chip.setText(itemsArrayList.get(arrayPositionAdjusted));
            holder.line.addView(chip);
        }
    }

    @Override
    public int getItemCount() {
        return return (int) Math.ceil(itemsArrayList.size()/ (double) itemsPerRow);
    }

}


生成
screenshot2

1

我还通过BindingAdapter以更简单的方式实现了它:

 <androidx.recyclerview.widget.RecyclerView
                    app:listVideoTagChip="@{viewModel.videoSelected.tags}"
                    android:id="@+id/rv_video_chips"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
                    android:orientation="horizontal"
                    tools:listitem="@layout/chip_video_tag"/>

private const val TAG_PER_ROW = 10

@BindingAdapter("listVideoTagChip")
fun RecyclerView.bindRecyclerView(data: List<String>?) {
    val adapter: VideoTagAdapter = this.adapter as VideoTagAdapter
    (layoutManager as StaggeredGridLayoutManager).spanCount =
        data?.size?.let {
            ceil(it.toDouble().div(TAG_PER_ROW)).toInt()
        } ?: 1
    adapter.submitList(data)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接