Android
RecyclerView
수색…
소개
RecyclerView 는 개선 된 성능 및 추가 기능으로 목록보기의 고급 버전입니다.
매개 변수
매개 변수 | 세부 묘사 |
---|---|
어댑터 | 데이터 세트의 항목을 나타내는 뷰를 제공하는 RecyclerView.Adapter의 서브 클래스입니다. |
위치 | 어댑터 내의 데이터 항목의 위치 |
색인 | getChildAt (int)를 호출 할 때 사용 된 첨부 된 자식 뷰의 인덱스입니다. 직위와 대조 |
제본 | 어댑터 내의 위치에 대응하는 데이터를 표시하기위한 아이 뷰를 준비하는 프로세스 |
재활용 (보기) | 이전에 특정 어댑터 위치에 대한 데이터를 표시하는 데 사용 된보기는 나중에 동일한 유형의 데이터를 나중에 다시 표시하기 위해 캐시에 배치 될 수 있습니다. 이는 초기 레이아웃 인플레이션 또는 건설을 생략함으로써 성능을 획기적으로 향상시킬 수 있습니다. |
스크랩 (보기) | 레이아웃 중에 일시적으로 detached 상태에 들어간 아이 뷰입니다. 스크랩 뷰는 부모 RecyclerView에서 완전히 분리되지 않고 재사용 될 수 있습니다. 리 바인딩이 필요하지 않거나 뷰가 더럽다고 간주되는 경우 어댑터가 수정하지 않으면 수정되지 않습니다. |
더티 (보기) | 표시되기 전에 어댑터가 리 바인드해야하는 하위보기 |
비고
RecyclerView
는 큰 데이터 세트에 제한된 창을 제공하는 유연한보기입니다.
RecyclerView
를 사용하기 전에 build.gradle
파일에 지원 라이브러리 종속성을 추가 build.gradle
합니다.
dependencies {
// Match the version of your support library dependency
compile 'com.android.support:recyclerview-v7:25.3.1'
}
공식 사이트 에서 최신 버전의 recyclerview를 찾을 수 있습니다.
기타 관련 주제 :
RecyclerView
구성 요소를 설명하는 다른 주제가 있습니다.
공식 문서
http://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
이전 버전 :
//it requires compileSdkVersion 25
compile 'com.android.support:recyclerview-v7:25.2.0'
compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.android.support:recyclerview-v7:25.0.0'
//it requires compileSdkVersion 24
compile 'com.android.support:recyclerview-v7:24.2.1'
compile 'com.android.support:recyclerview-v7:24.2.0'
compile 'com.android.support:recyclerview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.1.0'
//it requires compileSdkVersion 23
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.3.0'
compile 'com.android.support:recyclerview-v7:23.2.1'
compile 'com.android.support:recyclerview-v7:23.2.0'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.0'
compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.0'
//it requires compileSdkVersion 22
compile 'com.android.support:recyclerview-v7:22.2.1'
compile 'com.android.support:recyclerview-v7:22.2.0'
compile 'com.android.support:recyclerview-v7:22.1.1'
compile 'com.android.support:recyclerview-v7:22.1.0'
compile 'com.android.support:recyclerview-v7:22.0.0'
//it requires compileSdkVersion 21
compile 'com.android.support:recyclerview-v7:21.0.3'
compile 'com.android.support:recyclerview-v7:21.0.2'
compile 'com.android.support:recyclerview-v7:21.0.0'
RecyclerView 추가하기
Remark 섹션에 설명 된대로 종속성을 추가 한 다음 레이아웃에 RecyclerView
를 추가합니다.
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
레이아웃에 RecyclerView
위젯을 추가하면 객체 핸들을 가져 와서 레이아웃 관리자에 연결하고 표시 할 데이터에 대한 어댑터를 첨부합니다.
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// set a layout manager (LinearLayoutManager in this example)
mLayoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
또는 다음 행을 추가하여 xml에서 레이아웃 관리자를 설치하기 만하면됩니다.
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
당신은 내용의 변화 알고 있다면 RecyclerView
의 레이아웃 크기가 변경되지 않습니다 RecyclerView
, 구성 요소의 성능을 개선하기 위해 다음 코드를 사용합니다. RecyclerView의 크기가 고정되어 있으면 RecyclerView 자체가 자식으로 인해 크기가 조정되지 않기 때문에 요청 레이아웃을 전혀 호출하지 않습니다. 단지 변경 자체를 처리합니다. 부모가 무효 인 경우 코디네이터, 레이아웃 또는 기타 사항을 무효화하십시오. ( LayoutManager
와 Adapter
를 설정하기 LayoutManager
메소드를 사용할 수 있습니다).
mRecyclerView.setHasFixedSize(true);
RecyclerView
는 이러한 내장 레이아웃 관리자를 제공합니다. 따라서 RecyclerView
사용하여 목록, 격자 및 엇갈린 격자를 만들 수 있습니다.
- LinearLayoutManager 는 항목을 수직 또는 수평 스크롤 목록에 표시합니다.
- GridLayoutManager 는 모눈에 항목을 표시합니다.
- StaggeredGridLayoutManager 는 엇갈린 격자로 항목을 표시합니다.
항목의 매끄러운 로딩
RecyclerView
의 항목이 네트워크 (일반적으로 이미지)에서 데이터를로드하거나 다른 처리를 수행하는 경우 상당한 시간이 걸릴 수 있으며 화면에는 항목이 있지만 완전히로드되지 않을 수 있습니다. 이를 방지하기 위해 기존 LinearLayoutManager
를 확장하여 화면에 표시되기 전에 여러 항목을 미리로드 할 수 있습니다.
package com.example;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
/**
* A LinearLayoutManager that preloads items off-screen.
* <p>
* Preloading is useful in situations where items might take some time to load
* fully, commonly because they have maps, images or other items that require
* network requests to complete before they can be displayed.
* <p>
* By default, this layout will load a single additional page's worth of items,
* a page being a pixel measure equivalent to the on-screen size of the
* recycler view. This can be altered using the relevant constructor, or
* through the {@link #setPages(int)} method.
*/
public class PreLoadingLinearLayoutManager extends LinearLayoutManager {
private int mPages = 1;
private OrientationHelper mOrientationHelper;
public PreLoadingLinearLayoutManager(final Context context) {
super(context);
}
public PreLoadingLinearLayoutManager(final Context context, final int pages) {
super(context);
this.mPages = pages;
}
public PreLoadingLinearLayoutManager(final Context context, final int orientation, final boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void setOrientation(final int orientation) {
super.setOrientation(orientation);
mOrientationHelper = null;
}
/**
* Set the number of pages of layout that will be preloaded off-screen,
* a page being a pixel measure equivalent to the on-screen size of the
* recycler view.
* @param pages the number of pages; can be {@code 0} to disable preloading
*/
public void setPages(final int pages) {
this.mPages = pages;
}
@Override
protected int getExtraLayoutSpace(final RecyclerView.State state) {
if (mOrientationHelper == null) {
mOrientationHelper = OrientationHelper.createOrientationHelper(this, getOrientation());
}
return mOrientationHelper.getTotalSpace() * mPages;
}
}
끌어서 놓기 및 RecyclerView로 스 와이프
타사 라이브러리를 사용하지 않고도 RecyclerView로 스 와이프 - 투 - 마비 및 드래그 앤 드롭 기능을 구현할 수 있습니다.
RecyclerView 지원 라이브러리에 포함 된 ItemTouchHelper
클래스를 사용하면됩니다.
SimpleCallback
콜백으로 ItemTouchHelper
를 인스턴스화하고 지원하는 기능에 따라 onMove(RecyclerView, ViewHolder, ViewHolder)
및 / 또는 onSwiped(ViewHolder, int)
하고 마지막으로 RecyclerView
연결해야합니다.
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
// remove item from adapter
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
final int fromPos = viewHolder.getAdapterPosition();
final int toPos = target.getAdapterPosition();
// move item in `fromPos` to `toPos` in adapter.
return true;// true if moved, false otherwise
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
SimpleCallback
생성자가 동일한 스 와이프 전략을 RecyclerView
모든 항목에 적용한다는 점을 언급 할 필요가 있습니다. getSwipeDirs(RecyclerView, ViewHolder)
메소드를 오버라이드하여 특정 항목에 대한 기본 스 와이프 방향을 업데이트 할 수 있습니다.
예를 들어 RecyclerView
에 HeaderViewHolder
포함되어 있고 우리가 분명히 스 와이프를 적용하고 싶지 않다고 가정 해 봅시다. 다음과 같이 getSwipeDirs
를 오버라이드하면 충분합니다.
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof HeaderViewHolder) {
// no swipe for header
return 0;
}
// default swipe for all other items
return super.getSwipeDirs(recyclerView, viewHolder);
}
RecyclerView에 머리글 / 바닥 글 추가
이것은 샘플 어댑터 코드입니다.
public class SampleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int FOOTER_VIEW = 1;
// Define a view holder for Footer view
public class FooterViewHolder extends ViewHolder {
public FooterViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Now define the viewholder for Normal list item
public class NormalViewHolder extends ViewHolder {
public NormalViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the normal items
}
});
}
}
// And now in onCreateViewHolder you have to pass the correct view
// while populating the list item.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if (viewType == FOOTER_VIEW) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_footer, parent, false);
FooterViewHolder vh = new FooterViewHolder(v);
return vh;
}
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_normal, parent, false);
NormalViewHolder vh = new NormalViewHolder(v);
return vh;
}
// Now bind the viewholders in onBindViewHolder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
try {
if (holder instanceof NormalViewHolder) {
NormalViewHolder vh = (NormalViewHolder) holder;
vh.bindView(position);
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder vh = (FooterViewHolder) holder;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Now the critical part. You have return the exact item count of your list
// I've only one footer. So I returned data.size() + 1
// If you've multiple headers and footers, you've to return total count
// like, headers.size() + data.size() + footers.size()
@Override
public int getItemCount() {
if (data == null) {
return 0;
}
if (data.size() == 0) {
//Return 1 here to show nothing
return 1;
}
// Add extra view to show the footer view
return data.size() + 1;
}
// Now define getItemViewType of your own.
@Override
public int getItemViewType(int position) {
if (position == data.size()) {
// This is where we'll add footer.
return FOOTER_VIEW;
}
return super.getItemViewType(position);
}
// So you're done with adding a footer and its action on onClick.
// Now set the default ViewHolder for NormalViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
// Define elements of a row here
public ViewHolder(View itemView) {
super(itemView);
// Find view by ID and initialize here
}
public void bindView(int position) {
// bindView() method to implement actions
}
}
}
여기 에 머리말과 꼬리말이있는 RecyclerView
구현에 대한 좋은 정보가 있습니다.
다른 방법 :
위의 대답은 작동하지만 NestedScrollView
를 사용하는 리사이클 러 뷰를 사용하여이 접근법을 사용할 수도 있습니다. 다음 방법을 사용하여 헤더 레이아웃을 추가 할 수 있습니다.
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/drawer_view_header"
android:id="@+id/navigation_header"/>
<android.support.v7.widget.RecyclerView
android:layout_below="@id/navigation_header"
android:id="@+id/followers_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
또는 NestedScrollView
에서 수직 정렬 된 LinearLayout
을 사용할 수도 있습니다.
참고 : 이 기능은 23.2.0 이상의 RecyclerView
에서만 작동합니다.
compile 'com.android.support:recyclerview-v7:23.2.0'
ItemViewType과 함께 여러 개의 ViewHolders 사용
때때로 RecyclerView는 UI에 표시된 목록에 표시 할 여러 유형의보기를 사용해야하며 각보기에는 다른 레이아웃 xml이 필요합니다.
이 문제는 RecyclerView - getItemViewType(int position)
의 특별한 메소드를 사용하여 단일 Adapter에서 다른 ViewHolders를 사용할 수 있습니다.
다음은 두 개의 ViewHolders를 사용하는 예입니다.
리스트 엔트리를 표시하기위한 ViewHolder
여러 헤더보기를 표시하기위한 ViewHolder
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(context).inflate(viewType, parent, false); return ViewHolder.create(itemView, viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final Item model = this.items.get(position); ((ViewHolder) holder).bind(model); } @Override public int getItemViewType(int position) { return inSearchState ? R.layout.item_header : R.layout.item_entry; } abstract class ViewHolder { abstract void bind(Item model); public static ViewHolder create(View v, int viewType) { return viewType == R.layout.item_header ? new HeaderViewHolder(v) :new EntryViewHolder(v); } } static class EntryViewHolder extends ViewHolder { private View v; public EntryViewHolder(View v) { this.v = v; } @Override public void bind(Item model) { // Bind item data to entry view. } } static class HeaderViewHolder extends ViewHolder { private View v; public HeaderViewHolder(View v) { this.v = v; } @Override public void bind(Item model) { // Bind item data to header view. } }
SearchView로 RecyclerView 내부의 항목 필터링
RecyclerView.Adapter
에 filter
메소드 추가 :
public void filter(String text) {
if(text.isEmpty()){
items.clear();
items.addAll(itemsCopy);
} else{
ArrayList<PhoneBookItem> result = new ArrayList<>();
text = text.toLowerCase();
for(PhoneBookItem item: itemsCopy){
//match by name or phone
if(item.name.toLowerCase().contains(text) || item.phone.toLowerCase().contains(text)){
result.add(item);
}
}
items.clear();
items.addAll(result);
}
notifyDataSetChanged();
}
itemsCopy
는 itemsCopy.addAll(items)
과 같은 어댑터의 생성자에서 초기화됩니다.
이 경우 SearchView
OnQueryTextListener
에서 filter
를 호출 OnQueryTextListener
됩니다.
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
adapter.filter(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(newText);
return true;
}
});
recyclerView가있는 팝업 메뉴
이 코드를 ViewHolder에 넣으십시오.
참고 :이 코드에서는 전체 recyclerview
클릭 이벤트에 대해 listener를 itemView 객체로 설정할 수있는 btnExpand
click-event를 사용하고 있습니다.
public class MyViewHolder extends RecyclerView.ViewHolder{
CardView cv;
TextView recordName, visibleFile, date, time;
Button btnIn, btnExpand;
public MyViewHolder(final View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cardview);
recordName = (TextView)itemView.findViewById(R.id.tv_record);
visibleFile = (TextView)itemView.findViewById(R.id.visible_file);
date = (TextView)itemView.findViewById(R.id.date);
time = (TextView)itemView.findViewById(R.id.time);
btnIn = (Button)itemView.findViewById(R.id.btn_in_out);
btnExpand = (Button) itemView.findViewById(R.id.btn_expand);
btnExpand.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(btnExpand.getContext(), itemView);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete:
moveFile(recordName.getText().toString(), getAdapterPosition());
return true;
case R.id.action_play:
String valueOfPath = recordName.getText().toString();
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
File file = new File(valueOfPath);
intent.setDataAndType(Uri.fromFile(file), "audio/*");
context.startActivity(intent);
return true;
case R.id.action_share:
String valueOfPath = recordName.getText().toString();
File filee = new File(valueOfPath);
try {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("audio/*");
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(filee));
context.startActivity(sendIntent);
} catch (NoSuchMethodError | IllegalArgumentException | NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return true;
default:
return false;
}
}
});
// here you can inflate your menu
popup.inflate(R.menu.my_menu_item);
popup.setGravity(Gravity.RIGHT);
// if you want icon with menu items then write this try-catch block.
try {
Field mFieldPopup=popup.getClass().getDeclaredField("mPopup");
mFieldPopup.setAccessible(true);
MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popup);
mPopup.setForceShowIcon(true);
} catch (Exception e) {
}
popup.show();
}
});
}
}
메뉴에 아이콘을 표시하는 다른 방법
try {
Field[] fields = popup.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(popup);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Exception e) {
}
출력은 다음과 같습니다.
애니메이션 데이터 변경
RecyclerView
는 notifyDataSetChanged
제외하고 "notify"메소드가 사용 된 경우 관련 애니메이션을 수행합니다. 여기에는 notifyItemChanged
, notifyItemInserted
, notifyItemMoved
, notifyItemRemoved
등이 포함됩니다.
어댑터는 RecyclerView.Adapter
대신이 클래스를 확장해야합니다.
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import java.util.List;
public abstract class AnimatedRecyclerAdapter<T, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
protected List<T> models;
protected AnimatedRecyclerAdapter(@NonNull List<T> models) {
this.models = models;
}
//Set new models.
public void setModels(@NonNull final List<T> models) {
applyAndAnimateRemovals(models);
applyAndAnimateAdditions(models);
applyAndAnimateMovedItems(models);
}
//Remove an item at position and notify changes.
private T removeItem(int position) {
final T model = models.remove(position);
notifyItemRemoved(position);
return model;
}
//Add an item at position and notify changes.
private void addItem(int position, T model) {
models.add(position, model);
notifyItemInserted(position);
}
//Move an item at fromPosition to toPosition and notify changes.
private void moveItem(int fromPosition, int toPosition) {
final T model = models.remove(fromPosition);
models.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
//Remove items that no longer exist in the new models.
private void applyAndAnimateRemovals(@NonNull final List<T> newTs) {
for (int i = models.size() - 1; i >= 0; i--) {
final T model = models.get(i);
if (!newTs.contains(model)) {
removeItem(i);
}
}
}
//Add items that do not exist in the old models.
private void applyAndAnimateAdditions(@NonNull final List<T> newTs) {
for (int i = 0, count = newTs.size(); i < count; i++) {
final T model = newTs.get(i);
if (!models.contains(model)) {
addItem(i, model);
}
}
}
//Move items that have changed their position.
private void applyAndAnimateMovedItems(@NonNull final List<T> newTs) {
for (int toPosition = newTs.size() - 1; toPosition >= 0; toPosition--) {
final T model = newTs.get(toPosition);
final int fromPosition = models.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
}
setModels
와List
에 대해서는List
를 사용 하지 말아야 합니다.
models
을 전역 변수로 선언합니다. DataModel
은 더미 클래스입니다.
private List<DataModel> models;
private YourAdapter adapter;
models
을 어댑터에 전달하기 전에 초기화하십시오. YourAdapter
는 AnimatedRecyclerAdapter
의 구현입니다.
models = new ArrayList<>();
//Add models
models.add(new DataModel());
//Do NOT pass the models directly. Otherwise, when you modify global models,
//you will also modify models in adapter.
//adapter = new YourAdapter(models); <- This is wrong.
adapter = new YourAdapter(new ArrayList(models));
글로벌 models
을 업데이트 한 후에 이것을 호출하십시오.
adapter.setModels(new ArrayList(models));
equals
재정의하지 않으면 모든 비교가 참조로 비교됩니다.
SortedList를 사용하는 예제
Android는 RecyclerView
가 도입 된 직후에 SortedList
클래스를 도입했습니다. 이 클래스는 RecyclerView.Adapter
에 대한 모든 '통지'메소드 호출을 처리하여 적절한 애니메이션을 보장하고 여러 변경 사항을 일괄 처리 할 수 있으므로 애니메이션이 지터를 일으키지 않습니다.
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.util.SortedListAdapterCallback;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private SortedList<DataModel> mSortedList;
class ViewHolder extends RecyclerView.ViewHolder {
TextView text;
CheckBox checkBox;
ViewHolder(View itemView){
super(itemView);
//Initiate your code here...
}
void setDataModel(DataModel model) {
//Update your UI with the data model passed here...
text.setText(modle.getText());
checkBox.setChecked(model.isChecked());
}
}
public MyAdapter() {
mSortedList = new SortedList<>(DataModel.class, new SortedListAdapterCallback<DataModel>(this) {
@Override
public int compare(DataModel o1, DataModel o2) {
//This gets called to find the ordering between objects in the array.
if (o1.someValue() < o2.someValue()) {
return -1;
} else if (o1.someValue() > o2.someValue()) {
return 1;
} else {
return 0;
}
}
@Override
public boolean areContentsTheSame(DataModel oldItem, DataModel newItem) {
//This is to see of the content of this object has changed. These items are only considered equal if areItemsTheSame() returned true.
//If this returns false, onBindViewHolder() is called with the holder containing the item, and the item's position.
return oldItem.getText().equals(newItem.getText()) && oldItem.isChecked() == newItem.isChecked();
}
@Override
public boolean areItemsTheSame(DataModel item1, DataModel item2) {
//Checks to see if these two items are the same. If not, it is added to the list, otherwise, check if content has changed.
return item1.equals(item2);
}
});
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = //Initiate your item view here.
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Just update the holder with the object in the sorted list from the given position
DataModel model = mSortedList.get(position);
if (model != null) {
holder.setDataModel(model);
}
}
@Override
public int getItemCount() {
return mSortedList.size();
}
public void resetList(List<DataModel> models) {
//If you are performing multiple changes, use the batching methods to ensure proper animation.
mSortedList.beginBatchedUpdates();
mSortedList.clear();
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
//The following methods each modify the data set and automatically handles calling the appropriate 'notify' method on the adapter.
public void addModel(DataModel model) {
mSortedList.add(model);
}
public void addModels(List<DataModel> models) {
mSortedList.addAll(models);
}
public void clear() {
mSortedList.clear();
}
public void removeModel(DataModel model) {
mSortedList.remove(model);
}
public void removeModelAt(int i) {
mSortedList.removeItemAt(i);
}
}
데이터 바인딩이있는 RecyclerView
다음은 모든 DataBinding 레이아웃에서 사용할 수있는 일반적인 ViewHolder 클래스입니다. 여기서 특정 ViewDataBinding
클래스의 인스턴스는 확장 된 View
객체 및 DataBindingUtil
유틸리티 클래스를 사용하여 생성됩니다.
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class BindingViewHolder<T> extends RecyclerView.ViewHolder{
private final T binding;
public BindingViewHolder(View itemView) {
super(itemView);
binding = (T)DataBindingUtil.bind(itemView);
}
public T getBinding() {
return binding;
}
}
이 클래스를 생성 한 후 레이아웃 파일에서 <layout>
을 사용하여 다음과 같이 해당 레이아웃에 대한 데이터 바인딩을 활성화 할 수 있습니다.
file name: my_item.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="item"
type="ItemModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@{item.itemLabel}" />
</LinearLayout>
</layout>
여기에 샘플 dataModel이 있습니다.
public class ItemModel {
public String itemLabel;
}
기본적으로 Android Data Binding 라이브러리는 레이아웃 파일 이름을 기반으로 ViewDataBinding
클래스를 생성하고 파스칼 케이스로 변환하고 "Binding"접미사로 변환합니다. 이 예를 들어이 될 것이다 MyItemBinding
레이아웃 파일에 대한 my_item.xml
. 이 Binding 클래스에는 레이아웃 파일 (이 예제의 경우 ItemModel
에서 데이터로 정의 된 객체를 설정하는 setter 메서드도 있습니다.
이제 우리는 모든 조각을 가지고 다음과 같이 어댑터를 구현할 수 있습니다.
class MyAdapter extends RecyclerView.Adapter<BindingViewHolder<MyItemBinding>>{
ArrayList<ItemModel> items = new ArrayList<>();
public MyAdapter(ArrayList<ItemModel> items) {
this.items = items;
}
@Override public BindingViewHolder<MyItemBinding> onCreateViewHolder(ViewGroup parent, int viewType) {
return new BindingViewHolder<>(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_item, parent, false));
}
@Override public void onBindViewHolder(BindingViewHolder<ItemModel> holder, int position) {
holder.getBinding().setItemModel(items.get(position));
holder.getBinding().executePendingBindings();
}
@Override public int getItemCount() {
return items.size();
}
}
Recycleview에서 끝없는 스크롤.
여기에서는 재활용보기에서 끝없는 스크롤을 구현하기위한 코드 스 니펫을 공유했습니다.
1 단계 : 먼저 아래와 같이 Recycleview 어댑터에서 하나의 추상 메소드를 만듭니다.
public abstract class ViewAllCategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public abstract void load();
}
2 단계 : 이제 ViewAllCategoryAdapter 클래스의 onBindViewHolder 및 getItemCount()
메서드를 재정의하고 아래의 Load()
메서드를 호출합니다.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if ((position >= getItemCount() - 1)) {
load();
}
}
@Override
public int getItemCount() {
return YOURLIST.size();
}
3 단계 : 이제 모든 백엔드 로직이 완성되었습니다 . 이제이 로직을 실행할 시간입니다. 어댑터의 오브젝트를 작성하는로드 메소드를 간단하게 대체 할 수 있습니다.이 메소드는 사용자가 리스팅의 끝에 도달하는 동안 자동으로 호출됩니다.
adapter = new ViewAllCategoryAdapter(CONTEXT, YOURLIST) {
@Override
public void load() {
/* do your stuff here */
/* This method is automatically call while user reach at end of your list. */
}
};
recycleCategory.setAdapter(adapter);
이제 load()
메소드는 사용자가리스트의 끝에서 스크롤하는 동안 자동으로 호출한다.
최고의 행운
항목이로드되거나 데이터를 사용할 수 없을 때까지 기본보기 표시
어댑터 클래스
private class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final int EMPTY_VIEW = 77777;
List<CustomData> datalist = new ArrayList<>();
MyAdapter() {
super();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == EMPTY_VIEW) {
return new EmptyView(layoutInflater.inflate(R.layout.nothing_yet, parent, false));
} else {
return new ItemView(layoutInflater.inflate(R.layout.my_item, parent, false));
}
}
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == EMPTY_VIEW) {
EmptyView emptyView = (EmptyView) holder;
emptyView.primaryText.setText("No data yet");
emptyView.secondaryText.setText("You're doing good !");
emptyView.primaryText.setCompoundDrawablesWithIntrinsicBounds(null, new IconicsDrawable(getActivity()).icon(FontAwesome.Icon.faw_ticket).sizeDp(48).color(Color.DKGRAY), null, null);
} else {
ItemView itemView = (ItemView) holder;
// Bind data to itemView
}
}
@Override
public int getItemCount() {
return datalist.size() > 0 ? datalist.size() : 1;
}
@Override
public int getItemViewType(int position) {
if datalist.size() == 0) {
return EMPTY_VIEW;
}
return super.getItemViewType(position);
}
}
nothing_yet.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingBottom="100dp"
android:paddingTop="100dp">
<TextView
android:id="@+id/nothingPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableTint="@android:color/secondary_text_light"
android:drawableTop="@drawable/ic_folder_open_black_24dp"
android:enabled="false"
android:fontFamily="sans-serif-light"
android:text="No Item's Yet"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/secondary_text_light"
android:textSize="40sp"
tools:targetApi="m" />
<TextView
android:id="@+id/nothingSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:enabled="false"
android:fontFamily="sans-serif-condensed"
android:text="You're doing good !"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_light" />
</LinearLayout>
이미지 용 아이콘 라이브러리가있는 FontAwesome을 사용하고 있습니다. 앱 수준 build.gradle 파일에 추가합니다.
compile 'com.mikepenz:fontawesome-typeface:4.6.0.3@aar'
compile 'com.mikepenz:iconics-core:2.8.1@aar'
RecyclerView 항목에 구분선 추가
이 줄을 초기화에 추가하기 만하면됩니다.
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
adapter
추가하고 .notifyDataSetChanged();
호출 .notifyDataSetChanged();
평소처럼!
이것은 Recyclerview의 내장 된 기능이 아니지만 지원 라이브러리에 추가되었습니다. 따라서 이것을 앱 수준 build.gradle 파일에 포함하는 것을 잊지 마십시오.
compile "com.android.support:appcompat-v7:25.3.1"
compile "com.android.support:recyclerview-v7:25.3.1"
하나의 RecyclerView에 여러 ItemDecorations를 추가 할 수 있습니다.
구분선 색상 변경 :
itemDecoration의 색상을 설정하는 것은 매우 쉽습니다.
- 단계는
drawable
폴더에있는divider.xml
파일을 만드는 것입니다.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<size
android:width="1px"
android:height="1px"/>
<solid android:color="@color/divider_color"/>
</shape>
- 단계는 드로어 블 설정입니다.
// Get drawable object
Drawable mDivider = ContextCompat.getDrawable(m_jContext, R.drawable.divider);
// Create a DividerItemDecoration whose orientation is Horizontal
DividerItemDecoration hItemDecoration = new DividerItemDecoration(m_jContext,
DividerItemDecoration.HORIZONTAL);
// Set the drawable on it
hItemDecoration.setDrawable(mDivider);
// Create a DividerItemDecoration whose orientation is vertical
DividerItemDecoration vItemDecoration = new DividerItemDecoration(m_jContext,
DividerItemDecoration.VERTICAL);
// Set the drawable on it
vItemDecoration.setDrawable(mDivider);