如何在每个子类中显示不同的片段/视图?Android

huangapple go评论95阅读模式
英文:

How is it possible to display different fragment/view for each subclass? Android

问题

我有一个Message对象列表。Message是一个抽象类,有两个子类:TextMessageImageMessage

我想要在可滚动的列表中显示这些消息,根据消息的类型进行显示。如何创建一个自定义的视图/片段,以抽象类作为参数,并根据实际的子类创建其中的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 类声明一个抽象的 getViewTypebindToView 方法,如下所示:

Message.java

  1. public abstract class Message {
  2. public abstract int getViewType();
  3. public abstract void bindToView(View messageView);
  4. public enum TYPE {
  5. TextMessage,
  6. ImageMessage
  7. }
  8. public static View createView(int typeOrdinal, Context context) {
  9. switch (TYPE.values()[typeOrdinal]) {
  10. case TextMessage:
  11. return TextMessage.createNewView(context);
  12. case ImageMessage:
  13. return ImageMessage.createNewView(context);
  14. default:
  15. throw new RuntimeException("Incorrect typeOrdinal: " + typeOrdinal);
  16. }
  17. }
  18. }

TextMessage.java

  1. public class TextMessage extends Message {
  2. public static TextView createNewView(Context context) {
  3. return new TextView(context);
  4. }
  5. @Override
  6. public void bindToView(View messageView) {
  7. ((TextView) messageView).setText("一些特定的文本");
  8. }
  9. @Override
  10. int getViewType() {
  11. return TYPE.TextMessage.ordinal();
  12. }
  13. }

ImageMessage.java

  1. public class ImageMessage extends Message {
  2. public static ImageView createNewView(Context context) {
  3. return new ImageView(context);
  4. }
  5. @Override
  6. public void bindToView(View messageView) {
  7. Bitmap forExampleSomeBitmap = null; // TODO 实现
  8. ((ImageView) messageView).setImageBitmap(forExampleSomeBitmap);
  9. }
  10. @Override
  11. int getViewType() {
  12. return TYPE.ImageMessage.ordinal();
  13. }
  14. }

然后,保持来自该 Google 示例代码的所有其余代码不变,你的 RecyclerView.Adapter 可能会如下所示:

  1. public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
  2. private Message[] mDataset;
  3. public static class MyViewHolder extends RecyclerView.ViewHolder {
  4. public View messageView;
  5. public MyViewHolder(View v) {
  6. super(v);
  7. messageView = v;
  8. }
  9. }
  10. @NonNull
  11. @Override
  12. public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  13. return new MyViewHolder(Message.createView(viewType, parent.getContext()));
  14. }
  15. @Override
  16. public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
  17. mDataset[position].bindToView(holder.messageView);
  18. }
  19. @Override
  20. public int getItemViewType(int position) {
  21. return mDataset[position].getViewType();
  22. }
  23. @Override
  24. public int getItemCount() {
  25. return mDataset.length;
  26. }
  27. }

如果你想了解更多关于 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

  1. public abstract class Message {
  2. public abstract int getViewType();
  3. public abstract void bindToView(View messageView);
  4. public enum TYPE {
  5. TextMessage,
  6. ImageMessage
  7. }
  8. public static View createView(int typeOrdinal, Context context) {
  9. switch (TYPE.values()[typeOrdinal]) {
  10. case TextMessage:
  11. return TextMessage.createNewView(context);
  12. case ImageMessage:
  13. return ImageMessage.createNewView(context);
  14. default:
  15. throw new RuntimeException(&quot;Incorrect typeOrdinal: &quot; + typeOrdinal);
  16. }
  17. }
  18. }

TextMessage.java

  1. public class TextMessage extends Message {
  2. public static TextView createNewView(Context context) {
  3. return new TextView(context);
  4. }
  5. @Override
  6. public void bindToView(View messageView) {
  7. ((TextView) messageView).setText(&quot;some specific text&quot;);
  8. }
  9. @Override
  10. int getViewType() {
  11. return TYPE.TextMessage.ordinal();
  12. }
  13. }

