Представление Recyclerview не работает с setNestedScrollingEnabled, и оно никогда не перерабатывает никакие представления.

Я сталкиваюсь с двумя проблемами:

  1. Слушатель прокрутки не будет работать
  2. RecyclerView никогда не перерабатывает представления, когда он присоединен к NestedScrollView. Он действует как линейный макет внутри ScrollView. Он использует много памяти и создает лаги.

Я прикрепляю фрагмент проигрывателя YouTube поверх представления ресайклера, так как я не могу поместить фрагмент в представление ресайклера. В моем коде вы можете видеть, что есть макет кадра.

Мой макет выглядит так:

    <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nestedScroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <FrameLayout               
                android:layout_width="match_parent"
                android:layout_height="240dp"
                android:layout_alignParentTop="true"/>





        </LinearLayout>


        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/youtube_layout"
            android:visibility="visible"/>




    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

Я хочу использовать прослушиватель прокрутки для загрузки большего количества элементов, поэтому я пробовал следующее:

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    Log.i(TAG, "onScrolled: ");
    // bail out if scrolling upward or already loading data
    if (dy < 0 || dataLoading.isDataLoading()) return;

    final int visibleItemCount = recyclerView.getChildCount();
    final int totalItemCount = layoutManager.getItemCount();
    final int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();

    if ((totalItemCount - visibleItemCount) <= (firstVisibleItem )) {
        onLoadMore();
    }


}

Но layoutManager.findFirstVisibleItemPosition()==0 так что это не работает, и более того onScrolled never called twice так как я установил recyclerview.setNestedScrollingEnabled(false)

