NestedScrollView 내부에 RecyclerView를 추가하면 이상한 스크롤 동작이 나타납니다.
스크롤보기에 화면에 표시 할 수있는 것보다 많은 행이있을 때마다 활동이 시작 되 자마자 NestedScrollView가 맨 위에서 오프셋 (이미지 1)으로 시작됩니다. 스크롤보기에 한 번에 모든 항목을 표시 할 수있는 항목이 거의없는 경우에는 발생하지 않습니다 (그림 2).
지원 라이브러리 버전 23.2.0을 사용하고 있습니다.
이미지 1 : 잘못된-상단에서 오프셋으로 시작
이미지 2 : 수정-재활용 기보기의 일부 항목
내 레이아웃 코드 아래에 붙여 넣습니다.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
style="@style/TextAppearance.AppCompat.Body1"
android:text="Neque porro quisquam est qui dolorem ipsum"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle:"
style="@style/TextAppearance.AppCompat.Caption"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Body1"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:focusable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
뭔가 빠졌습니까? 누구 든지이 문제를 해결하는 방법을 알고 있습니까?
업데이트 1
활동을 초기화 할 때 다음 코드를 배치하면 올바르게 작동합니다.
sv.post(new Runnable() {
@Override
public void run() {
sv.scrollTo(0,0);
}
});
sv는 NestedScrollView에 대한 참조이지만 꽤 해킹처럼 보입니다.
업데이트 2
요청에 따라 다음은 내 어댑터 코드입니다.
public abstract class ArrayAdapter<T, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
private List<T> mObjects;
public ArrayAdapter(final List<T> objects) {
mObjects = objects;
}
/**
* Adds the specified object at the end of the array.
*
* @param object The object to add at the end of the array.
*/
public void add(final T object) {
mObjects.add(object);
notifyItemInserted(getItemCount() - 1);
}
/**
* Remove all elements from the list.
*/
public void clear() {
final int size = getItemCount();
mObjects.clear();
notifyItemRangeRemoved(0, size);
}
@Override
public int getItemCount() {
return mObjects.size();
}
public T getItem(final int position) {
return mObjects.get(position);
}
public long getItemId(final int position) {
return position;
}
/**
* Returns the position of the specified item in the array.
*
* @param item The item to retrieve the position of.
* @return The position of the specified item.
*/
public int getPosition(final T item) {
return mObjects.indexOf(item);
}
/**
* Inserts the specified object at the specified index in the array.
*
* @param object The object to insert into the array.
* @param index The index at which the object must be inserted.
*/
public void insert(final T object, int index) {
mObjects.add(index, object);
notifyItemInserted(index);
}
/**
* Removes the specified object from the array.
*
* @param object The object to remove.
*/
public void remove(T object) {
final int position = getPosition(object);
mObjects.remove(object);
notifyItemRemoved(position);
}
/**
* Sorts the content of this adapter using the specified comparator.
*
* @param comparator The comparator used to sort the objects contained in this adapter.
*/
public void sort(Comparator<? super T> comparator) {
Collections.sort(mObjects, comparator);
notifyItemRangeChanged(0, getItemCount());
}
}
그리고 여기 내 ViewHolder가 있습니다.
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView txt;
public ViewHolder(View itemView) {
super(itemView);
txt = (TextView) itemView;
}
public void render(String text) {
txt.setText(text);
}
}
그리고 여기 RecyclerView의 각 항목의 레이아웃 android.R.layout.simple_spinner_item
이 있습니다 ( 단지 -이 화면은이 버그의 예를 보여주기위한 것입니다).
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAlignment="inherit"/>
답변
설정을 통해 이러한 문제를 해결했습니다.
<ImageView ...
android:focusableInTouchMode="true"/>
RecyclerView 위의 내보기 (원치 않는 스크롤 후에 숨겨져 있음). 이 속성을 RecyclerView 위의 LinearLayout 또는 RecyclerView의 컨테이너 인 LinearLayout으로 설정하십시오 (다른 경우에 도움이 됨).
NestedScrollView 소스에서 알 수 있듯이 onRequestFocusInDescendants에서 가능한 첫 번째 자식에 초점을 맞추려고 시도하고 RecyclerView 만 초점을 맞출 수 있으면 승리합니다.
편집 (Waran 덕분에) : 부드러운 스크롤을 위해 설정하는 것을 잊지 마십시오 yourRecyclerView.setNestedScrollingEnabled(false);
답변
당신에 LinearLayout
즉시 후 NestedScrollView
사용 android:descendantFocusability
다음과 같은 방법으로
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
android:descendantFocusability="blocksDescendants">
편집하다
많은 사람들 이이 답변을 유용하게 사용하므로 설명도 제공합니다.
의 사용은 descendantFocusability
주어진 여기 . 그리고 현재의 focusableInTouchMode
이상 여기 . 따라서 blocksDescendants
in을 사용 descendantFocusability
하면 아이가 만지는 동안 초점을 맞출 수 없으므로 계획되지 않은 행동을 멈출 수 있습니다.
에 관해서는 focusInTouchMode
, 모두 AbsListView
와 RecyclerView
메소드 호출 setFocusableInTouchMode(true);
이 당신의 XML 레이아웃에서 그 속성을 사용하지 않아도되도록 기본적으로 자신의 생성자를.
그리고 NestedScrollView
다음과 같은 방법이 사용됩니다.
private void initScrollView() {
mScroller = ScrollerCompat.create(getContext(), null);
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
}
여기서는 setFocusable()
대신 method가 사용됩니다 setFocusableInTouchMode()
. 하지만이에 따라 포스트 , focusableInTouchMode
안드로이드 정상적인 동작과 일관성을 나누기로 특정 조건을 제외하고 피해야한다. 게임은 터치 모드 속성에서 포커스를 잘 활용할 수있는 응용 프로그램의 좋은 예입니다. Google지도 에서처럼 전체 화면으로 사용되는 MapView는 터치 모드에서 초점을 맞출 수있는 또 다른 좋은 예입니다.
답변
android:descendantFocusability="blocksDescendants"
내부 LinearLayout 나를 위해 일했습니다.
답변
나는 같은 문제가 있었고 NestedScrollView를 확장하고 집중적 인 자식을 비활성화하여 슬퍼했습니다. 어떤 이유로 든 RecyclerView는 서랍을 열고 닫았을 때도 항상 포커스를 요청했습니다.
public class DummyNestedScrollView extends NestedScrollView {
public DummyNestedScrollView(Context context) {
super(context);
}
public DummyNestedScrollView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public DummyNestedScrollView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Fixind problem with recyclerView in nested scrollview requesting focus
* http://stackoverflow.com/questions/36314836/recycler-view-inside-nestedscrollview-causes-scroll-to-start-in-the-middle
* @param child
* @param focused
*/
@Override
public void requestChildFocus(View child, View focused) {
Log.d(getClass().getSimpleName(), "Request focus");
//super.requestChildFocus(child, focused);
}
/**
* http://stackoverflow.com/questions/36314836/recycler-view-inside-nestedscrollview-causes-scroll-to-start-in-the-middle
* @param direction
* @param previouslyFocusedRect
* @return
*/
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
Log.d(getClass().getSimpleName(), "Request focus descendants");
//return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
return false;
}
}
답변
필자의 경우이 코드는 내 문제를 해결합니다.
RecyclerView recyclerView = findViewById(R.id.recyclerView);
NestedScrollView nestedScrollView= findViewById(R.id.nestedScrollView);
recyclerView.setFocusable(false);
nestedScrollView.requestFocus();
//populate recyclerview here
내 레이아웃에는 자식 LinearLayout이있는 NestedScrollView와 같은 부모 레이아웃이 있습니다. LinearLayout은 “수직”방향과 자식 RecyclerView 및 EditText를 갖습니다. 참고
답변
두 가지 추측이 있습니다.
먼저 :이 줄을 NestedScrollView에 넣으십시오.
app:layout_behavior="@string/appbar_scrolling_view_behavior"
둘째 : 사용
<android.support.design.widget.CoordinatorLayout
부모님의 의견으로
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"/>
<TextView
style="@style/TextAppearance.AppCompat.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum"/>
<TextView
style="@style/TextAppearance.AppCompat.Caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Subtitle:"/>
<TextView
style="@style/TextAppearance.AppCompat.Body1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/bodyPadding"
android:text="Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
가능한 마지막 해결책. 맹세합니다 🙂
답변
이 문제는 재활용보기 포커스로 인해 발생합니다.
크기가 화면 크기를 확장하면 자동으로 모든 초점이 재생보기로 이동했습니다.
추가 android:focusableInTouchMode="true"
와 같은 최초의 ChildView에 TextView
, Button
등등 (하지에 ViewGroup
같은 Linear
, Relative
등) 메이크업 감각이 문제지만 API 레벨 25를 해결하고 위의 해결책은 작동하지 않습니다.
그냥 같이 당신의 ChildView에서이 두 줄을 추가 TextView
, Button
등등 (하지에 ViewGroup
같은 Linear
, Relative
등등)
android:focusableInTouchMode="true"
android:focusable="true"
API 레벨 25에서이 문제에 직면했습니다. 다른 사람들이 이것에 시간을 낭비하지 않기를 바랍니다.
RecycleView의 부드러운 스크롤을 위해이 줄을 추가하십시오.
android:nestedScrollingEnabled="false"
그러나이 복장을 추가하면 API 레벨 21 이상에서만 작동합니다. API 레벨 25 이하에서 스무딩 스크롤링 작업을하려면 클래스에이 줄을 추가하십시오
mList = findViewById(R.id.recycle_list);
ViewCompat.setNestedScrollingEnabled(mList, false);