Hello guys, welcome to another useful post Expandable RecyclerView Android. In this post, we will build Expandable RecyclerView Items for our List. You might already know we use RecyclerView to display a List of data in our application. This time we will do the same we will create a RecyclerView, but the items of the RecyclerView will toggle on tapping. So initially some details of the list items will be hidden, and when we tap on the item it will show us the remaining detail by expanding itself. Sounds confusing? 😉 Don’t worry it is very easy. Let’s start.
Table of Contents
The List Design
- The first step is to decide the design of our List. So below you can see the design I have decided.
- I hope you got the basic idea of our Expandable RecyclerView from the image shown above. Now lets start creating our Android Project.
Expandable RecyclerView Android
Creating a New Project
- As always we will create a new Android Studio project.
- Here I have created a project named ExpandableRecyclerView using an empty activity.
Adding Dependencies
- Here is my app level build.gradle file. You need to add these dependencies to your project as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.1' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' implementation 'com.google.android.material:material:1.2.1' implementation 'com.android.volley:volley:1.1.1' implementation 'com.github.bumptech.glide:glide:4.11.0' } |
- I am using RecyclerView, CardView for building the List and Volley and Glide for network request and loading images from URL.
Web Service
- We will fetch the data from the following web services. You can use the same or you can also create your own.
1 2 3 |
https://simplifiedcoding.net/demos/marvel/ |
- When you will go to the above URL you will see the following JSON data.
Data Model
- Now to store the above JSON data, we need to create a model class. So create a new class named Hero.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package net.simplifiedlearning.expandablerecyclerview; /** * Created by Belal on 7/15/2017. */ public class Hero { private String name, realName, team, firstAppearance, createdBy, publisher, imageUrl, bio; public Hero(String name, String realName, String team, String firstAppearance, String createdBy, String publisher, String imageUrl, String bio) { this.name = name; this.realName = realName; this.team = team; this.firstAppearance = firstAppearance; this.createdBy = createdBy; this.publisher = publisher; this.imageUrl = imageUrl; this.bio = bio; } public String getName() { return name; } public String getRealName() { return realName; } public String getTeam() { return team; } public String getFirstAppearance() { return firstAppearance; } public String getCreatedBy() { return createdBy; } public String getPublisher() { return publisher; } public String getImageUrl() { return imageUrl; } public String getBio() { return bio; } } |
Adding RecyclerView
- Now come back to the layout of your MainActivity which is usually activity_main.xml and add a RecyclerView here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> |
Designing List Layout
- Now let’s design the xml layout for the List. So first create a new layout resource file named list_layout_heroes.xml (or you can give it any name), and write the following xml code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/textViewName" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ff3847" android:padding="10dp" android:text="Iron Man" android:textAlignment="center" android:textAppearance="@style/Base.TextAppearance.AppCompat.Large.Inverse" /> <LinearLayout android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:animateLayoutChanges="true" android:orientation="vertical" android:visibility="gone"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="fitXY" /> <TableLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="15dp"> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Real Name " /> <TextView android:id="@+id/textViewRealName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tony Stark" android:textStyle="bold" /> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Team " /> <TextView android:id="@+id/textViewTeam" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Avengers" android:textStyle="bold" /> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="First Appearance " /> <TextView android:id="@+id/textViewFirstAppearance" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1974" android:textStyle="bold" /> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Created By " /> <TextView android:id="@+id/textViewCreatedBy" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stan Lee" android:textStyle="bold" /> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Publisher " /> <TextView android:id="@+id/textViewPublisher" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Marvel Comics" android:textStyle="bold" /> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bio " /> <TextView android:id="@+id/textViewBio" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="textMultiLine" android:text="Steven Rogers was born in the Lower East Side of Manhattan, New York City, in 1925 to poor Irish immigrants, Sarah and Joseph Rogers.[54] Joseph died when Steve was a child, and Sarah died of pneumonia while Steve was a teen. By early 1940, before America's entry into World War II, Rogers is a tall, scrawny fine arts student specializing in illustration and a comic book writer and artist." android:textStyle="bold" /> </TableRow> </TableLayout> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> </RelativeLayout> |
- So thats it for the layout. The above xml code will display the following layout.
- You can see only name is visible as the other thing will be visible after tapping the name. Now lets create an slide down animation effect and custom RecyclerView adapter.
Slide Down Animation
- Inside the res folder create a new folder named anim. Inside this folder create a new anim resource file (basically a normal xml file) and write the following xml code.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:duration="500" android:fromXScale="1.0" android:fromYScale="0.0" android:toXScale="1.0" android:toYScale="1.0" /> </set> |
Creating RecyclerView Adapter
- Create a new class named HeroAdapter.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
public class HeroAdapter extends RecyclerView.Adapter<HeroAdapter.HeroViewHolder> { private List<Hero> heroList; private Context context; private static int currentPosition = 0; public HeroAdapter(List<Hero> heroList, Context context) { this.heroList = heroList; this.context = context; } @Override public HeroViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_layout_heroes, parent, false); return new HeroViewHolder(v); } @Override public void onBindViewHolder(final HeroViewHolder holder, final int position) { Hero hero = heroList.get(position); holder.textViewName.setText(hero.getName()); holder.textViewRealName.setText(hero.getRealName()); holder.textViewTeam.setText(hero.getTeam()); holder.textViewFirstAppearance.setText(hero.getFirstAppearance()); holder.textViewCreatedBy.setText(hero.getCreatedBy()); holder.textViewPublisher.setText(hero.getPublisher()); holder.textViewBio.setText(hero.getBio().trim()); Glide.with(context).load(hero.getImageUrl()).into(holder.imageView); holder.linearLayout.setVisibility(View.GONE); //if the position is equals to the item position which is to be expanded if (currentPosition == position) { //creating an animation Animation slideDown = AnimationUtils.loadAnimation(context, R.anim.slide_down); //toggling visibility holder.linearLayout.setVisibility(View.VISIBLE); //adding sliding effect holder.linearLayout.startAnimation(slideDown); } holder.textViewName.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //getting the position of the item to expand it currentPosition = position; //reloding the list notifyDataSetChanged(); } }); } @Override public int getItemCount() { return heroList.size(); } class HeroViewHolder extends RecyclerView.ViewHolder { TextView textViewName, textViewRealName, textViewTeam, textViewFirstAppearance, textViewCreatedBy, textViewPublisher, textViewBio; ImageView imageView; LinearLayout linearLayout; HeroViewHolder(View itemView) { super(itemView); textViewName = itemView.findViewById(R.id.textViewName); textViewRealName = itemView.findViewById(R.id.textViewRealName); textViewTeam = itemView.findViewById(R.id.textViewTeam); textViewFirstAppearance = itemView.findViewById(R.id.textViewFirstAppearance); textViewCreatedBy = itemView.findViewById(R.id.textViewCreatedBy); textViewPublisher = itemView.findViewById(R.id.textViewPublisher); textViewBio = itemView.findViewById(R.id.textViewBio); imageView = itemView.findViewById(R.id.imageView); linearLayout = itemView.findViewById(R.id.linearLayout); } } } |
- The above RecyclerView adapter is same as we created the RecyclerView in previous tutorials. The only difference is we are toggling the visibility. I have added the comments where I am doing the toggling. Rest of the code is same.
Getting Data from Web Service and Loading it to RecyclerView
- Now come back to MainActivity.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
public class MainActivity extends AppCompatActivity { final String URL_GET_DATA = "https://simplifiedcoding.net/demos/marvel/"; RecyclerView recyclerView; HeroAdapter adapter; List<Hero> heroList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recyclerView); recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); heroList = new ArrayList<>(); loadHeroes(); } private void loadHeroes() { StringRequest stringRequest = new StringRequest(Request.Method.GET, URL_GET_DATA, new Response.Listener<String>() { @Override public void onResponse(String response) { try { JSONArray jsonArray = new JSONArray(response); for (int i = 0; i < jsonArray.length(); i++) { JSONObject obj = jsonArray.getJSONObject(i); Hero hero = new Hero( obj.getString("name"), obj.getString("realname"), obj.getString("team"), obj.getString("firstappearance"), obj.getString("createdby"), obj.getString("publisher"), obj.getString("imageurl"), obj.getString("bio") ); heroList.add(hero); } adapter = new HeroAdapter(heroList, getApplicationContext()); recyclerView.setAdapter(adapter); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); RequestQueue requestQueue = Volley.newRequestQueue(this); requestQueue.add(stringRequest); } } |
- Thats it now you can try running your application.
- Bingo! It is working fine. If you are in confusions, you can get the source code of this Expandable RecyclerView Android project from the link given below.
So that’s all for this Expandable RecyclerView Android tutorial. Hope you found it helpful. For any queries or feedback, you can leave your comments below. And I will soon post some more useful content for you. Thank You 🙂