1

Instagram의 필터 레이아웃이 작동하는 것과 비슷한 레이아웃을 만들려고합니다. 기본적으로 필터를 선택하면 선택한 항목으로 스크롤되어 더 많은 필터가 있음을 보여줍니다.LinearLayoutManager 부드러운 스크롤이 잘못된 위치로 점프합니다.

나는 현재 여기 내 수평 RecyclerView에 대한 사용자 지정 LinearLayoutManager 구축을 위해 노력하고 있어요 : 스크롤 의도대로 작품을 왼쪽하지만 난 잘 스크롤있을 때 그냥 목록의 끝으로 이동 보인다

public class LinearLayoutSnapManager extends LinearLayoutManager { 
    private int mCurrentPos = 0; 

    public LinearLayoutSnapManager(Context context) { 
     super(context); 
    } 

    public LinearLayoutSnapManager(Context context, int orientation, boolean reverseLayout) { 
     super(context, orientation, reverseLayout); 
    } 

    public LinearLayoutSnapManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 

    } 


    public void snap(RecyclerView rv, int position) { 
     if (mCurrentPos == position) { 
      // No move 
      return; 
     } 

     boolean goingRight = true; 
     if (position < mCurrentPos) { 
      goingRight = false; 
     } 
     mCurrentPos = position; 
     smoothScrollToPosition(rv, new RecyclerView.State(), goingRight ? getScrollRightPos(): getScrollLeftPos()); 
    } 

    private int getScrollLeftPos() { 
     int newPos = mCurrentPos - 1; 
     return (newPos > 0) ? newPos : 0; 
    } 

    private int getScrollRightPos() { 
     return mCurrentPos + 1; 
    } 
} 

newItem + 1과 비교할 때 왜 그런 일이 발생하는지 알 수 없습니다.

enter image description here

+0

더 많은 코드를 게시 할 수 있습니까? 그 방법을 사용하는 방법은 무엇입니까? 당신의 논리는 괜찮은 것 같지만 잘못된 순간에 위치를 전달할 수도 있습니다. 즉, – FabioR

+0

getScrollRightPos가 호출 될 때 오래된 (업데이트되지 않은) 위치가 mCurrentPos로 전달되어서 OLD 위치 + 1 (리사이클 러뷰의 끝 부분에있을 수도 있습니다.) 또한, 현재 항목에 인접하지 않은 항목을 클릭하면 스크롤이 문제가되는 것입니까? – FabioR

+0

누가'snap()'을 호출하나요? 'int position'이 어디서 오는가? – g4s8

답변

1

snap 인터페이스 호출에서 내 수평 목록에 onclicklistener에서 전화를 걸었습니다. 인터페이스가 호출되기 전에 선택한 항목을 설정하고보기를 통보하여 현재 상태를 업데이트하도록 변경했습니다. 이로 인해 layoutmanager가 잘못된 인덱스를 반환하는 모든 문제가 발생했습니다.

빈 프로젝트를 만들고 내 논리를 테스트 한 후에이를 발견했습니다. 놀랍게도 실제 문제를 추적 할 수있게 도와주었습니다.

일단 모든 내보기 로직이 게시 된 코드를 변경하지 않고 의도 한대로 작동하기 전에 스냅 프리딕을 옮겼습니다.

앞으로 도움이 될 수 있기를 바랍니다.

0

당신이 마지막으로 선택한 필터가 두 번째로 표시합니다 (하나 개의 필터 전에, 몇 가지 필터 후)이, 당신이 바로 그 방법이 없습니다.

이 경우 오른쪽 또는 왼쪽 방향과 관계없이 프로세스가 동일합니다. RecyclerView의 위치는 첫 번째 요소를 제외하고 항상 선택된 필터의 위치보다 1 작습니다.

public class LinearLayoutSnapManager extends LinearLayoutManager { 
    private int mCurrentSelectedPos = 0; 

    public LinearLayoutSnapManager(Context context) { 
     super(context); 
    } 

    public LinearLayoutSnapManager(Context context, int orientation, boolean reverseLayout) { 
     super(context, orientation, reverseLayout); 
    } 

    public LinearLayoutSnapManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 

    } 


    public void snap(RecyclerView rv, int selectedPosition) { 
     if (mCurrentSelectedPos == selectedPosition) { 
      // No move 
      return; 
     } 

     mCurrentSelectedPos = selectedPosition; 

     int newDisplayPos; 
     if (mCurrentSelectedPos > 0) { 
      newDisplayPos = mCurrentSelectedPos - 1; 
     } else { 
      newDisplayPos = 0; 
     } 

     smoothScrollToPosition(rv, new RecyclerView.State(), newDisplayPos); 
    } 

} 
+0

이 코드는 아무 것도 스크롤하지 않을 때 점프하는 대신 위와 동일한 문제가 있습니다. 오른쪽으로 스크롤 할 때 왼쪽으로 스크롤 할 때의 동작을 수행해야합니다. – Nick

1

내가 다른 솔루션을 제안합니다 (이 예는 최신 위치에 최적화되지 않음). LinearLayoutManager는 편리한 기능을 함께 제공 :

int findFirstCompletelyVisibleItemPosition()

는 최초의 완전 보이는 뷰의 어댑터 위치를 돌려줍니다.


int findLastCompletelyVisibleItemPosition()

은 지난 완벽하게 보이는 뷰의 어댑터 위치를 돌려줍니다.

int findFirstVisibleItemPosition()

첫 번째 눈에 보이는 뷰의 어댑터 위치를 돌려줍니다.

int findFirstVisibleItemPosition()

는 마지막으로 볼 수있는 뷰의 어댑터 위치를 돌려줍니다.

첫 번째 두 함수는 완전히 보이는보기의 위치를 ​​반환하지만 마지막 두 개는 부분적으로 보이는보기를 반환합니다. 선택은 당신이 달성하고자하는 행동에 달려 있습니다.

을 사용하여 기능 getScrollLeftPosgetScrollRightPos은 다음과 같은 모양입니다 :

private int getScrollLeftPos() { 
    int newPos = findFirstCompletelyVisibleItemPosition() - 1; 
    return (newPos > 0) ? newPos : 0; 
} 

private int getScrollRightPos() { 
    return findLastCompletelyVisibleItemPosition()+ 1; 
} 

그리고 메소드를 호출하지 않습니다

smoothScrollToPosition(rv, new RecyclerView.State(), goingRight ? getScrollRightPos(): getScrollLeftPos()); 

LayoutManager에서. 당신이 RecyclerView의 소스 코드에 보면

rv.smoothScrollToPosition(newPosition); 

것은 당신이 이러한 구현을 찾을 수 있습니다 : 당신이 RecyclerView에 대한 참조가있는 경우, 호출 당신이로

public void smoothScrollToPosition(int position) { 
    if (mLayoutFrozen) { 
     return; 
    } 
    if (mLayout == null) { 
     Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " + 
       "Call setLayoutManager with a non-null argument."); 
     return; 
    } 
    mLayout.smoothScrollToPosition(this, mState, position); 
} 

이 기본적으로 동일하지만, 수 해당 RecyclerView.State과 함께 LayoutManager의 기능이 호출됨을 알고 있어야합니다. 그것은 단지와 일치합니다

+1

그래서 문제의 핵심은'findLastVisibleItemPosition()'이 옳지 않은 것 같아요. 목록에서 두 번째 항목을 클릭하면 0을 반환합니다. 'findLastCompletelyVisibleItemPosition()'과 동일합니다. 'Getchildcount()'는 리사이클 러 뷰에 첨부 된 4 개의 뷰가있을 때 1입니다. – Nick