поэтому я пробовал в onBindView вот так

   public void onBindViewHolder(RecyclerView.ViewHolder customViewHolder, int i) {
    Log.w("d","inside bind view");

    if(i>=getItemCount()-1  &&   !datamanager.isDataLoading()){
        datamanager.loadmoreData();
    }

но recylerview связывает все представления одновременно, прежде чем я даже начну прокручивать, поэтому этот метод также не работает.


person Asthme    schedule 03.08.2017    source источник


Ответы (3)


Представление recycler никогда не перерабатывает какие-либо представления, когда оно прикреплено к вложенному представлению прокрутки, оно действует как набор в линейном макете внутри представления прокрутки. Оно создает огромную память и отстает от экрана.

В яблочко. Вы не можете поместить RecyclerView в другое представление с прокруткой.

Это не сработает, потому что обертывающему представлению необходимо знать общую высоту RecyclerView, а RecyclerView может узнать свою общую высоту только путем измерения и компоновки всех своих элементов.

Как это исправить?

Не размещайте RecyclerView внутри другого представления с прокруткой.

Если вам нужен верхний или нижний колонтитул, вам придется добавить его в RecyclerView и позволить RecyclerView позаботиться о его отображении. Избавьтесь от ScrollView и переместите заголовок внутрь RecyclerView.

Технически можно также загружать фрагменты внутри RecyclerView, но я должен признать, что заставить это работать должным образом немного сложно.

Существует также множество библиотек, облегчающих этот процесс, моя любимая — Epoxy от AirBnb, но есть также Groupie и многие другие.

person David Medenjak    schedule 05.08.2017
comment
я загрузил фрагменты, но просмотр переработчика не позволяет состояние фрагмента. Случайно вылетает. - person Asthme; 06.08.2017

Я справился с такой ситуацией. Есть recyclerview. Представление Recycler имеет viewpager. Viewpager имеет фрагменты, а затем внутри фрагмента есть recyclerview.

Вам нужно взломать касания, чтобы он отлично прокручивался.

private boolean interceptTouch = true;
    private static final int MIN_DISTANCE = 200;
    private float downX = 0, downY = 0, moveX = 0, moveY = 0, upX = 0, upY;

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

    public TouchInterceptRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (getRvTop() == 0) {
            onTouchEvent(ev);
        }
        return interceptTouch;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                moveX = event.getX();
                moveY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                upX = event.getX();
                upY = event.getY();
                break;
        }
        float deltaX = upX - downX;

        if (getViewTop() == 0 && moveY > downY && Math.abs(moveY - downY) > MIN_DISTANCE) {  // moving down
            interceptTouch = true;
        }else if (Math.abs(deltaX) > MIN_DISTANCE) {
            if (upX > downX) {    // Left to Right swipe action
                interceptTouch = false;
            }else {    // Right to left swipe action
                interceptTouch = false;
            }
        } else {  // screen tap
            interceptTouch = false;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    public void onScrolled(int dx, int dy) {
        if (getViewTop() <= 0) {
            interceptTouch = false;            // dispatch the touch to child when reached top
        } else {
            interceptTouch = true;           // do not dispatch the touch event
        }
        super.onScrolled(dx, dy);
    }

    public int getViewTop() {
        int top = 0;
        View v = this.getChildAt(1);
        if (v == null) {
            v = this.getChildAt(0);
        }
        if (v != null && v instanceof LinearLayout) {
            top = v.getTop();
        }
        return top;
    }

    public int getRvTop() {
        int top = -1;
        View v = this.getChildAt(1);
        if (v == null) {
            v = this.getChildAt(0);
        }
        if (v != null && v instanceof LinearLayout) {

            ViewPager vp = (ViewPager) v.findViewById(R.id.single_tribe_pager);
            if (vp != null) {
                int currentPos = vp.getCurrentItem();
                RecyclerView rv = (RecyclerView) vp.findViewWithTag("recyclerview" + currentPos);
                if (rv != null) {
                    View v1 = rv.getChildAt(0);
                    if (v1 != null && v1 instanceof CardView) {
                        top = v1.getTop() - ResourceUtils.getDimensionPixelOffset(R.dimen.padding_20);   // deducting 20 as we have give top margin as 20 to the top layout
                    }
                }
            }
        }
        return top;
    }
person Harsh    schedule 12.08.2017

Вот как я этого добился, я пытался сократить код до минимума

public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int VIEW_TYPE_LOADING = 0;
    private static final int VIEW_TYPE_ITEM = 1;

    public boolean isLoading;
    private int visibleThreshold = 5;
    private int lastVisibleItem, totalItemCount;

    public ArrayList<Data> datas;

    private OnLoadMoreListener mOnLoadMoreListener;

    public DataAdapter(RecyclerView mRecyclerView, ArrayList<Data> datas) {
        this.datas = datas;

        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();

                if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    if (mOnLoadMoreListener != null) {
                        DataAdapter.this.datas.remove(null);
                        mOnLoadMoreListener.onLoadMore();
                    }
                }
            }
        });
    }
    public static class DataObjectHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        //your views

        public DataObjectHolder(View itemView) {
            super(itemView);
            //initialize your views
        }

        @Override
        public void onClick(View v) {
            if (onItemClickListener != null) onItemClickListener.onItemClick(getAdapterPosition(), v);
        }
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    @Override
    public int getItemViewType(int position) {
        return datas.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_ITEM) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_data, parent, false);
            DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
            return dataObjectHolder;
        } else if (viewType == VIEW_TYPE_LOADING) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_loading_item, parent, false);
            return new LoadingViewHolder(view);
        }
        return null;
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder hldr, final int position) {
        if (hldr instanceof DataObjectHolder) {
            final Data data = datas.get(position);
            final DataObjectHolder holder = (DataObjectHolder) hldr;

            //bind your views


        } else if (hldr instanceof LoadingViewHolder) {
            LoadingViewHolder loadingViewHolder = (LoadingViewHolder) hldr;

            if (isLoading) {
                loadingViewHolder.progressBar.setVisibility(View.VISIBLE);
                loadingViewHolder.progressBar.setIndeterminate(true);

                loadingViewHolder.tv_load_more.setVisibility(View.GONE);
                loadingViewHolder.tv_load_more.setOnClickListener(null);
            } else {
                loadingViewHolder.progressBar.setVisibility(View.GONE);

                loadingViewHolder.tv_load_more.setVisibility(View.VISIBLE);
                loadingViewHolder.tv_load_more.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if (mOnLoadMoreListener != null) {
                            datas.remove(null);
                            mOnLoadMoreListener.onLoadMore();
                        }
                    }
                });
            }
        }
    }

    @Override
    public int getItemCount() {
        return datas.size();
    }

    public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
        this.mOnLoadMoreListener = mOnLoadMoreListener;
    }

}

XML для loadingViewHolder показан ниже, вы просто надуваете, чтобы получить держатель

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="60dp">

    <ProgressBar
        android:id="@+id/progressBar1"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_centerInParent="true"
        android:layout_gravity="center"
        android:indeterminate="true"/>

    <TextView
        android:id="@+id/tv_load_more"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="Tap to load more"
        android:textSize="14sp"/>

</RelativeLayout>

Надеюсь, вы найдете это полезным

person Odufuwa Segun    schedule 05.08.2017
comment
я использую фрагмент в верхней части recyclerview. я не могу так писать - person Asthme; 05.08.2017
comment
Ой, извините, я отвечал на другой вопрос - person Odufuwa Segun; 05.08.2017
comment
Не стесняйтесь удалить свой ответ, если вы определили, что разместили его по ошибке. - person Cody Gray; 05.08.2017
comment
Вы знаете, что, я не отправил ответ на неправильный вопрос. Я решил часть загрузки большего количества элементов в представление ресайклера при прокрутке вниз. Как указывали другие, вы не можете использовать фрагмент внутри представления переработчика. Всегда есть лучший способ добиться того, что вы пытаетесь сделать. - person Odufuwa Segun; 06.08.2017