【问题标题】:2-vertical and 2-horizontal card views inside recyclerview androidrecyclerview android中的2垂直和2水平卡片视图
【发布时间】:2018-02-19 04:56:08
【问题描述】:

我想用一个数据集列表创建以下 UI。

我尝试使用多视图类型,但无法达到我的要求。我还实现了这个博客Android Horizontal and Vertical RecyclerView Example

但这使用了两个recyclerviews,并且有两组数据(水平数据和垂直数据)。

我也试过这个。 RecyclerView with multiple views using custom adapter in Android

但这是在 XML 中使用静态卡片视图并将它们加载到适配器中。

我是 Android 开发的初学者。请帮忙!

提前谢谢你。

【问题讨论】:

  • 使用位置来确定是显示水平卡片还是垂直卡片

标签: java android xml android-layout android-recyclerview


【解决方案1】:

可以通过在RecyclerView.Adapter 中使用GridLayoutManager 和两个“项目视图类型”来实现您想要的布局。

这是我的布局 XML 文件:

activity_main.xml:
-------------------------

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
    
horizontal.xml:
-------------------------

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_margin="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/image"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#ccc"/>

        <TextView
            android:id="@+id/text"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:background="#fff"
            android:textColor="#000"
            android:textSize="18sp"
            android:text="TEXT"/>

    </LinearLayout>

</android.support.v7.widget.CardView>

vertical.xml:
-------------------------

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_margin="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="#ccc"/>

        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:background="#fff"
            android:textColor="#000"
            android:textSize="18sp"
            android:text="TEXT"/>

    </LinearLayout>

</android.support.v7.widget.CardView>

这是我的 Java 文件:

public class MainActivity extends AppCompatActivity {

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

        GridLayoutManager manager = new GridLayoutManager(this, 2);
        manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                return (position % 4) < 2 ? 2 : 1;
            }
        });

        RecyclerView recycler = (RecyclerView) findViewById(R.id.recycler);
        recycler.setLayoutManager(manager);
        recycler.setAdapter(new MyAdapter());
    }

    private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

        @Override
        public int getItemViewType(int position) {
            return (position % 4) < 2
                    ? R.layout.horizontal
                    : R.layout.vertical;
        }

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View itemView = inflater.inflate(viewType, parent, false);
            return new MyViewHolder(itemView);
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.image.setImageResource(R.drawable.mouse);
            holder.text.setText("" + position);
        }

        @Override
        public int getItemCount() {
            return Integer.MAX_VALUE;
        }
    }

    private static class MyViewHolder extends RecyclerView.ViewHolder {

        private final ImageView image;
        private final TextView text;

        public MyViewHolder(View itemView) {
            super(itemView);
            this.image = (ImageView) itemView.findViewById(R.id.image);
            this.text = (TextView) itemView.findViewById(R.id.text);
        }
    }
}

让我们回顾一下重要的部分。首先是GridLayoutManagerSpanSizeLookup 的组合。我们正在使用这一行创建布局管理器:

GridLayoutManager manager = new GridLayoutManager(this, 2);

这意味着,默认情况下,我们网格的每一行都会有两张卡片。但随后我们应用SpanSizeLookup,它表示我们的一半行(由语句position % 4 &lt; 2 找到)实际上应该占据两列。所以我们会有一张卡片,一张卡片,两张卡片在我们的“网格”中重复。

然后,在RecyclerView.Adapter 类中,我们重写getItemViewType() 方法。这里我们再次使用position % 4 &lt; 2 语句来表示我们的一半视图应该是水平的,一半应该是垂直的。

getItemViewType() 只需要为每种视图类型返回任何唯一的int,因此我们使用了一个很好的技巧,即从此方法返回R.layout 常量。由于视图类型将被传递到onCreateViewHolder(),我们可以使用viewType 参数来膨胀正确的布局。

就是这样!毕竟还不错。这是我的代码的截图:

【讨论】:

  • 完美。这就是我要找的。谢谢。 Click 事件会和往常一样吧?
【解决方案2】:

不久前我遇到了这个问题,虽然我可能不是专家,但我认为我的回答也可以帮助你。您可以通过创建两种不同类型的布局来做到这一点,类似于文章。您需要创建两个布局类型都可以扩展的抽象类。然后,在您的适配器中,检查应该显示什么类型的对象。

抽象类:

public abstract class ListItem {

    public static final int TYPE_HORIZONTAL = 0;
    public static final int TYPE_VERTICAL = 1;

    abstract public int getType();
}

水平项目:

public class HorizontalItem extends ListItem {

    private String text;
    private Bitmap image;

    public HorizontalItem(String text, Bitmap image) {
        this.text = text;
        this.image = image;
    }

    /*
     * Getter and setter methods here
     */


    @Override
    public int getType() {
        return ListItem.TYPE_HORIZONTAL;
    }
}

垂直项目:

public class VerticalItem extends ListItem {

    private String text1;
    private Bitmap image1;
    private String text2;
    private Bitmap image2;

    public VerticalItem(String text1, String text2, Bitmap image1, Bitmap image2) {
        this.text1 = text1;
        this.image1 = image1;
        this.text2 = text2;
        this.image2 = image2;
    }

    /*
     * Getter and setter methods here
     */


    @Override
    public int getType() {
        return ListItem.TYPE_HORIZONTAL;
    }
}

适配器:

public class ListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private ArrayList<ListItem> listItems;

    public static class HorizontalViewHolder extends RecyclerView.ViewHolder {
        public TextView text;
        public ImageView imageView;
        public HorizontalHolder(View v) {
            super(v);
            text = (TextView) v.findViewById(R.id.text);
            imageView = (ImageView) v.findViewById(R.id.imageView);
        }
    }

    public static class VerticalViewHolder extends RecyclerView.ViewHolder {
        public TextView text1;
        public ImageView imageView1;
        public TextView text2;
        public ImageView imageView2;
        public HorizontalHolder(View v) {
            super(v);
            text1 = (TextView) v.findViewById(R.id.text1);
            imageView1 = (ImageView) v.findViewById(R.id.imageView1);
            text2 = (TextView) v.findViewById(R.id.text2);
            imageView2 = (ImageView) v.findViewById(R.id.imageView2);
        }
    }

    // constructor
    public ListAdapter(ArrayList<ListItem> listItems) {
        this.listItems = listItems;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v;
        RecyclerView.ViewHolder holder = null;
        switch (viewType) {
            case ListItem.TYPE_HORIZONTAL:
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.template_horizontal, parent, false);
                holder = new HorizontalViewHolder(v);
                break;
            case ListItem.TYPE_VERTICAL:
                v = LayoutInflater.from(parent.getContext()).inflate(R.layout.template_vertical, parent, false);
                holder = new VerticalViewHolder(v);
                break;
        }
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        switch (holder.getItemViewType()) {
            case ListItem.TYPE_HORIZONTAL:
                ((HorizontalViewHolder) holder).text.setText(listItems.get(position).getText());
                ((HorizontalViewHolder) holder).imageView.setImageBitmap(listItems.get(position).getBitmap());
                // the getText() and getBitmap() methods come from the getters of the HorizontalItems and VerticalItems that are stored in the ArrayList, listItems
                break;
            case ListItem.TYPE_DECK:
                // Identical to above
                break;
        }
    }

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

    // This is extremely important, it is what lets the adapter know what type each listItem element is
    @Override
    public int getItemViewType(int position) {
        return listItems.get(position).getType();
    }
}

活动:

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

    // Must be of abstract type ListItem
    ArrayList<ListItem> items = new ArrayList<>();
    // populate your ArrayList
    items.add(new HorizontalItem("text", bitmap));
    items.add(new VerticalItem("text1", "text2", bitmap1, bitmap2));
    // ... and so on

    ListAdapter adapter = new ListAdapter(items)
    RecyclerView recycler = (RecyclerView) findViewById(R.id.recycler);
    recycler.setAdapter(adapter);
    recycler.setLayoutManager(new LinearLayoutManager(this));

    // ... the rest of your code below
}

在您的垂直列表项布局中,我将只创建一个包含两半的文件。您可以使用 LinearLayout 轻松地将子部分分成完美的两半。

【讨论】:

    猜你喜欢
    • 2016-01-20
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多