【问题标题】:RecyclerVIew auto scroll to display all the elements as in News Feed etc.,RecyclerVIew 自动滚动显示所有元素,如 News Feed 等,
【发布时间】:2016-03-03 13:48:08
【问题描述】:

如何平滑地自动滚动RecyclerView,以便用户可以看到 RecyclerView 的所有元素并从头开始再次滚动 - 就像在新闻提要等中一样。

我知道smoothScrollToPosition()scrollToPosition(),但它们最终会滚动到最后一个元素的速度过快。

我希望 RecyclerView 具有动画效果并缓慢移动。

【问题讨论】:

标签: android scroll android-recyclerview


【解决方案1】:

只是为了稍微改进一下答案,它是自动无限滚动,动画流畅。

final int speedScroll = 1200;
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
    int count = 0;
    boolean flag = true;
    @Override
    public void run() {
        if(count < adapter.getItemCount()){
            if(count==adapter.getItemCount()-1){
                flag = false;
            }else if(count == 0){
                flag = true;
            }
            if(flag) count++;
            else count--;

            recyclerView.smoothScrollToPosition(count);
            handler.postDelayed(this,speedScroll);
        }
    }
};

handler.postDelayed(runnable,speedScroll);

这正是您的答案,但如果您链接到更流畅的动画,请使用 LayoutManager

recyclerView.setLayoutManager(new CustomLinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));

控制你的动画改变 MILLISECONDS_PER_INCH 值。

public class CustomLinearLayoutManager extends LinearLayoutManager {
    public CustomLinearLayoutManager(Context context) {
        super(context);
    }

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

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

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        final LinearSmoothScroller linearSmoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    private static final float MILLISECONDS_PER_INCH = 200f;

                    @Override
                    public PointF computeScrollVectorForPosition(int targetPosition) {
                        return CustomLinearLayoutManager.this
                                .computeScrollVectorForPosition(targetPosition);
                    }

                    @Override
                    protected float calculateSpeedPerPixel
                            (DisplayMetrics displayMetrics) {
                        return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
                    }
                };
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }
}

【讨论】:

  • 当我手动滚动时。自动滚动不会从该项目继续。
  • 完美运行,但滑块时间太慢,增加到 3000 毫秒是完美的。
  • 在我的模拟器中运行,似乎 CPU 几乎无法工作。我想知道电池消耗会不会太高。
  • OutOfMemoryError 发生。
  • @AbhilashMaurya 没有发现任何内存问题。
【解决方案2】:

我认为这是最好的解决方案。

    final int speedScroll = 150;
    final Handler handler = new Handler();
    final Runnable runnable = new Runnable() {
        int count = 0;
        @Override
        public void run() {
            if(count < list.size()){
                recyclerView.scrollToPosition(count++);
                handler.postDelayed(this,speedScroll);
            }


        }
    };

    handler.postDelayed(runnable,speedScroll);

【讨论】:

  • 如何获取卡片显示的位置,并从中递增而不是重新开始
  • 这个滚动不流畅。以及如何一次又一次地开始,直到活动开始?
  • @AliAhmed 是的,最好使用 LayoutManager 进行滚动而不是 Recyclerview 本身
【解决方案3】:

这是Auto Scroll RecyclerView及其100%工作的最佳方式:

  RecyclerView recyclerView = findViewById(R.id.rv_id);

  final int time = 4000; // it's the delay time for sliding between items in recyclerview

    final Adapter adapter = new Adapter(dataItems);
    recyclerView.setAdapter(adapter);

    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(rootView.getContext(), LinearLayoutManager.HORIZONTAL, false);
    recyclerView.setLayoutManager(linearLayoutManager);

    //The LinearSnapHelper will snap the center of the target child view to the center of the attached RecyclerView , it's optional if you want , you can use it
    final LinearSnapHelper linearSnapHelper = new LinearSnapHelper();
    linearSnapHelper.attachToRecyclerView(recyclerView); 

    final Timer timer = new Timer();
    timer.schedule(new TimerTask() {

        @Override
        public void run() {

            if (linearLayoutManager.findLastCompletelyVisibleItemPosition() < (adapter.getItemCount() - 1)) {

                linearLayoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), linearLayoutManager.findLastCompletelyVisibleItemPosition() + 1);
            }

            else if (linearLayoutManager.findLastCompletelyVisibleItemPosition() == (adapter.getItemCount() - 1)) {

                linearLayoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), 0);
            }
        }
    }, 0, time);

