Android 卡片基于位置的多种布局

Android cards multiple layouts based on position

我想根据卡片在屏幕上的位置使用不同的布局。例如我需要第一张卡片(位置 0 使用布局 first_card.xml),其他卡片应该使用 other_cards.xml 布局并且应该水平放置(见下图(图片来自官方 google 站点)).

这是我的代码

public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
    private List<CardData> mItems;
    private Context context;
    private SendInfoToCards cardDatas;
    private boolean mainMenu;
    private static final int FIRST = 1;
    private static final int SECOND = 2;

    public CardAdapter(Context c, SendInfoToCards datas, boolean main) {
        super();
        this.context = c;
        this.cardDatas = datas;
        mItems = datas.getList();
        this.mainMenu = main;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
        if(!mainMenu) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_card_item, viewGroup, false);
            ViewHolder viewHolder = new ViewHolder(v);
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    TextView city = (TextView) v.findViewById(R.id.tv_movie);
                    String fragmentSwitcher = city.getText().toString();
                    if (fragmentSwitcher.equals("Zemelapis")) {
                        switchFragments(0);
                    } else {
                        switchFragments(1);
                    }
                }
            });
            return viewHolder;
        } else {
            View v;
            if(position == 0){
                v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
            }else{
                v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
            }
            ViewHolder viewHolder = new ViewHolder(v);
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    TextView city = (TextView) v.findViewById(R.id.tv_movie);
                    String fragmentSwitcher = city.getText().toString();
                }
            });
            return viewHolder;
        }
    }

    private void switchFragments(int nr){
        if(nr == 0){
            Log.d("TAG", "mapo");
        } else {
            Intent intent = new Intent(context, DetailTourActivity.class);
            context.startActivity(intent);
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        if(i != 0){

        } else {
            CardData data = mItems.get(i);
            viewHolder.tvMovie.setText(data.getName());
            viewHolder.imgThumbnail.setImageResource(data.getThumbnail());
        }
    }

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

    class ViewHolder extends RecyclerView.ViewHolder{
        public ImageView imgThumbnail;
        public TextView tvMovie;

        public ViewHolder(View itemView) {
            super(itemView);
            imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
            tvMovie = (TextView)itemView.findViewById(R.id.tv_movie);
        }
    }
}

遗憾的是 onCreateViewHolder 方法的第二个参数 position 始终为 0。这是为什么呢?如何解决?

问题是第二个参数不是位置,它是viewType

来自docs

public abstract VH onCreateViewHolder (ViewGroup parent, int viewType)

看看public void onBindViewHolder (VH holder, int position, List<Object> payloads),这才是你真正需要的

这是您的适配器 class 大致的样子

public class CardAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder>{
    private List<CardData> mItems;
    private Context context;
    private SendInfoToCards cardDatas;
    private boolean mainMenu;
    private static final int FIRST = 1;
    private static final int SECOND = 2;

    public CardAdapter(Context c, SendInfoToCards datas, boolean main) {
        super();
        this.context = c;
        this.cardDatas = datas;
        mItems = datas.getList();
        this.mainMenu = main;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
        if(type == SECOND){
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
            return new SecondViewViewHolder(v);
        } else {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
            return new FirstViewViewHolder(v);
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        if(viewHolder instanceof SecondViewViewHolder){
            SecondViewViewHolder secondViewViewHolder = (SecondViewViewHolder) viewHolder;
            // bind second views
            secondViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
        } else {
            FirstViewViewHolder firstViewViewHolder = (FirstViewViewHolder) viewHolder;
            // bind firs view
            firstViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return FIRST;
        } else {
            return SECOND;
        }
    }

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

    class FirstViewViewHolder extends RecyclerView.ViewHolder{
        public ImageView imgThumbnail;
        public TextView tvMovie;

        public FirstViewViewHolder(View itemView) {
            super(itemView);
            imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
            tvMovie = (TextView)itemView.findViewById(R.id.tv_movie);
        }
    }

    class SecondViewViewHolder extends RecyclerView.ViewHolder{
        public ImageView imgThumbnail;
        public TextView tvMovie;
        public ImageView imgThumbnail2;
        public TextView tvMovie2;

        public SecondViewViewHolder(View itemView) {
            super(itemView);
            //find viewby id
        }
    }
}

改变了什么

由于 recyclerview 可以处理多种视图类型,因此您可以根据某些条件决定扩充哪个布局。您可以通过重写 RecylerView Adapter

getItemViewTypeMethod() 来实现
 @Override
 public int getItemViewType(int position) {
    if (position == 0) {
         return FIRST;
    } else {
       return SECOND;
    }
}

创建viewholder时。 onCreateViewHolder 方法将获取视图类型。根据类型,您应该膨胀适当的布局和 return 适当的 viewholder

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
   if(type == SECOND){
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
        return new SecondViewViewHolder(v);
    } else {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
        return new FirstViewViewHolder(v);
    }
}

由于涉及两个布局,我创建了两个 ViewHolder 来保存第一个和第二个布局。 (FirstViewHolder & SecondViewHolder)。因此,您必须像这样

将适配器的 ViewHolder 类型设置为基本 ViewHolder class
public class CardAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder>{
   ...
}

现在在 onBindViewHolder 方法中,您可以确定当前正在绑定哪个 ViewHolder 并相应地执行您的工作

 @Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
    if(viewHolder instanceof SecondViewViewHolder){
        SecondViewViewHolder secondViewViewHolder = (SecondViewViewHolder) viewHolder;
        // bind second views
            secondViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
    } else {
        FirstViewViewHolder firstViewViewHolder = (FirstViewViewHolder) viewHolder;
        // bind firs view
        firstViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
    }
}

查看 this 示例