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 示例
我想根据卡片在屏幕上的位置使用不同的布局。例如我需要第一张卡片(位置 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 classpublic 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 示例