Selection

RecyclerView를 구현하고 다중 선택 기능을 추가 하기 위해서는 Selection 라이브러리를 사용할 수 있습니다. 안드로이드 내의 사진들을 Grid형식으로 구성하고 Selection으로 다중 선택하는 예제를 만들어 보도록 하겠습니다

Selection 구현하기

의존성 추가하기

//androidx 를 쓰지 않는다면
implementation "com.android.support:recyclerview-selection:28.0.0"

or

//androidx를 쓴다면
androidx.recyclerview:recyclerview-selection:1.0.0

Key타입 결정하기

Selection라이브러리는 3가지 타입의 Key타입을 지원합니다.

  • Parcelable
  • String
  • Long

하나의 Item을 식별하기 위한 고유값(ID)으로 설정하면됩니다.

Key타입을 결정하였다면, Adapter에게 Id를 이용해 Item을 식별하겠다는 설정을 하도록합니다.

public class PhotoAdapter {
    protected PhotoAdapter(Context context) {
        ...
        setHasStableIds(true);
        ...
    }
}

그런 다음 아이템 ID를 지정하도록 합니다.

public class PhotoAdapter extends RecyclerView.Adapter<LookUpViewHolder> {
    ...
    @Override
    public long getItemId(int position) {
        return position;
    }
    ...
}

KeyProvider 구현하기

Key 타입을 선택으므로, 해당 Key 타입에 맞추어 KeyProvider를 구현할 시간입니다. Selection 라이브러리는 StableIdKeyProvider를 제공하므로 이를 이용하면 됩니다. SelectionTracker를 만들때 보도록 하겠습니다.

ItemDetailsLookUp 구현하기

ItemDetailsLookup<T> 클래스는 사용자의 선택과 관련된 항목에 대한 정보를 제공합니다. MotionEvent를 기반하여 선택된 내용을 ViewHolder에 매핑합니다.

public class PhotoDetailsLookUp extends ItemDetailsLookup<Long> {

    private RecyclerView recyclerView;
    public PhotoDetailsLookUp(RecyclerView recyclerView){
        this.recyclerView = recyclerView;
    }
    @Nullable
    @Override
    public ItemDetails<Long> getItemDetails(@NonNull MotionEvent motionEvent) {
        View view = recyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY());
        if (view != null) {
            LookUpViewHolder viewHolder = (LookUpViewHolder) recyclerView.getChildViewHolder(view);
            return viewHolder.getItemDetails();
        }
        return null;
    }
}

ViewHolder로 돌아가서 getItemDetails()메소드를 살펴보도록 합시다.

public class LookUpViewHolder extends RecyclerView.ViewHolder {

    ImageView image;
    ImageView checkBox;

    public LookUpViewHolder(View itemView) {
        super(itemView);
        image = itemView.findViewById(R.id.image);
        checkBox = itemView.findViewById(R.id.checkbox);
    }

    public ItemDetailsLookup.ItemDetails<Long> getItemDetails(){
        return new ItemDetailsLookup.ItemDetails<Long>() {
            @Override
            public int getPosition() {
                return getAdapterPosition();
            }

            @Nullable
            @Override
            public Long getSelectionKey() {
                return getItemId();
            }
        };
    }

getItemDetails라는 메소드를 통해 ItemDetails를 리턴하고 있습니다. 추상클래스인 ItemDetails에는 getPosition과 getSelectionKey라는 메소드를 구현하게끔 되어있는데, 위와 같이 adapter의 position과 item id를 리턴시켜줍니다.

SelectionTracker 만들기

다음과 같이 빌더를 통해 SelectionTracker를 만듭니다. 

private void setupSelectionTracker(){
    selectionTracker = new SelectionTracker.Builder<>(
            "selection_id",
            recyclerView,
            new StableIdKeyProvider(recyclerView),
            new PhotoDetailsLookUp(recyclerView),
            StorageStrategy.createLongStorage())
            .withSelectionPredicate(SelectionPredicates.<Long>createSelectAnything())
            .build();
}

Warning : SelectionTracker는 반드시 RecyclerView에 Adapter가 참조된 이후에 만들어야 합니다. 그렇지 않으면 IllegalArgumentException이 발생됩니다.

Builder를 만드는데 필요한 파라미터 내용입니다.

  • selectionId : 선택내용 대한 Id를 지정합니다.
  • recyclerView : 선택내용을 추적할 RecyclerView를 지정합니다.
  • keyProvider : 캐시를 위한 선택되는 아이템의 Key제공자
  • itemDetailsLookup : RecyclerView 아이템의 대한 정보
  • storage : saved state에서 키를 저장하기 위한 전략

withSelectionPredicate는 어떠한 선택을 할지 결정할 수 있게 합니다. Selection라이브러리에서 제공하는 SelectionPredicates.createSelectionAnything()을 쓸 수도 있고, 자신만의 SelectionPredicate를 만들 수도 있습니다.

SelectionTracker를 만들었다면, Adapter에 setter를 만들어SelectionTracker를 넘겨줍니다.

public void setSelectionTracker(SelectionTracker<Long> selectionTracker) {
    this.selectionTracker = selectionTracker;
}

Adapter에서 이제 selectionTracker를 참조할 수 있게 되었습니다.

@Override
public void onBindViewHolder(@NonNull LookUpViewHolder lookUpViewHolder, int position) {
    Photo photo = photoList.get(position);
    lookUpViewHolder.setPhoto(photo);
    lookUpViewHolder.setSelectionTracker(selectionTracker);
}

뷰홀더가 바인딩 되는 시점에 selectionTracker의 정보를 읽어 선택내용에 대한 UI를 결정할 수 있습니다.

예제 프로젝트는 github에서 확인하실 수 있습니다.

카테고리: Java

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.