RecyclerView
through config LayoutManager
. It's weakness in building grid layout is cannot auto fixed number of columns of grid view in default. So, in this tip, I will present a solution to do this trick by custom, make a subclass of RecyclerView
.
Customizing the RecyclerView
GridLayoutManager
as RecyclerView
's layout manager here (to define that it will behave as a GridView
):
AutofitRecyclerView.java
package info.devexchanges.autocolumn;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
public class AutofitRecyclerView extends RecyclerView {
private GridLayoutManager manager;
private int columnWidth = -1; //default value
public AutofitRecyclerView(Context context) {
super(context);
init(context, null);
}
public AutofitRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public AutofitRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
int[] attrsArray = {android.R.attr.columnWidth};
TypedArray array = context.obtainStyledAttributes(attrs, attrsArray);
columnWidth = array.getDimensionPixelSize(0, -1);
array.recycle();
}
manager = new GridLayoutManager(getContext(), 1);
setLayoutManager(manager);
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
if (columnWidth > 0) {
int spanCount = Math.max(1, getMeasuredWidth() / columnWidth);
manager.setSpanCount(spanCount);
}
}
}
Usage in UI (Activity/Fragment)
AutofitRecyclerView
object in activity layout out (xml file) like this:
activity_main.xml
There is no special point in the activity Java code, we mustn't set layout manager for <?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"
android:orientation="vertical">
<info.devexchanges.autocolumn.AutofitRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:columnWidth="@dimen/column_width"
android:padding="@dimen/activity_horizontal_margin" />
</LinearLayout>
AutofitRecyclerView
anymore, we have done in it's constructor above:
MainActivity.java
Customizing the package info.devexchanges.autocolumn;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auto_fit_recycler_view);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(new NumberedAdapter(30));
}
}
RecyclerView.ViewHolder
, handling each grid view item click event in onBindViewHolder()
, this is adapter for our RecyclerView
:
NumberedAdapter.java
Layout for each grid view item:
package info.devexchanges.autocolumn;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class NumberedAdapter extends RecyclerView.Adapter<NumberedAdapter.ViewHolder> {
private List<String> labels;
public NumberedAdapter(int count) {
labels = new ArrayList<>(count);
for (int i = 0; i < count; ++i) {
labels.add(String.valueOf(i));
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final String label = labels.get(position);
holder.textView.setText(label);
//handling item click event
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(holder.textView.getContext(), label, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return labels.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text);
}
}
}
layout_item.xml
In order to make this
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/item_margin"
android:background="@drawable/light_blue_background"
android:gravity="center"
android:padding="8dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
RecyclerView
compatible with multiple devices, I declared some dimensions value in dimensions resource:
styles.xml
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="item_margin">8dp</dimen>
<dimen name="column_width">80dp</dimen>
</resources>
values-w820dp/styles.xml
Running this example, we'll have this output:<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
<dimen name="item_margin">14dp</dimen>
<dimen name="column_width">120dp</dimen>
</resources>
When rotating device to landscape mode, number of columns will be increased to fit with new device width:
Running in a 7" tablet (Samsung Galaxy Tab 4):
Clicking at grid view item:
Conclusions
RecyclerView
's constructor, we can make a auto-column grid view easily. Further, to deep understanding this widget, you can visit this tag link to read other posts about it. Thanks for reading!