Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
138 views
in Technique[技术] by (71.8m points)

android - Create a RecyclerView with multiple view from layouts

I am trying to have 2 layout in one 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.

enter image description here

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);*/
        }



    }



}

This is the grid item layout

<?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;
    }
    }

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>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is the answer

Follow this steps

First Create a two layout for your Multiple viewType

SAMPLE CODE

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

<?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>

Now you need to create two RecyclerView.ViewHolder for your both viewType

Now you need to Override getItemViewType()

  • it Return the viewType of the item at position for the purposes of view recycling.

Now in your onCreateViewHolder() method you need to return your instance of your ViewHolder based on your viewType which you will get using getItemViewType() method

Than in your onBindViewHolder() method based your viewType set your view property

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);

        }
    }
}

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 class

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 = findViewBy

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...