[android] ItemTouchHelper.SimpleCallback을 사용하여 RecyclerView의 위치에 대해 스 와이프를 비활성화합니다.

recyclerview 22.2.0 및 도우미 클래스 ItemTouchHelper.SimpleCallback을 사용 하여 내 목록에 대해 스 와이프 하여 닫기 옵션을 활성화 합니다. 그러나 헤더 유형이 있으므로 어댑터의 첫 번째 위치에 대해 스 와이프 동작을 비활성화해야합니다. 으로 RecyclerView.Adapter이 없는 의 IsEnabled () 메소드를 나는 방법을 통해 뷰의 상호 작용을하지 않도록 노력 의 IsEnabled ()isFocusable () ViewHolder 생성 자체, 그러나 성공이 없었다. SimpleCallback의 메서드 getSwipeThreshold () 에서 0f ot 1f 와 같이 스 와이프 임계 값을 전체 값으로 조정하려고 했지만 성공하지 못했습니다.

당신이 나를 도울 수 있도록 내 코드의 일부.

내 활동 :

@Override
protected void onCreate(Bundle bundle) {
    //... initialization
    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
            if (viewHolder instanceof CartAdapter.MyViewHolder) return 1f;
            return super.getSwipeThreshold(viewHolder);
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {

        }
    };

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);
}

그리고 두 가지 보기 유형 이있는 공통 어댑터가 있습니다. 스 와이프를 비활성화하려는 ViewHolder 에서 다음을 수행 했습니다.

public static class MyViewHolder extends RecyclerView.ViewHolder {
    public ViewGroup mContainer;

    public MyViewHolder(View v) {
        super(v);
        v.setFocusable(false);
        v.setEnabled(false);
        mContainer = (ViewGroup) v.findViewById(R.id.container);
    }
}



답변

비트를 연주 후, 나는 그 관리 SimpleCallback이 방법이라고이 getSwipeDirs을 () . 스 와이프 할 수 없는 위치에 대한 특정 ViewHolder가 있으므로 스 와이프 를 방지하기 위해 instanceof 를 사용할 수 있습니다 . 그렇지 않은 경우 어댑터의 ViewHolder 위치를 사용하여이 제어를 수행 할 수 있습니다.

자바

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if (viewHolder instanceof CartAdapter.MyViewHolder) return 0;
    return super.getSwipeDirs(recyclerView, viewHolder);
}

Kotlin

override fun getSwipeDirs (recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
    if (viewHolder is CartAdapter.MyViewHolder) return 0
    return super.getSwipeDirs(recyclerView, viewHolder)
}


답변

누군가 ItemTouchHelper.Callback을 사용하는 경우 . 그런 다음 getMovementFlags (..) 함수 에서 관련 플래그를 제거 할 수 있습니다 .

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(dragFlags, swipeFlags);
}

여기에서 dragFlagsswipeFlags 대신 0을 전달하여 해당 기능을 비활성화 할 수 있습니다.

ItemTouchHelper.START 는 왼쪽에서 오른쪽 로케일 (LTR 애플리케이션 지원)의 경우 왼쪽에서 오른쪽으로 스 와이프하지만 오른쪽에서 왼쪽 로케일 (RTL 애플리케이션 지원)에서는 반대 방향으로 스 와이프하는 것을 의미합니다.
ItemTouchHelper.END 는의 반대 방향으로 스 와이프하는 것을 의미 START합니다.

따라서 요구 사항에 따라 플래그를 제거 할 수 있습니다.


답변

다음은 스 와이프되는 항목의 위치에만 의존하는 간단한 방법입니다.

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    int dragFlags = 0; // whatever your dragFlags need to be
    int swipeFlags = createSwipeFlags(position)

    return makeMovementFlags(dragFlags, swipeFlags);
}

private int createSwipeFlags(int position) {
  return position == 0 ? 0 : ItemTouchHelper.START | ItemTouchHelper.END;
}

다음을 사용하는 경우에도 작동합니다 SimpleCallback.

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
    int position = holder.getAdapterPosition();
    return createSwipeFlags(position);
}

private int createSwipeFlags(int position) {
  return position == 0 ? 0 : super.getSwipeDirs(recyclerView, viewHolder);
}

항목의 데이터에 대한 조건부 스 와이프를 비활성화하려면 position값을 사용하여 스 와이프되는 항목에 대한 어댑터에서 데이터를 가져오고 그에 따라 비활성화합니다.

스 와이프 할 필요가없는 특정 홀더 유형이 이미있는 경우 수락 된 답변이 작동합니다. 그러나 위치에 대한 프록시로 홀더 유형을 생성하는 것은 번거롭기 때문에 피해야합니다.


