从布局创建具有多个视图的RecyclerView [英] Create a RecyclerView with multiple view from layouts
问题描述
我正在尝试在一个RecyclerView中使用2种布局
I am trying to have 2 layout in one RecyclerView
我有一个称为Bookmark的回收站视图列表,它是从xml中解析出来的,并且都可以正常工作,但是我想在此回收站视图中放置另一个包含按钮且可以单击的布局. 就像照片中的图标一样,图标来自recyclerview,加号按钮必须与列表兼容,如果列表较大或较小,则按钮将与列表空间兼容.
I have a recycler view list which is called Bookmark and it is parsed from an xml and this is all working , but I wanna in this recyclerview to put another layout which contains a button and that can be clickable. Like in the photo the icons are from recyclerview and the plus button need to be compatible with the list, if the list is larger or smaller the button will be compatible with the space of list.
这是我的适配器新代码,具体取决于答案@LluisFelisart
这是错误
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
This is my new code for the Adapter which depends on the answer @LluisFelisart
And this is the error
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList = new ArrayList<>();
public MyAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
public class ViewHolder0 extends RecyclerView.ViewHolder {
TextView tvName,tvId,tvSearchUrl,tvNativeUrl;
ImageView tvIcon;
public ViewHolder0(@NonNull View itemView) {
super(itemView);
tvName=itemView.findViewById(R.id.textView);
tvIcon = itemView.findViewById(R.id.image_view);
/* tvId=itemView.findViewById(R.id.tvId);
tvSearchUrl=itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl=itemView.findViewById(R.id.tvNativeUrl);*/
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
ImageView tvAddBookmark;
public ViewHolder2(@NonNull View itemView) {
super(itemView);
tvAddBookmark = itemView.findViewById(R.id.image_button_add);
}
}
@Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.grid_item, viewGroup, false);
switch (i) {
case 0: return new ViewHolder0(viewGroup);
case 2: return new ViewHolder2(viewGroup);
}
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolder0 viewHolder0 = (ViewHolder0) holder;
((ViewHolder0) holder).tvName.setText(arrayList.get(position).getName());
((ViewHolder0) holder).tvIcon.setImageResource(arrayList.get(position).getIcon());
break;
case 2:
ViewHolder2 viewHolder2 = (ViewHolder2) holder;
}
((ViewHolder0) holder).tvIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent;
intent = new Intent(context, BookmarkActivity.class);
v.getContext().startActivity(intent);
}
});
((ViewHolder0) holder).tvIcon.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Intent intent = new Intent(context, ActivityBookmarksFavorites.class);
v.getContext().startActivity(intent);
return false;
}
});
}
@Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName,tvId,tvSearchUrl,tvNativeUrl;
ImageView tvIcon;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvName=itemView.findViewById(R.id.textView);
tvIcon = itemView.findViewById(R.id.image_view);
/* tvId=itemView.findViewById(R.id.tvId);
tvSearchUrl=itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl=itemView.findViewById(R.id.tvNativeUrl);*/
}
}
}
这是网格项目的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="vertical"
android:visibility="visible"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/image_view"
style="@style/BookmarkIconIv" />
<TextView android:id="@+id/textView"
android:layout_marginTop="1.0dip"
style="@style/BookmarkTextTv" />
</LinearLayout>
这是我想在回收站视图中显示的按钮的布局
This is the layout of button which I want to be in the recycler view
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@+id/image_button_add"
android:layout_width="45dp"
android:layout_height="45dp"
android:src="@drawable/ic_add_black_24dp"
android:background="@color/transparent" />
</android.support.constraint.ConstraintLayout>
这是在回收站视图中显示的片段
This is the Fragment which the recycler view it is shown
public class FragmentBookmark extends Fragment {
ArrayList<Bookmark> arrayList = new ArrayList<>();
XmlPullParser pullParser;
MyAdapter myAdapter;
View paramView;
RecyclerView myRecyclerView;
private Context mContext;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
@Nullable
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
paramView = inflater.inflate(R.layout.bookmark, container, false);
myRecyclerView = paramView.findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new GridLayoutManager(mContext, 4));
myRecyclerView.setHasFixedSize(true);
myAdapter = new MyAdapter(mContext, arrayList);
myRecyclerView.setAdapter(myAdapter);
try {
XmlPullParser xpp = getResources().getXml(R.xml.bookmarks);
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
if (xpp.getEventType() == XmlPullParser.START_TAG) {
if (xpp.getName().equals("Bookmark")) {
Bookmark bookmark = new Bookmark();
bookmark.setName(xpp.getAttributeValue(null, "name"));
int drawableResourceId = getResources().getIdentifier(xpp.getAttributeValue(null, "icon"),"drawable", mContext.getPackageName());
bookmark.setIcon(drawableResourceId);
arrayList.add(bookmark);
}
}
xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
myAdapter.notifyDataSetChanged();
return paramView;
}
}
这是包含recyclerview的布局书签
This is the layout bookmark which contains recyclerview
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/myRecyclerView"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:fillViewport="false">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
推荐答案
这是答案
按照此步骤
示例代码
layout.layout_one
layout.layout_one
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:cardCornerRadius="15dp"
app:cardElevation="5dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Name : " />
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Icon : " />
<ImageView
android:id="@+id/tvIcon"
android:layout_width="20dp"
android:layout_height="20dp"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Id : " />
<TextView
android:id="@+id/tvId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="SearchUrl : " />
<TextView
android:id="@+id/tvSearchUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="NativeUrl : " />
<TextView
android:id="@+id/tvNativeUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
layout.button_two
layout.button_two
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imgButton"
android:layout_width="50dp"
android:layout_height="50dp" />
</LinearLayout>
现在您需要为两个viewType创建两个RecyclerView.ViewHolder
现在,您需要覆盖 getItemViewType()
- it返回位于位置的项目的
viewType
,以用于视图回收. - it Return the
viewType
of the item at position for the purposes of view recycling.
Now you need to create two RecyclerView.ViewHolder
for your both viewType
Now you need to Override getItemViewType()
这是具有多种视图类型的
RecyclerView.Adapter
的示例代码
here is the sample code of
RecyclerView.Adapter
with multiple view types
DataAdapter
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<Bookmark> arrayList = new ArrayList<>();
public static final int ITEM_TYPE_ONE = 0;
public static final int ITEM_TYPE_TWO = 1;
public DataAdapter(Context context, ArrayList<Bookmark> arrayList) {
this.context = context;
this.arrayList = arrayList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = null;
// check here the viewType and return RecyclerView.ViewHolder based on view type
if (viewType == ITEM_TYPE_ONE) {
view = LayoutInflater.from(context).inflate(R.layout.layout_one, parent, false);
return new ViewHolder(view);
} else if (viewType == ITEM_TYPE_TWO) {
view = LayoutInflater.from(context).inflate(R.layout.button_two, parent, false);
return new ButtonViewHolder(view);
}else {
return null;
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
final int itemType = getItemViewType(position);
// First check here the View Type
// than set data based on View Type to your recyclerview item
if (itemType == ITEM_TYPE_ONE) {
ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.tvName.setText(arrayList.get(position).getName());
viewHolder.tvIcon.setImageResource(arrayList.get(position).getIcon());
viewHolder.tvSearchUrl.setText(arrayList.get(position).getSearchUrl());
viewHolder.tvNativeUrl.setText(arrayList.get(position).getNativeUrl());
} else if (itemType == ITEM_TYPE_TWO) {
ButtonViewHolder buttonViewHolder = (ButtonViewHolder) holder;
buttonViewHolder.imgButton.setImageResource(arrayList.get(position).getIcon());
}
}
@Override
public int getItemViewType(int position) {
// based on you list you will return the ViewType
if (arrayList.get(position).getViewType() == 0) {
return ITEM_TYPE_ONE;
} else {
return ITEM_TYPE_TWO;
}
}
@Override
public int getItemCount() {
return arrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tvName, tvId, tvSearchUrl, tvNativeUrl;
ImageView tvIcon;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvName = itemView.findViewById(R.id.tvName);
tvIcon = itemView.findViewById(R.id.tvIcon);
tvId = itemView.findViewById(R.id.tvId);
tvSearchUrl = itemView.findViewById(R.id.tvSearchUrl);
tvNativeUrl = itemView.findViewById(R.id.tvNativeUrl);
}
}
public class ButtonViewHolder extends RecyclerView.ViewHolder {
ImageView imgButton;
public ButtonViewHolder(@NonNull View itemView) {
super(itemView);
imgButton = itemView.findViewById(R.id.imgButton);
}
}
}
在列表中添加数据时,您需要在列表中提供viewtype
.
在您的Bookmark
POJO类中进行一些更改
When you adding data in your list you need to provide the viewtype
in list
Make some changes in your Bookmark
POJO class
Bookmark
POJO类
public class Bookmark
{
String name,id,nativeUrl,searchUrl;
int icon;
int viewType;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getNativeUrl() {
return nativeUrl;
}
public void setNativeUrl(String nativeUrl) {
this.nativeUrl = nativeUrl;
}
public String getSearchUrl() {
return searchUrl;
}
public void setSearchUrl(String searchUrl) {
this.searchUrl = searchUrl;
}
public int getViewType() {
return viewType;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
@Override
public String toString() {
return "Bookmark{" +
"name='" + name + '\'' +
", icon='" + icon + '\'' +
", id='" + id + '\'' +
", nativeUrl='" + nativeUrl + '\'' +
", searchUrl='" + searchUrl + '\'' +
'}';
}
}
示例活动代码
Sample activity code
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private Context mContext;
ArrayList<Bookmark> arrayList = new ArrayList<>();
RecyclerView myRecyclerView;
DataAdapter dataAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
myRecyclerView = findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
myRecyclerView.setHasFixedSize(true);
dataAdapter = new DataAdapter(mContext, arrayList);
myRecyclerView.setAdapter(dataAdapter);
try {
XmlPullParser xpp = getResources().getXml(R.xml.bookmarks);
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
if (xpp.getEventType() == XmlPullParser.START_TAG) {
if (xpp.getName().equals("Bookmark")) {
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(0) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(1) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(5) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(2) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(3) + " * ");
Log.e("MY_VALUE", " * " + xpp.getAttributeValue(4) + " * ");
Bookmark bookmark = new Bookmark();
bookmark.setName(xpp.getAttributeValue(0));
int drawableResourceId = this.getResources().getIdentifier(xpp.getAttributeValue(1), "drawable", mContext.getPackageName());
bookmark.setIcon(drawableResourceId);
bookmark.setId(xpp.getAttributeValue(2));
bookmark.setSearchUrl(xpp.getAttributeValue(3));
bookmark.setNativeUrl(xpp.getAttributeValue(4));
// here you need to set view type
bookmark.setViewType(0);
arrayList.add(bookmark);
}
}
xpp.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// here i have added second viewType
// you need to set as per your requirement
Bookmark bookmark = new Bookmark();
bookmark.setViewType(1);
bookmark.setIcon(R.drawable.dishu);
arrayList.add(bookmark);
dataAdapter.notifyDataSetChanged();
}
}
注意
在下面的代码中,我在Arraylist
的最后一个索引处设置了第二个viewType
您需要根据需要设置viewType
NOTE
In the below code i have set second viewType
at the last index of Arraylist
you need to set viewType
as per your requirement
有关更多信息,您可以查看以下文章
For more information you can check below articles
- 使用RecyclerView和多种视图类型
- 具有多种项目类型的RecyclerView
- 具有不同子布局的Android RecyclerView
- Android分页教程-处理多种视图类型
- RecyclerView内部的异构布局
- Android RecyclerView示例–多个ViewType
- 如何创建具有多种视图类型的RecyclerView?
- 使用RecyclerView的Android多行布局
- Working with RecyclerView and multiple view types
- A RecyclerView with multiple item types
- Android RecyclerView with Different Child Layouts
- Android Pagination Tutorial—Handling Multiple View Types
- Heterogenous Layouts inside RecyclerView
- Android RecyclerView Example – Multiple ViewTypes
- How to create RecyclerView with multiple view type?
- Android Multiple row layout using RecyclerView
这篇关于从布局创建具有多个视图的RecyclerView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!