【讨论】:

  • 真正完美的答案。谢谢。
【解决方案4】:

经过反复试验,这对我来说是完美的

    final RecyclerView mRecyclerViewr;
    final ArrayList<String> stringArrayData = new ArrayList<String>
    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, false);
    mRecyclerViewr.setLayoutManager(linearLayoutManager);
    CustomAdapter customAdapter = new CustomAdapter(getApplicationContext(), topPriceBarList);
    mRecyclerViewr.setAdapter(customAdapter);

        // Auto Scroll Left To Right
        final int scrollSpeed = 100;   // Scroll Speed in Milliseconds
        final Handler handler = new Handler();
        final Runnable runnable = new Runnable() {
            int x = 15;        // Pixels To Move/Scroll
            boolean flag = true;
            // Find Scroll Position By Accessing RecyclerView's LinearLayout's Visible Item Position
            int scrollPosition = linearLayoutManager.findLastCompletelyVisibleItemPosition();  
            int arraySize = stringArrayData.size();  // Gets RecyclerView's Adapter's Array Size

            @Override
            public void run() {
                if (scrollPosition < arraySize) {
                    if (scrollPosition == arraySize - 1) {
                        flag = false;
                    } else if (scrollPosition <= 1) {
                        flag = true;
                    }
                    if (!flag) {
                        try {
                            // Delay in Seconds So User Can Completely Read Till Last String
                            TimeUnit.SECONDS.sleep(1); 
                            mRecyclerViewr.scrollToPosition(0);  // Jumps Back Scroll To Start Point
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // Know The Last Visible Item
                    scrollPosition = linearLayoutManager.findLastCompletelyVisibleItemPosition();

                    mRecyclerViewr.smoothScrollBy(x, 0);
                    handler.postDelayed(this, scrollSpeed);
                }
            }
        };
        handler.postDelayed(runnable, scrollSpeed);

这将自动将您的 RecyclerView 滚动到最后,等待一秒钟 (So User Can Read Till End) 并在 RecyclerView 的数组列表中跳转/滚动回第一个字符串。 如果你想在正负方向自动滚动You Just Need To Change The Condition Instead Of Using if(!flag) You Need To Set Value Of x in it

    if (flag) x = 15;
    else x= -15;  // For Auto Scroll To Negative i.e Left Direction

【讨论】:

  • 使用 smoothScrollBy 禁用 onClick 项目,如何解决该问题
【解决方案5】:
private void hanldeAutoScroll() {


    int position=0;

    final int duration = 2000;
    //final int pixelsToMove = 90;

    final Handler mHandler = new Handler(Looper.getMainLooper());
     final Runnable SCROLLING_RUNNABLE = new Runnable() {

        @Override
        public void run() {

            position++;

            if (position<urls.size())
            {
                recyclerView.scrollToPosition(position);

            }else if (position==urls.size())
            {

                position=-1;

            }

           // recyclerView.smoothScrollBy(pixelsToMove, 0);
            mHandler.postDelayed(this, duration);
        }
    };
    mHandler.postDelayed(SCROLLING_RUNNABLE, 2000);




}

【讨论】:

  • 使用 smoothScrollToPosition 而不是 scrollToPosition 以获得更好的滚动效果。
【解决方案6】:

在 Kotlin 中简化:

 lifecycleScope.launch(Dispatchers.Main, start = CoroutineStart.DEFAULT) {
        var position = MINIMUM_POSITION
        repeat(AUTO_SCROLL_REPEATING_TIMES) {
            delay(SCROLL_DELAY)
            rvBanners.smoothScrollToPosition(position)
            when {
                position+1 == listSize -> position = 0
                position == 0 -> position = MINIMUM_POSITION
                else -> position++
            }
        }
    }

如果你想在特定时间开始自动滚动:

val job = lifecycleScope.launch(Dispatchers.Main, start = CoroutineStart.LAZY) {
        var position = MINIMUM_POSITION
        repeat(AUTO_SCROLL_REPEATING_TIMES) {
            delay(SCROLL_DELAY)
            rvBanners.smoothScrollToPosition(position)
            when {
                position+1 == listSize -> position = 0
                position == 0 -> position = MINIMUM_POSITION
                else -> position++
            }
        }
    }
...
job.start()

【讨论】:

    【解决方案7】:

    你也可以这样实现,设置recyclerview为adapter后

    final int duration = 10;
    final int pixelsToMove = 263;
    final Handler mHandler = new Handler(Looper.getMainLooper());
    
    final Runnable SCROLLING_RUNNABLE = new Runnable() {
            @Override
            public void run() {
                recyclerView.smoothScrollBy(pixelsToMove, 0);
                mHandler.postDelayed(this, duration);
            }
        };
    
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int lastItem = horizontalLayoutManager.findLastCompletelyVisibleItemPosition();
                if (lastItem == horizontalLayoutManager.getItemCount() - 1) {
                    mHandler.removeCallbacks(SCROLLING_RUNNABLE);
                    Handler postHandler = new Handler();
                    postHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            quickTips.setAdapter(null);
                            quickTips.setAdapter(adapter);
                            mHandler.postDelayed(SCROLLING_RUNNABLE, 2000);
                        }
                    }, 2000);
                }
            }
        });
        mHandler.postDelayed(SCROLLING_RUNNABLE, 2000);
    

    【讨论】:

      【解决方案8】:

      对于平滑自动滚动,您可以使用此自定义 RecyclerView 类,您还可以在其中设置滚动时间。

      public class AutoScrollRecyclerView extends RecyclerView {
          private static long delayTime = 45;// How long after the interval to perform scrolling
          AutoPollTask autoPollTask;// Scroll thread
          private boolean running; // Is it rolling?
          private boolean canRun;// Can it be automatically scrolled, depending on whether the data exceeds the screen
      
          public AutoScrollRecyclerView(Context context) {
              super(context);
          }
      
          public AutoScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
              super(context, attrs);
              autoPollTask = new AutoPollTask(this);// Instantiate the scroll refresh thread
          }
      
          static class AutoPollTask implements Runnable {
              private final WeakReference<AutoScrollRecyclerView> mReference;
      
              // Use weak references to hold external class references to prevent memory leaks
              public AutoPollTask(AutoScrollRecyclerView reference) {
                  this.mReference = new WeakReference<>(reference);
              }
      
              @Override
              public void run() {
                  AutoScrollRecyclerView recyclerView = mReference.get();// Get the recyclerview object
                  if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
                      recyclerView.scrollBy(2, 2);// Note the difference between scrollBy and scrollTo
                      //delayed to send
                      recyclerView.postDelayed(recyclerView.autoPollTask, delayTime);
                  }
              }
          }
      
          @Override
          public boolean onTouchEvent(MotionEvent e) {
              switch (e.getAction()) {
                  case MotionEvent.ACTION_DOWN:
                      /*if (running)
                          stop();*/
                      break;
                  case MotionEvent.ACTION_UP:
                  case MotionEvent.ACTION_CANCEL:
                  case MotionEvent.ACTION_OUTSIDE:
                      /*if (canRun)
                          start();*/
                      break;
              }
              return super.onTouchEvent(e);
          }
      
          //Open: If it is running, stop first -> then open
          public void start() {
              if (running)
                  stop();
              canRun = true;
              running = true;
              postDelayed(autoPollTask, delayTime);
          }
          
          public void stop() {
              running = false;
              removeCallbacks(autoPollTask);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-12-18
        • 2020-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多