답변

이에 대해 몇 가지 방법이 있지만 ViewHolder가 하나만 있고 레이아웃이 둘 이상인 경우이 방법을 사용할 수 있습니다.

getItemViewType을 재정의하고 객체의 위치 또는 데이터 유형에 따라 뷰 유형을 결정하는 로직을 제공합니다 (객체에 getType 함수가 있습니다).

@Override
public int getItemViewType(int position) {
    return data.get(position).getType;
}

ViewType을 기반으로 onCreateView에서 적절한 레이아웃을 반환합니다 (ViewHolder 클래스에 뷰 유형을 전달해야합니다.

@Override
public AppListItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    mContext = parent.getContext();

    if (viewType == 0){
        return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.layout, parent, false), viewType);
    else
        return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.header, parent, false), viewType);
    }
}

보기 유형에 따라 다양한 레이아웃의 콘텐츠보기를 가져옵니다. public static class AppListItemHolder extends RecyclerView.ViewHolder {

    public AppListItemHolder (View v, int viewType) {
        super(v);

        if (viewType == 0)
            ... get your views contents
        else
            ... get other views contents
        }
    }
}

그런 다음 ItemTouchHelper에서 ViewType에 따라 작업을 변경합니다. 나를 위해 이것은 RecyclerView 섹션 헤더의 스 와이프를 비활성화합니다.

@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if (viewHolder.getItemViewType() == 1) return 0;
        return super.getSwipeDirs(recyclerView, viewHolder);
    }
}


답변

먼저 onCreateViewHolder 메서드의 recyclerView에서 아래 코드와 같이 각 viewHolder 유형에 대한 태그를 설정합니다.

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    if(ITEM_TYPE_NORMAL == viewType) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.deposite_card_view, viewGroup, false);
        ItemViewHolder holder = new ItemViewHolder(context, v);
        holder.itemView.setTag("normal");
        return holder;
    } else {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_header, viewGroup, false);
        HeaderViewHolder holder = new HeaderViewHolder(context, v);
        holder.itemView.setTag("header");
        return holder;
    }
}

그런 다음 ItemTouchHelper.Callback 구현에서 아래와 같이 getMovementFlags 메서드를 업데이트합니다.

public class SwipeController extends ItemTouchHelper.Callback {

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    if("normal".equalsIgnoreCase((String) viewHolder.itemView.getTag())) {
        return makeMovementFlags(0, LEFT | RIGHT);
    } else {
        return 0;
    }
}

끝에서 recyclerView에 연결 :

final SwipeController swipeController = new SwipeController();

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
    itemTouchHelper.attachToRecyclerView(recyclerView);


답변

@Rafael Toledo 답변 외에도 Adapter에서 개체의 위치 또는 데이터 유형에 따라 LEFT 스 와이프 또는 RIGHT 스 와이프와 같은 특정 스 와이프 제스처를 제거하려면 다음과 같이 할 수 있습니다.

@Override
  public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
       {
          int position = viewHolder.getAdapterPosition();
          ConversationDataModel conversationModel = null;
          conversationModel = mHomeAdapter.getItems().get(position);
          boolean activeChat = true;
          if(conversationModel!=null && !conversationModel.isActive())
           {
             activeChat = false;
           }
  return activeChat ? super.getSwipeDirs(recyclerView, viewHolder): ItemTouchHelper.RIGHT;
        }

여기 내 경우 Recyclerview에서 채팅 대화를로드하고 있으며 각 항목에 대해 RIGHT (아카이브) 및 LEFT (EXIT) 스 와이프 제스처가 있습니다. 그러나 대화가 활성화되지 않은 경우 Recycler보기에서 특정 항목에 대해 오른쪽 스 와이프를 비활성화해야합니다.

그래서 나는 확인 activeChat하고 그에 따라 오른쪽 스 와이프를 비활성화했습니다.


답변

다음을 사용하여 비활성화 할 수 있습니다. ItemTouchHelper.ACTION_STATE_IDLE

ItemTouchHelper.SimpleCallback(
    ItemTouchHelper.UP or ItemTouchHelper.DOWN, //drag directions
    ItemTouchHelper.ACTION_STATE_IDLE //swipe directions
)
val touchHelperCallback = object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.ACTION_STATE_IDLE) {
    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        (recyclerView.adapter as MyAdapter).onItemMove(viewHolder.adapterPosition, target.adapterPosition)
        return true
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        return
    }

}
val touchHelper = ItemTouchHelper(touchHelperCallback)
touchHelper.attachToRecyclerView(recyclerViewX)