수색…


소개

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 자체가 자식으로 인해 크기가 조정되지 않기 때문에 요청 레이아웃을 전혀 호출하지 않습니다. 단지 변경 자체를 처리합니다. 부모가 무효 인 경우 코디네이터, 레이아웃 또는 기타 사항을 무효화하십시오. ( LayoutManagerAdapter 를 설정하기 LayoutManager 메소드를 사용할 수 있습니다).

mRecyclerView.setHasFixedSize(true);

RecyclerView 는 이러한 내장 레이아웃 관리자를 제공합니다. 따라서 RecyclerView 사용하여 목록, 격자 및 엇갈린 격자를 만들 수 있습니다.

  1. LinearLayoutManager 는 항목을 수직 또는 수평 스크롤 목록에 표시합니다.
  2. GridLayoutManager 는 모눈에 항목을 표시합니다.
  3. 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) 메소드를 오버라이드하여 특정 항목에 대한 기본 스 와이프 방향을 업데이트 할 수 있습니다.

예를 들어 RecyclerViewHeaderViewHolder 포함되어 있고 우리가 분명히 스 와이프를 적용하고 싶지 않다고 가정 해 봅시다. 다음과 같이 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를 사용하는 예입니다.

  1. 리스트 엔트리를 표시하기위한 ViewHolder

  2. 여러 헤더보기를 표시하기위한 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.Adapterfilter 메소드 추가 :

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

itemsCopyitemsCopy.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) {

}

출력은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오.

애니메이션 데이터 변경

RecyclerViewnotifyDataSetChanged 제외하고 "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);
            }
        }
    }
}

setModelsList 에 대해서는 List 를 사용 하지 말아야 합니다.

models 을 전역 변수로 선언합니다. DataModel 은 더미 클래스입니다.

private List<DataModel> models;
private YourAdapter adapter;

models 을 어댑터에 전달하기 전에 초기화하십시오. YourAdapterAnimatedRecyclerAdapter 의 구현입니다.

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 클래스의 onBindViewHoldergetItemCount() 메서드를 재정의하고 아래의 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의 색상을 설정하는 것은 매우 쉽습니다.

  1. 단계는 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>
  1. 단계는 드로어 블 설정입니다.
    // 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);

horizontal_divider

    // Create a DividerItemDecoration whose orientation is vertical
    DividerItemDecoration vItemDecoration = new DividerItemDecoration(m_jContext,
            DividerItemDecoration.VERTICAL);
    // Set the drawable on it
    vItemDecoration.setDrawable(mDivider);

여기에 이미지 설명을 입력하십시오.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow