【问题标题】:Nested Vertical RecycleView of fixed height (Scroll issue)固定高度的嵌套垂直RecycleView(滚动问题)
【发布时间】:2020-04-09 18:52:13
【问题描述】:

我设计了这个布局布局,其中我有一个 NestdScrollView,其中包含 3 个 RecycleViews。在每个RecycleView 项目上单击会出现另一个NestedRecycleView 出现在高度200dpScrollView 内。 NestedRecycleView 滚动不起作用。在图像中有超过 4 个“列表项”,但只显示了 4 个,它不可滚动。当我滚动父 NestdScrollView 滚动时。

如果有人有想法,有人评论说这是糟糕的设计 如何处理这个问题也请分享您的想法。

RecycleView 适配器

  public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {

        private List<String> mData;
        private LayoutInflater mInflater;
        private ItemClickListener mClickListener;
        private Context context;

        // data is passed into the constructor
        MyRecyclerViewAdapter(Context context, List<String> data) {
            this.mInflater = LayoutInflater.from(context);
            this.mData = data;
            this.context=context;
        }

        // inflates the row layout from xml when needed
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = mInflater.inflate(R.layout.list_item_text, parent, false);
            return new ViewHolder(view);
        }

        // binds the data to the TextView in each row
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            String animal = mData.get(position);
            holder.myTextView.setText(animal);
        }

        // total number of rows
        @Override
        public int getItemCount() {
            return mData.size();
        }


        // stores and recycles views as they are scrolled off screen
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            TextView myTextView;
            RecyclerView recyclerViewNested;
            ScrollView nestedScrollViewRecycleView;

            ViewHolder(View itemView) {
                super(itemView);
                myTextView = itemView.findViewById(R.id.text_view);
                recyclerViewNested = itemView.findViewById(R.id.recycle_view_nested);
                nestedScrollViewRecycleView= itemView.findViewById(R.id.nested_scrollview_in_recycleview);
                myTextView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        ArrayList<String> list12 = new ArrayList<String>(
                                Arrays.asList("list item", "list item", "list item","list item","list item", "list item", "list item","list item","list item", "list item", "list item","list item","list item", "list item", "list item","list item","list item", "list item", "list item","list item"));
                        nestedScrollViewRecycleView.setVisibility(View.VISIBLE);

                        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(context, list12);
                        LinearLayoutManager layoutManager = new LinearLayoutManager(context, recyclerViewNested.VERTICAL, false);
                        recyclerViewNested.setLayoutManager(layoutManager);
                        recyclerViewNested.setAdapter(adapter);


                    }
                });
                //itemView.setOnClickListener(this);
            }

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

        // convenience method for getting data at click position
        String getItem(int id) {
            return mData.get(id);
        }

        // allows clicks events to be caught
        void setClickListener(ItemClickListener itemClickListener) {
            this.mClickListener = itemClickListener;
        }

        // parent activity will implement this method to respond to click events
        public interface ItemClickListener {
            void onItemClick(View view, int position);
        }
    }

MainActivity

public class MainActivity extends AppCompatActivity {

    public static final int SWIPE_THRESHOLD = 100;
    public static final int SWIPE_VELOCITY_THRESHOLD = 100;
    private static final String TAG = "MainActivity";

    ArrayList<String> list2;
    NestedScrollView NestedScroll1;
    ConstraintLayout constraintLayout;
    RecyclerView recyclerView1;
    //vars

 private boolean mSwiping = false;
    private float mDownX = 0;
    private float xCoOrdinate;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView1 = findViewById(R.id.firstColumn);
        RecyclerView recyclerView2 = findViewById(R.id.secondColumn);
        RecyclerView recyclerView3 = findViewById(R.id.thirdColumn);
        NestedScroll1 = findViewById(R.id.scrollview_nested);

        ArrayList<String> list12 = new ArrayList<String>(
                Arrays.asList("A", "column1", "test1", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3"));
        list2 = new ArrayList<String>(
                Arrays.asList("B", "column3", "test3", "111", "211", "311", "111", "211", "311", "111", "211", "311", "111", "211", "311", "111", "211", "311", "311", "111", "211", "311", "111", "211", "311", "111", "211", "311"));


        // set up the RecyclerView
        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(this, list12);

        configRecyclerView(recyclerView1, adapter);
        configRecyclerView(recyclerView2, adapter);
        configRecyclerView(recyclerView3, adapter);


    recyclerView2.addOnItemTouchListener(getOnItemTouchListener());
    recyclerView3.addOnItemTouchListener(getOnItemTouchListener());

    }

    private void configRecyclerView(RecyclerView recyclerView, MyRecyclerViewAdapter adapter) {
        LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext(), recyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);
    }



private RecyclerView.OnItemTouchListener getOnItemTouchListener() {
        return new RecyclerView.OnItemTouchListener() {
            @SuppressLint("LongLogTag")
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
                Log.d("TableView OnswipeTouchListener: ", " recycleViewOdds item onInterceptTouchEvent");

                switch (ev.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mDownX = ev.getX();
                        mSwiping = false;

                        //coordinate for moving
                        xCoOrdinate = constraintLayout.getX() - ev.getRawX();

                        break;
                    case MotionEvent.ACTION_CANCEL:
                        //return true;
                    case MotionEvent.ACTION_UP:
                        if (mSwiping) {

                            /// this return true block touch event
                            Log.d("TableView OnswipeTouchListener:", "Recycle view odds OnItemTouchListener: you swiped!");
                            return true;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float xMove = ev.getX();
                        float xDelta = Math.abs(xMove - mDownX);

                        if (xDelta > 5) {
                            mSwiping = true;
                            // this one also
                            return true;
                        }
                        break;
                }

                return false;
            }

            private Rect rect;

            @SuppressLint("LongLogTag")
            @Override
            public void onTouchEvent(RecyclerView rv, MotionEvent event) {

                int limitLeft = constraintLayout.getLeft();
                int limitRight = constraintLayout.getRight();


                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        break;
                    case MotionEvent.ACTION_MOVE:
                        //   Log.d("OnSwipeTouchListener Class", "recycleViewOdds action move");

                        //Restrict move to constraintLayout width
                        // Log.d("Recycleview TouchListener windowwidth: ", limitLeft + ", " + limitRight);

                        float range = event.getRawX() + xCoOrdinate;

                        if (Math.abs(range) > limitLeft - 350 && Math.abs(range) < limitRight - 250) {
                            //constraintLayout.scrollTo((int) (event.getRawX() + xCoOrdinate),0);
                            constraintLayout.animate().x(event.getRawX() + xCoOrdinate).setDuration(0).start();
                            constraintLayout.setAlpha(0.7f);
                        }

                        break;
                    case MotionEvent.ACTION_UP:
                        Log.d("TableView OnswipeTouchListener:", "recycleViewOdds action up");
                        constraintLayout.animate().alpha(1).translationX(0).translationY(0);

                        break;

                    case MotionEvent.ACTION_CANCEL:
                        constraintLayout.animate().alpha(1).translationX(0).translationY(0);

                        Log.d("TableView OnswipeTouchListener:", "recycleViewOdds action cancel");
                        break;
                }
            }


            @SuppressLint("LongLogTag")
            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
                Log.e("TableView OnswipeTouchListener:", "recycleViewOdds item touch intercept disallow request");

            }
        };
    }

}

activity_main.xml

<androidx.core.widget.NestedScrollView
    android:id="@+id/scrollview_nested"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:text="Hello World!"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/firstColumn"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:nestedScrollingEnabled="false"
            app:layout_constraintEnd_toStartOf="@id/secondColumn"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/secondColumn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            app:layout_constraintEnd_toStartOf="@id/thirdColumn"
            app:layout_constraintLeft_toRightOf="@id/firstColumn"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/thirdColumn"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="16dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintLeft_toRightOf="@id/secondColumn"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

list_item_text.xml

  <?xml version="1.0" encoding="utf-8"?>