ImageMessage.java

  1. public class ImageMessage extends Message {
  2. public static ImageView createNewView(Context context) {
  3. return new ImageView(context);
  4. }
  5. @Override
  6. public void bindToView(View messageView) {
  7. Bitmap forExampleSomeBitmap = null; // TODO implement
  8. ((ImageView) messageView).setImageBitmap(forExampleSomeBitmap);
  9. }
  10. @Override
  11. int getViewType() {
  12. return TYPE.ImageMessage.ordinal();
  13. }
  14. }

And then With all the rest of the code from that google sample code unchanged, your RecyclerView.Adapter could then look like this:

  1. public class MyAdapter extends RecyclerView.Adapter&lt;MyAdapter.MyViewHolder&gt; {
  2. private Message[] mDataset;
  3. public static class MyViewHolder extends RecyclerView.ViewHolder {
  4. public View messageView;
  5. public MyViewHolder(View v) {
  6. super(v);
  7. messageView = v;
  8. }
  9. }
  10. @NonNull
  11. @Override
  12. public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  13. return new MyViewHolder(Message.createView(viewType, parent.getContext()));
  14. }
  15. @Override
  16. public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
  17. mDataset[position].bindToView(holder.messageView);
  18. }
  19. @Override
  20. public int getItemViewType(int position) {
  21. return mDataset[position].getViewType();
  22. }
  23. @Override
  24. public int getItemCount() {
  25. return mDataset.length;
  26. }
  27. }

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 资源

将以下行添加到第二个片段:

  1. <androidx.recyclerview.widget.RecyclerView
  2. android:id="@+id/recyclerview"
  3. android:layout_width="409dp"
  4. android:layout_height="460dp"
  5. android:layout_marginStart="1dp"
  6. android:layout_marginTop="1dp"
  7. android:layout_marginEnd="1dp"
  8. android:layout_marginBottom="1dp"
  9. android:visibility="visible"
  10. app:layout_constraintBottom_toTopOf="@+id/button_second"
  11. app:layout_constraintEnd_toEndOf="parent"
  12. app:layout_constraintStart_toStartOf="parent"
  13. app:layout_constraintTop_toTopOf="parent" />

3: 创建一个带有 TextView 的帧布局

前往 /res/layout/newlayout/layoutresource 文件,创建一个帧布局,将以下代码替换到布局内:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="wrap_content"
  5. android:layout_height="wrap_content"
  6. android:layout_margin="8dp">
  7. <TextView
  8. android:id="@+id/randomText"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. tools:text="This is some temp text" />
  12. </FrameLayout>

4: 在片段中添加 RecyclerView

前往第二个片段,粘贴以下所有代码:

  1. public class SecondFragment extends Fragment {
  2. // 添加 RecyclerView 成员
  3. private RecyclerView recyclerView;
  4. @Override
  5. public View onCreateView(
  6. LayoutInflater inflater, ViewGroup container,
  7. Bundle savedInstanceState
  8. ) {
  9. // 为该片段填充布局
  10. View view = inflater.inflate(R.layout.fragment_second, container, false);
  11. // 添加以下行以创建 RecyclerView
  12. recyclerView = view.findViewById(R.id.recyclerview);
  13. recyclerView.setHasFixedSize(true);
  14. recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
  15. recyclerView.setAdapter(new RandomNumListAdapter(1234));
  16. return view;
  17. }
  18. }

5: 为 RecyclerView 创建一个 ViewHolder

创建如下类:

  1. public class RecyclerViewHolder extends RecyclerView.ViewHolder {
  2. private TextView view;
  3. public RecyclerViewHolder(@NonNull View itemView) {
  4. super(itemView);
  5. view = itemView.findViewById(R.id.randomText);
  6. }
  7. public TextView getView() {
  8. return view;
  9. }
  10. }

