英文:
How is it possible to display different fragment/view for each subclass? Android
问题
我有一个Message
对象列表。Message
是一个抽象类,有两个子类:TextMessage
和ImageMessage
我想要在可滚动的列表中显示这些消息,根据消息的类型进行显示。如何创建一个自定义的视图/片段,以抽象类作为参数,并根据实际的子类创建其中的TextView/ImageView?
我已阅读了官方的Android指南,但仍然不知道如何实现这一点。
英文:
I have a list of Message
objects. Message
is an abstract class, with two subclasses: TextMessage
and ImageMessage
I would like to display the messages in a scrollable list, based on the type of the message. How is it possible to create a custom view/fragment with an abstract class as parameter, and create a TextView/ImageView inside it according to the actual subclass?
I've read the official android guide, but I still have no idea, how to do this.
答案1
得分: 2
好的,以下是翻译好的内容:
好的,既然 RecyclerView 是推荐用于显示具有未定义大小的项目列表的视图,我会假设你想要在这里使用 RecyclerView。
如果你按照 示例代码 来创建这样一个视图,那么你可以让你的 Message
类声明一个抽象的 getViewType
和 bindToView
方法,如下所示:
Message.java
public abstract class Message {
public abstract int getViewType();
public abstract void bindToView(View messageView);
public enum TYPE {
TextMessage,
ImageMessage
}
public static View createView(int typeOrdinal, Context context) {
switch (TYPE.values()[typeOrdinal]) {
case TextMessage:
return TextMessage.createNewView(context);
case ImageMessage:
return ImageMessage.createNewView(context);
default:
throw new RuntimeException("Incorrect typeOrdinal: " + typeOrdinal);
}
}
}
TextMessage.java
public class TextMessage extends Message {
public static TextView createNewView(Context context) {
return new TextView(context);
}
@Override
public void bindToView(View messageView) {
((TextView) messageView).setText("一些特定的文本");
}
@Override
int getViewType() {
return TYPE.TextMessage.ordinal();
}
}
ImageMessage.java
public class ImageMessage extends Message {
public static ImageView createNewView(Context context) {
return new ImageView(context);
}
@Override
public void bindToView(View messageView) {
Bitmap forExampleSomeBitmap = null; // TODO 实现
((ImageView) messageView).setImageBitmap(forExampleSomeBitmap);
}
@Override
int getViewType() {
return TYPE.ImageMessage.ordinal();
}
}
然后,保持来自该 Google 示例代码的所有其余代码不变,你的 RecyclerView.Adapter 可能会如下所示:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Message[] mDataset;
public static class MyViewHolder extends RecyclerView.ViewHolder {
public View messageView;
public MyViewHolder(View v) {
super(v);
messageView = v;
}
}
@NonNull
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(Message.createView(viewType, parent.getContext()));
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
mDataset[position].bindToView(holder.messageView);
}
@Override
public int getItemViewType(int position) {
return mDataset[position].getViewType();
}
@Override
public int getItemCount() {
return mDataset.length;
}
}
如果你想了解更多关于 RecyclerView 如何工作以及为什么它会回收视图的信息,我建议阅读 这篇文章。
英文:
Ok, So since a RecyclerView is the recommended view for a list of items with an undefined size, I'm gonna assume your want to use a RecyclerView for this.
If you then follow the sample code to make such a view, then you could make your Message
class declare an abstract getViewType
and bindToView
method as follows:
Message.java
public abstract class Message {
public abstract int getViewType();
public abstract void bindToView(View messageView);
public enum TYPE {
TextMessage,
ImageMessage
}
public static View createView(int typeOrdinal, Context context) {
switch (TYPE.values()[typeOrdinal]) {
case TextMessage:
return TextMessage.createNewView(context);
case ImageMessage:
return ImageMessage.createNewView(context);
default:
throw new RuntimeException("Incorrect typeOrdinal: " + typeOrdinal);
}
}
}
TextMessage.java
public class TextMessage extends Message {
public static TextView createNewView(Context context) {
return new TextView(context);
}
@Override
public void bindToView(View messageView) {
((TextView) messageView).setText("some specific text");
}
@Override
int getViewType() {
return TYPE.TextMessage.ordinal();
}
}
ImageMessage.java
public class ImageMessage extends Message {
public static ImageView createNewView(Context context) {
return new ImageView(context);
}
@Override
public void bindToView(View messageView) {
Bitmap forExampleSomeBitmap = null; // TODO implement
((ImageView) messageView).setImageBitmap(forExampleSomeBitmap);
}
@Override
int getViewType() {
return TYPE.ImageMessage.ordinal();
}
}
And then With all the rest of the code from that google sample code unchanged, your RecyclerView.Adapter could then look like this:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Message[] mDataset;
public static class MyViewHolder extends RecyclerView.ViewHolder {
public View messageView;
public MyViewHolder(View v) {
super(v);
messageView = v;
}
}
@NonNull
@Override
public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(Message.createView(viewType, parent.getContext()));
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
mDataset[position].bindToView(holder.messageView);
}
@Override
public int getItemViewType(int position) {
return mDataset[position].getViewType();
}
@Override
public int getItemCount() {
return mDataset.length;
}
}
If you want to know more about how the recyclerview works, why it recycles views, then I would recommend this arcticle.
答案2
得分: 1
1: 创建新项目
-> 选择 基本活动
在您的活动内有两个片段和一个按钮,用于在片段 A 和 B 之间进行切换。
2: 在 SecondFragment
(片段 B)中创建一个 RecyclerView
资源
将以下行添加到第二个片段:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="409dp"
android:layout_height="460dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/button_second"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
3: 创建一个带有 TextView
的帧布局
前往 /res/layout/newlayout/layoutresource
文件,创建一个帧布局,将以下代码替换到布局内:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<TextView
android:id="@+id/randomText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="This is some temp text" />
</FrameLayout>
4: 在片段中添加 RecyclerView
前往第二个片段,粘贴以下所有代码:
public class SecondFragment extends Fragment {
// 添加 RecyclerView 成员
private RecyclerView recyclerView;
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
// 为该片段填充布局
View view = inflater.inflate(R.layout.fragment_second, container, false);
// 添加以下行以创建 RecyclerView
recyclerView = view.findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
recyclerView.setAdapter(new RandomNumListAdapter(1234));
return view;
}
}
5: 为 RecyclerView
创建一个 ViewHolder
类
创建如下类:
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView view;
public RecyclerViewHolder(@NonNull View itemView) {
super(itemView);
view = itemView.findViewById(R.id.randomText);
}
public TextView getView() {
return view;
}
}
6: 创建一个 ListAdapter
public class RandomNumListAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private Random random;
public RandomNumListAdapter(int seed) {
this.random = new Random(seed);
}
@Override
public int getItemViewType(final int position) {
return R.layout.frame_textview;
}
@NonNull
@Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new RecyclerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
holder.getView().setText(String.valueOf(random.nextInt()));
}
@Override
public int getItemCount() {
return 100;
}
}
您可以用随机数字替换这些项。
英文:
1 : Create new project
-> select Basic Activity
there is to fragment inside your activity and a button to switch between fragment A to B
2 : create a RecyclerView
resource in SecondFragment
(fragment B )
add the following line into second fragment :
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="409dp"
android:layout_height="460dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/button_second"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
3 : create a frame layout with textview
go to /res/layout/newlayout/layoutresource
file and create an framlayout
inside the layout replace this codes
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<TextView
android:id="@+id/randomText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="This is some temp text" />
</FrameLayout>
4: Add RecyclerView
in Fragment
go to second fragment and paste all of these
public class SecondFragment extends Fragment {
// Add RecyclerView member
private RecyclerView recyclerView;
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
// Add the following lines to create RecyclerView
recyclerView = view.findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
recyclerView.setAdapter(new RandomNumListAdapter(1234));
return view;
}
5 : create a class Viewholder
for recyclerview
like this :
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView view;
public RecyclerViewHolder(@NonNull View itemView) {
super(itemView);
view = itemView.findViewById(R.id.randomText);
}
public TextView getView(){
return view;
}
}
6 : Create ListAdapter
public class RandomNumListAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private Random random;
public RandomNumListAdapter(int seed) {
this.random = new Random(seed);
}
@Override
public int getItemViewType(final int position) {
return R.layout.frame_textview;
}
@NonNull
@Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new RecyclerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
holder.getView().setText(String.valueOf(random.nextInt()));
}
@Override
public int getItemCount() {
return 100;
}
}
you can replace your items with random numbers .
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论