<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="10dp">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:layout_marginBottom="8dp"/>
    <ScrollView
        android:id="@+id/nested_scrollview_in_recycleview"
        android:layout_width="match_parent"
        android:visibility="gone"
        android:background="@color/colorAccent"
        android:layout_height="200dp">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle_view_nested"
            android:layout_width="match_parent"
            android:nestedScrollingEnabled="false"
            android:layout_height="wrap_content"/>

    </ScrollView>

</LinearLayout>

【问题讨论】:

  • 首先,为什么recycler 视图放置在嵌套滚动视图中?
  • 您可以考虑使用可扩展的回收器视图来获得嵌套列表效果。
  • 我在 nestedScrollview 中放置了 3 个主要的 recycleView,以便它们一起滚动。然后对于 NestedRecycleView,我把它放在滚动视图中,给它 200dp 的固定高度。 @afairplayer
  • 感谢您的建议,但我没有使用可扩展回收视图的原因是我希望我的嵌套回收视图有一定的高度,我不希望它在扩展时占据太多屏幕,因为它是巨大的清单。因此我把它放在滚动视图中,这样我可以给它一个固定的高度。 @afairplayer
  • 退后一步,看看你想要完成什么,也许你会想出一个更好更有机的方法来实现它。你正在做的这件事是糟糕的设计。

标签: java android android-recyclerview android-nestedscrollview


【解决方案1】:

我的建议是在“list_item_text”中,在这里,你有一个封装的滚动视图和回收器视图,我假设这些项目的数量在 5-10 左右会非常少,并且大部分会在屏幕上可见,所以不会有任何性能问题如果我们通过迭代循环直接在父布局中动态添加LinearLayout,这种方法的唯一缺点是屏幕外的视图将被加载到内存中(不在recycler view),但是考虑到您的项目数量,这是可以接受的,您的大部分项目都将在屏幕上可见,显然这将节省 Recyclerview 人口、渲染和所有方面的额外开销。希望它能解决您的触摸问题。

【讨论】:

  • 感谢您的建议,但这种方法如何解决滚动问题,因为我的布局高度是 200dp,我想用户仍然需要滚动列表才能查看所有项目。 scrollView 中大约有 100 个项目要显示。
  • 好的,我觉得,在滚动视图或回收器视图中覆盖 onIterceptTouchEvent() 可能会对您有所帮助,请查看以下链接以获取实现neevek.net/posts/2013/10/13/…
  • 感谢@akashzincle 我使用了onIterceptTouchEvent() 并设置了getparent().disallowTouchIntercept(true) 以禁止父级获取触摸监听器,但是父级还需要处理触摸监听器,就像父级recycleview 被刷卡时一样左右,它在用户触摸时动画。所以当nestedRecycleview 抓取触摸动画时对父级不起作用
  • 所以@akashzincle 我终于能够找出问题所在,您重写 onIterceptTouchEvent() 的想法有助于实现结果,我重写了我想要拦截触摸事件的那些回收视图的 onIterceptTouchEvent()。所以我接受你的回答,我在你的回答中添加了一个示例代码,它可能会帮助其他用户。
  • 太棒了!很高兴知道你破解了这个 :) 感谢您添加代码,会检查它
【解决方案2】:

recyclerView.setNestedScrollingEnabled(false); 添加到所有 RecyclerViews 并检查是否可以解决滚动问题。

【讨论】:

  • 感谢@新浪。我也尝试将 setNestedScrollingEnabled(false) 添加到嵌套的回收视图中,但仍然没有滚动。我想这与android上的触摸监听器有关,据我了解,两个recycleview ontouch监听器之间存在冲突。
  • @Amir 我会检查更多。
  • 你可以尝试将 recyclerView 的 layout_height 设置为 wrap_content 让它和它的孩子一样高,并且不需要滚动。
【解决方案3】:

activity_main.xml
请在所有 RecyclerView 标签中添加android:nestedScrollingEnabled="true"...


list_item_text.xml
请在 ScrollView 标签中添加android:fillViewport="true"
然后在 RecyclerView 标签中将android:layout_height="wrap_content" 更改为android:layout_height="0dp"...

【讨论】:

    猜你喜欢
    • 2017-01-16
    • 2023-04-11
    • 1970-01-01
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多