6: 创建一个 ListAdapter

  1. public class RandomNumListAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
  2. private Random random;
  3. public RandomNumListAdapter(int seed) {
  4. this.random = new Random(seed);
  5. }
  6. @Override
  7. public int getItemViewType(final int position) {
  8. return R.layout.frame_textview;
  9. }
  10. @NonNull
  11. @Override
  12. public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  13. View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
  14. return new RecyclerViewHolder(view);
  15. }
  16. @Override
  17. public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
  18. holder.getView().setText(String.valueOf(random.nextInt()));
  19. }
  20. @Override
  21. public int getItemCount() {
  22. return 100;
  23. }
  24. }

您可以用随机数字替换这些项。

英文:

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 :

  1. &lt;androidx.recyclerview.widget.RecyclerView
  2. android:id=&quot;@+id/recyclerview&quot;
  3. android:layout_width=&quot;409dp&quot;
  4. android:layout_height=&quot;460dp&quot;
  5. android:layout_marginStart=&quot;1dp&quot;
  6. android:layout_marginTop=&quot;1dp&quot;
  7. android:layout_marginEnd=&quot;1dp&quot;
  8. android:layout_marginBottom=&quot;1dp&quot;
  9. android:visibility=&quot;visible&quot;
  10. app:layout_constraintBottom_toTopOf=&quot;@+id/button_second&quot;
  11. app:layout_constraintEnd_toEndOf=&quot;parent&quot;
  12. app:layout_constraintStart_toStartOf=&quot;parent&quot;
  13. app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;

3 : create a frame layout with textview
go to /res/layout/newlayout/layoutresource file and create an framlayout
inside the layout replace this codes

  1. &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  2. &lt;FrameLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
  3. xmlns:tools=&quot;http://schemas.android.com/tools&quot;
  4. android:layout_width=&quot;wrap_content&quot;
  5. android:layout_height=&quot;wrap_content&quot;
  6. android:layout_margin=&quot;8dp&quot;&gt;
  7. &lt;TextView
  8. android:id=&quot;@+id/randomText&quot;
  9. android:layout_width=&quot;wrap_content&quot;
  10. android:layout_height=&quot;wrap_content&quot;
  11. tools:text=&quot;This is some temp text&quot; /&gt;
  12. &lt;/FrameLayout&gt;

4: Add RecyclerView in Fragment
go to second fragment and paste all of these

  1. public class SecondFragment extends Fragment {
  2. // Add RecyclerView member
  3. private RecyclerView recyclerView;
  4. @Override
  5. public View onCreateView(
  6. LayoutInflater inflater, ViewGroup container,
  7. Bundle savedInstanceState
  8. ) {
  9. // Inflate the layout for this fragment
  10. View view = inflater.inflate(R.layout.fragment_second, container, false);
  11. // Add the following lines to create RecyclerView
  12. recyclerView = view.findViewById(R.id.recyclerview);
  13. recyclerView.setHasFixedSize(true);
  14. recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
  15. recyclerView.setAdapter(new RandomNumListAdapter(1234));
  16. return view;
  17. }

5 : create a class Viewholder for recyclerview
like this :

  1. public class RecyclerViewHolder extends RecyclerView.ViewHolder {
  2. private TextView view;
  3. public RecyclerViewHolder(@NonNull View itemView) {
  4. super(itemView);
  5. view = itemView.findViewById(R.id.randomText);
  6. }
  7. public TextView getView(){
  8. return view;
  9. }
  10. }

6 : Create ListAdapter

  1. public class RandomNumListAdapter extends RecyclerView.Adapter&lt;RecyclerViewHolder&gt; {
  2. private Random random;
  3. public RandomNumListAdapter(int seed) {
  4. this.random = new Random(seed);
  5. }
  6. @Override
  7. public int getItemViewType(final int position) {
  8. return R.layout.frame_textview;
  9. }
  10. @NonNull
  11. @Override
  12. public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
  13. View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
  14. return new RecyclerViewHolder(view);
  15. }
  16. @Override
  17. public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
  18. holder.getView().setText(String.valueOf(random.nextInt()));
  19. }
  20. @Override
  21. public int getItemCount() {
  22. return 100;
  23. }
  24. }

you can replace your items with random numbers .

huangapple
  • 本文由 发表于 2020年8月30日 02:38:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/63650553.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定