Android
RecyclerViewおよびLayoutManager
サーチ…
動的スパン数を持つGridLayoutManager
グリッドレイアウトレイアウトマネージャを使用してrecyclerviewを作成するときは、コンストラクタでスパン数を指定する必要があります。スパン数は列の数を表します。これはかなりぎこちなく、画面サイズや画面の向きを考慮していません。 1つのアプローチは、さまざまな画面サイズの複数のレイアウトを作成することです。以下に、さらにもう一つのダイナミックなアプローチを示します。
最初に、次のようにカスタムRecyclerViewクラスを作成します。
public class AutofitRecyclerView extends RecyclerView {
private GridLayoutManager manager;
private int columnWidth = -1;
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);
}
}
}
このクラスは、recyclerviewに収まる列の数を決定します。これを使用するには、次のようにlayout.xmlに配置する必要があります:
<?xml version="1.0" encoding="utf-8"?>
<com.path.to.your.class.autofitRecyclerView.AutofitRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/auto_fit_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="200dp"
android:clipToPadding="false"
/>
columnWidth属性を使用することに注意してください。 recyclerviewは、使用可能なスペースに収まる列の数を決定するためにそれを必要とします。
あなたのアクティビティ/フラグメントでは、recylerviewへの参照を取得し、アダプタ(および追加したいアイテム装飾やアニメーション)を設定します。 レイアウトマネージャを設定しないでください
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.auto_fit_recycler_view);
recyclerView.setAdapter(new MyAdapter());
(MyAdapterはアダプタクラスです)
あなたは今、画面サイズに合うようにスパン数(すなわち列)を調整するrecyclerviewを持っています。最後に、columnsをrecyclerviewの中央に配置することもできます(デフォルトではlayout_startに揃えられています)。 AutofitRecyclerViewクラスを少し変更することで、これを行うことができます。まず、recyclerviewに内部クラスを作成します。これは、GridLayoutManagerから継承するクラスになります。行を中央に配置するには、左右に十分な余白が追加されます。
public class AutofitRecyclerView extends RecyclerView {
// etc see above
private class CenteredGridLayoutManager extends GridLayoutManager {
public CenteredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CenteredGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}
public CenteredGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}
@Override
public int getPaddingLeft() {
final int totalItemWidth = columnWidth * getSpanCount();
if (totalItemWidth >= AutofitRecyclerView.this.getMeasuredWidth()) {
return super.getPaddingLeft(); // do nothing
} else {
return Math.round((AutofitRecyclerView.this.getMeasuredWidth() / (1f + getSpanCount())) - (totalItemWidth / (1f + getSpanCount())));
}
}
@Override
public int getPaddingRight() {
return getPaddingLeft();
}
}
}
次に、AutofitRecyclerViewでLayoutManagerを設定すると、次のようにCenteredGridLayoutManagerが使用されます。
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 CenteredGridLayoutManager(getContext(), 1);
setLayoutManager(manager);
}
以上です!あなたはダイナミックなスパンマウント、centerlined gridlayoutmanagerベースのrecyclerviewを持っています。
ソース:
Gridlayoutマネージャを使用してrecyclerviewにヘッダビューを追加する
gridlayoutを持つrecyclerviewにヘッダーを追加するには、最初にヘッダー・ビューがコンテンツに使用される標準セルではなく、最初の位置であることをアダプターに伝える必要があります。次に、レイアウトマネージャーは、最初の位置がリスト全体の*スパン数に等しいスパンを持つべきであることを伝えなければなりません。 *
通常のRecyclerView.Adapterクラスを使用し、次のように設定します。
public class HeaderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int ITEM_VIEW_TYPE_HEADER = 0;
private static final int ITEM_VIEW_TYPE_ITEM = 1;
private List<YourModel> mModelList;
public HeaderAdapter (List<YourModel> modelList) {
mModelList = modelList;
}
public boolean isHeader(int position) {
return position == 0;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if (viewType == ITEM_VIEW_TYPE_HEADER) {
View headerView = inflater.inflate(R.layout.header, parent, false);
return new HeaderHolder(headerView);
}
View cellView = inflater.inflate(R.layout.gridcell, parent, false);
return new ModelHolder(cellView);
}
@Override
public int getItemViewType(int position) {
return isHeader(position) ? ITEM_VIEW_TYPE_HEADER : ITEM_VIEW_TYPE_ITEM;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder h, int position) {
if (isHeader(position)) {
return;
}
final YourModel model = mModelList.get(position -1 ); // Subtract 1 for header
ModelHolder holder = (ModelHolder) h;
// populate your holder with data from your model as usual
}
@Override
public int getItemCount() {
return _categories.size() + 1; // add one for the header
}
}
次に、activity / fragment:
final HeaderAdapter adapter = new HeaderAdapter (mModelList);
final GridLayoutManager manager = new GridLayoutManager();
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return adapter.isHeader(position) ? manager.getSpanCount() : 1;
}
});
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(adapter);
ヘッダーに加えて、ヘッダーの代わりに同じフッターを追加することもできます。
出典: Chiu-Ki ChanのSquare Islandブログ
LinearLayoutManagerを使用したシンプルなリスト
この例では、カスタムPlace
オブジェクトのArrayList
をデータセットとして使用して、画像と名前のある場所のリストを追加します。
アクティビティのレイアウト
アクティビティ/フラグメントのレイアウト、またはRecyclerViewが使用される場所には、RecyclerViewが含まれていなければなりません。 ScrollViewや特定のレイアウトは必要ありません。
<?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="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
データモデルを定義する
int
、 String
、 float[]
、 CustomObject
など、任意のクラスまたはプリミティブデータ型をモデルとして使用できます。 RecyclerViewは、このオブジェクト/プリミティブのList
を参照します。
リスト項目がテキスト、数字、画像(この例では場所を含む)のような異なるデータ型を参照する場合は、カスタムオブジェクトを使用することをお勧めします。
public class Place {
// these fields will be shown in a list item
private Bitmap image;
private String name;
// typical constructor
public Place(Bitmap image, String name) {
this.image = image;
this.name = name;
}
// getters
public Bitmap getImage() {
return image;
}
public String getName() {
return name;
}
}
リストアイテムのレイアウト
各リスト項目に使用されるxmlレイアウトファイルを指定する必要があります。この例では、イメージにはImageView
、名前にはTextView
が使用されています。 LinearLayout
はImageView
を左に配置し、 TextView
は画像に右に配置します。
<?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="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="8dp">
<ImageView
android:id="@+id/image"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
RecyclerViewアダプタとViewHolderを作成する
次に、あなたが継承する必要がありRecyclerView.Adapter
とRecyclerView.ViewHolder
。通常のクラス構造は次のようになります。
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
// ...
public class ViewHolder extends RecyclerView.ViewHolder {
// ...
}
}
まず、 ViewHolder
を実装しViewHolder
。デフォルトコンストラクタを継承し、必要なビューをいくつかのフィールドに保存します:
public class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private TextView nameView;
public ViewHolder(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.image);
nameView = (TextView) itemView.findViewById(R.id.name);
}
}
アダプタのコンストラクタは、使用されるデータセットを設定します。
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
private List<Place> mPlaces;
public PlaceListAdapter(List<Place> contacts) {
mPlaces = contacts;
}
// ...
}
カスタムリストアイテムレイアウトを使用するには、 onCreateViewHolder(...)
メソッドをオーバーライドします。この例では、レイアウトファイルのplace_list_item.xml
はplace_list_item.xml
です。
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
// ...
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.place_list_item,
parent,
false
);
return new ViewHolder(view);
}
// ...
}
onBindViewHolder(...)
では、実際にビューのコンテンツを設定しています。指定された位置のList
でそれを見つけて、 ViewHolder
のビューにイメージと名前を設定して、使用されたモデルを取得します。
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
// ...
@Override
public void onBindViewHolder(PlaceListAdapter.ViewHolder viewHolder, int position) {
Place place = mPlaces.get(position);
viewHolder.nameView.setText(place.getName());
viewHolder.imageView.setImageBitmap(place.getImage());
}
// ...
}
また、 List
のサイズを返すgetItemCount()
を実装する必要があります。
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
// ...
@Override
public int getItemCount() {
return mPlaces.size();
}
// ...
}
(ランダムデータを生成する)
この例では、ランダムな場所を生成します。
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
List<Place> places = randomPlaces(5);
// ...
}
private List<Place> randomPlaces(int amount) {
List<Place> places = new ArrayList<>();
for (int i = 0; i < amount; i++) {
places.add(new Place(
BitmapFactory.decodeResource(getResources(), Math.random() > 0.5 ?
R.drawable.ic_account_grey600_36dp :
R.drawable.ic_android_grey600_36dp
),
"Place #" + (int) (Math.random() * 1000)
));
}
return places;
}
RecyclerViewとPlaceListAdapterおよびデータセットを接続する
RecyclerView
とアダプタの接続は非常に簡単です。リストレイアウトを実現するには、レイアウトマネージャとしてLinearLayoutManager
を設定する必要があります。
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setAdapter(new PlaceListAdapter(places));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
完了!
StaggeredGridLayoutManager
- レイアウトXMLファイルにRecyclerViewを作成します:
<android.support.v7.widget.RecyclerView
android:id="@+id/recycleView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
データを保持するModelクラスを作成します。
public class PintrestItem { String url; public PintrestItem(String url,String name){ this.url=url; this.name=name; } public String getUrl() { return url; } public String getName(){ return name; } String name; }
RecyclerViewアイテムを保持するレイアウトファイルを作成します。
<ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:scaleType="centerCrop" android:id="@+id/imageView"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:id="@+id/name" android:layout_gravity="center" android:textColor="@android:color/white"/>
RecyclerViewのアダプタクラスを作成します。
public class PintrestAdapter extends RecyclerView.Adapter<PintrestAdapter.PintrestViewHolder>{ private ArrayList<PintrestItem>images; Picasso picasso; Context context; public PintrestAdapter(ArrayList<PintrestItem>images,Context context){ this.images=images; picasso=Picasso.with(context); this.context=context; } @Override public PintrestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.pintrest_layout_item,parent,false); return new PintrestViewHolder(view); } @Override public void onBindViewHolder(PintrestViewHolder holder, int position) { picasso.load(images.get(position).getUrl()).into(holder.imageView); holder.tv.setText(images.get(position).getName()); } @Override public int getItemCount() { return images.size(); } public class PintrestViewHolder extends RecyclerView.ViewHolder{ ImageView imageView; TextView tv; public PintrestViewHolder(View itemView) { super(itemView); imageView=(ImageView)itemView.findViewById(R.id.imageView); tv=(TextView)itemView.findViewById(R.id.name); } } }
アクティビティーまたはフラグメントでRecyclerViewをインスタンス化する:
RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView); //Create the instance of StaggeredGridLayoutManager with 2 rows i.e the span count and provide the orientation StaggeredGridLayoutManager layoutManager=new new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager); // Create Dummy Data and Add to your List<PintrestItem> List<PintrestItem>items=new ArrayList<PintrestItem> items.add(new PintrestItem("url of image you want to show","imagename")); items.add(new PintrestItem("url of image you want to show","imagename")); items.add(new PintrestItem("url of image you want to show","imagename")); recyclerView.setAdapter(new PintrestAdapter(items,getContext() );
build.gradleファイルにPicassoの依存関係を追加するのを忘れないでください:
compile 'com.squareup.picasso:picasso:2.5.2'