রিসাইক্লারভিউ - কোনও নির্দিষ্ট অবস্থানে আইটেমের শীর্ষে স্ক্রোলটি কীভাবে মসৃণ করা যায়?


125

একটি পুনর্ব্যবহারযোগ্য ভিউতে, আমি হঠাৎ ব্যবহার করে একটি নির্বাচিত আইটেমের শীর্ষে স্ক্রোল করতে সক্ষম হয়েছি:

((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);

তবে এটি হঠাৎ করে আইটেমটিকে শীর্ষ অবস্থানে নিয়ে যায়। আমি কোনও আইটেমের উপরে মসৃণভাবে যেতে চাই

আমি চেষ্টা করেছি:

recyclerView.smoothScrollToPosition(position);

তবে এটি কার্যকরভাবে কাজ করে না কারণ এটি আইটেমটিকে শীর্ষে নির্বাচিত অবস্থানে সরিয়ে দেয় না। অবস্থানটিতে থাকা আইটেমটি দৃশ্যমান না হওয়া পর্যন্ত এটি কেবল তালিকাটি স্ক্রোল করে।

উত্তর:


225

RecyclerViewএক্সটেনসিবল হওয়ার জন্য ডিজাইন করা হয়েছে, সুতরাং কেবল স্ক্রোলিং সম্পাদন করার জন্য LayoutManager( দ্রোদেব প্রস্তাবিত হিসাবে ) সাবক্লাস করার দরকার নেই ।

পরিবর্তে, SmoothScrollerপছন্দ হিসাবে একটি তৈরি করুন SNAP_TO_START:

RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(context) {
  @Override protected int getVerticalSnapPreference() {
    return LinearSmoothScroller.SNAP_TO_START;
  }
};

এখন আপনি যে অবস্থানটিতে স্ক্রোল করতে চান সেটি সেট করুন:

smoothScroller.setTargetPosition(position);

এবং সেই স্মুথস্ক্রোলারটিকে লেআউটম্যানেজারে পাস করুন:

layoutManager.startSmoothScroll(smoothScroller);

9
এই সংক্ষিপ্ত সমাধানের জন্য ধন্যবাদ। আমার প্রয়োগের ক্ষেত্রে আমাকে আরও দুটি বিষয় বিবেচনা করতে হয়েছিল: আমার যেমন একটি অনুভূমিক স্ক্রোলিং দৃশ্য সেট করতে হয়েছিল protected int getHorizontalSnapPreference() { return LinearSmoothScroller.SNAP_TO_START; }। তবুও আমাকে বিমূর্ত পদ্ধতিটি প্রয়োগ করতে হয়েছিল public PointF computeScrollVectorForPosition(int targetPosition) { return layoutManager.computeScrollVectorForPosition(targetPosition); }
অস্ট্রিয়ানডুড

2
পুনর্ব্যবহারযোগ্য ভিউ এক্সটেনসিবল হতে ডিজাইন করা যেতে পারে তবে এর মতো একটি সাধারণ জিনিস অনুপস্থিত হতে অলস বোধ করে। ভাল উত্তর! ধন্যবাদ.
মাইকেল

8
এটি শুরু করার জন্য কী কোনও উপায় আছে, তবে এক্স ডিপি-র অফসেট সহ?
মার্ক বুয়েকিমা

5
এটির গতি কমিয়ে দেওয়া কি সম্ভব?
আলিরেজা নুরালি

3
এছাড়াও ভাবছেন যে স্ক্রোলটি ঘটে তার গতিতে কী পরিবর্তন করা যায় (ধীর) @
অ্যালিরেজা

112

এর জন্য আপনাকে একটি কাস্টম লেআউটম্যানেজার তৈরি করতে হবে

public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {

    public LinearLayoutManagerWithSmoothScroller(Context context) {
        super(context, VERTICAL, false);
    }

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

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

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

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }
    }
}

আপনার পুনর্ব্যবহারযোগ্য দর্শনের জন্য এটি ব্যবহার করুন এবং স্মুথস্ক্রোলটোপজেশন কল করুন।

উদাহরণ:

 recyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(context));
 recyclerView.smoothScrollToPosition(position);

এটি নির্দিষ্ট অবস্থানের পুনর্ব্যবহারযোগ্য আইটেমের শীর্ষে স্ক্রোল করবে।

আশাকরি এটা সাহায্য করবে.


প্রস্তাবিত লেআউট ম্যানেজারটি প্রয়োগ করতে আমার সমস্যা হয়েছিল। এই উত্তর এখানে আমার জন্য অনেক সহজ কাজ stackoverflow.com/questions/28025425/...
arberg

3
ঘন্টা ব্যাথা পরে শুধুমাত্র দরকারী উত্তর, এটি নকশা হিসাবে কাজ করে!
wblaschko

1
@ জলদেব আমি আপনার উদাহরণটি মসৃণ স্ক্রোলিং সহ ব্যবহার করেছি এবং সাধারণত এসএনএপিএক্সপিএলটি আমার যা প্রয়োজন তা কিন্তু এটি আমার জন্য কিছু সমস্যা নিয়ে কাজ করে। কখনও কখনও স্ক্রোলিং 1,2,3 বা 4 পজিশন থামিয়ে দেয় যেগুলি আমি পাস করেছিলাম smoothScrollToPosition। কেন এই সমস্যা হতে পারে? ধন্যবাদ।
নাতাশা

আপনি কি কোনওভাবে আমাদের কাছে আপনার কোড পৌঁছে দিতে পারেন? আমি নিশ্চিত যে এটি আপনার কোড সমস্যা।
দ্রোদেব

1
এটি গৃহীত হওয়া সত্ত্বেও সঠিক উত্তর
অ্যালিসিও

25

এটি একটি হল এক্সটেনশন ফাংশন আমি লিখেছে Kotlin সঙ্গে ব্যবহার করার জন্য RecyclerView(@Paul Woitaschek উত্তর উপর ভিত্তি করে):

fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
  val smoothScroller = object : LinearSmoothScroller(this.context) {
    override fun getVerticalSnapPreference(): Int = snapMode
    override fun getHorizontalSnapPreference(): Int = snapMode
  }
  smoothScroller.targetPosition = position
  layoutManager?.startSmoothScroll(smoothScroller)
}

এটি এর মতো ব্যবহার করুন:

myRecyclerView.smoothSnapToPosition(itemPosition)

এইটা কাজ করে! মসৃণ স্ক্রোলের সমস্যাটি যখন আপনার কাছে বড় তালিকা থাকে এবং তারপরে নীচে বা শীর্ষে স্ক্রোল করে দীর্ঘ, দীর্ঘ সময় লাগে
পোর্টফোলিওবিল্ডার

@ ওওয়াহোস্ট আমি কীভাবে পছন্দসই অবস্থানটি কেন্দ্র করতে পারি?
ysfcyln

@ysfcyln এই চেক করুন stackoverflow.com/a/39654328/1502079 উত্তর
vovahost

12

আমরা এই মত চেষ্টা করতে পারেন

    recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(), recyclerView.getAdapter().getItemCount());

5

অফসেট ওয়াই / এক্স অবস্থান বাস্তবায়নের জন্য লিনিয়ারসমুথস্ক্রোলারে ক্যালকুলেটডাইটোমেকভিজেবল / ক্যালকুলেটডএক্সটোমেকভিজেবল ফাংশনটি ওভাররাইড করুন

override fun calculateDyToMakeVisible(view: View, snapPreference: Int): Int {
    return super.calculateDyToMakeVisible(view, snapPreference) - ConvertUtils.dp2px(10f)
}

এই আমি খুঁজছিলাম ছিল। এক্স / ওয়াই এর অফসেট অবস্থান বাস্তবায়নের জন্য এটি ভাগ করে নেওয়ার জন্য ধন্যবাদ :)
শান জিশি

3

RecyclerViewএটিকে স্ক্রোল করার সবচেয়ে সহজ উপায়টি হ'ল:

// Define the Index we wish to scroll to.
final int lIndex = 0;
// Assign the RecyclerView's LayoutManager.
this.getRecyclerView().setLayoutManager(this.getLinearLayoutManager());
// Scroll the RecyclerView to the Index.
this.getLinearLayoutManager().smoothScrollToPosition(this.getRecyclerView(), new RecyclerView.State(), lIndex);

2
যদি ইতিমধ্যে অবস্থানটি দৃশ্যমান হয় তবে এটি কোনও অবস্থানে স্ক্রোল করবে না won't অবস্থানটি দৃশ্যমান করার জন্য এটি সর্বনিম্ন পরিমাণে স্ক্রোল করে। সুতরাং কেন আমাদের নির্দিষ্ট অফসেট সহ একটি প্রয়োজন।
টাটিওভারফ্লো

3

আমি এটির মতো ব্যবহার করেছি:

recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, new RecyclerView.State(), 5);

2

ধন্যবাদ, সমাধানের জন্য @ জলদেব যদি কেউ কোটলিন সমাধানের সন্ধান করে তবে এটি উল্লেখ করুন:

    class LinearLayoutManagerWithSmoothScroller: LinearLayoutManager {
    constructor(context: Context) : this(context, VERTICAL,false)
    constructor(context: Context, orientation: Int, reverseValue: Boolean) : super(context, orientation, reverseValue)

    override fun smoothScrollToPosition(recyclerView: RecyclerView?, state: RecyclerView.State?, position: Int) {
        super.smoothScrollToPosition(recyclerView, state, position)
        val smoothScroller = TopSnappedSmoothScroller(recyclerView?.context)
        smoothScroller.targetPosition = position
        startSmoothScroll(smoothScroller)
    }

    private class TopSnappedSmoothScroller(context: Context?) : LinearSmoothScroller(context){
        var mContext = context
        override fun computeScrollVectorForPosition(targetPosition: Int): PointF? {
            return LinearLayoutManagerWithSmoothScroller(mContext as Context)
                    .computeScrollVectorForPosition(targetPosition)
        }

        override fun getVerticalSnapPreference(): Int {
            return SNAP_TO_START
        }


    }

}

1
ধন্যবাদ @ পঙ্কজ, কোটলিনে একটি সমাধান খুঁজছিলেন।
অক্ষয় কুমার দুজনেই

1
  1. "লিনিয়ারলআউট" শ্রেণি প্রসারিত করুন এবং প্রয়োজনীয় ফাংশনগুলি ওভাররাইড করুন
  2. আপনার খণ্ড বা ক্রিয়াকলাপে উপরের শ্রেণীর উদাহরণ তৈরি করুন
  3. "রিসাইক্লারভিউ.স্মোথস্ক্রোলটোপজিশন (টার্গেটপজিশন) কল করুন

কাস্টমলাইনারলআউটআউট.কেটি:

class CustomLayoutManager(private val context: Context, layoutDirection: Int):
  LinearLayoutManager(context, layoutDirection, false) {

    companion object {
      // This determines how smooth the scrolling will be
      private
      const val MILLISECONDS_PER_INCH = 300f
    }

    override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State, position: Int) {

      val smoothScroller: LinearSmoothScroller = object: LinearSmoothScroller(context) {

        fun dp2px(dpValue: Float): Int {
          val scale = context.resources.displayMetrics.density
          return (dpValue * scale + 0.5f).toInt()
        }

        // change this and the return super type to "calculateDyToMakeVisible" if the layout direction is set to VERTICAL
        override fun calculateDxToMakeVisible(view: View ? , snapPreference : Int): Int {
          return super.calculateDxToMakeVisible(view, SNAP_TO_END) - dp2px(50f)
        }

        //This controls the direction in which smoothScroll looks for your view
        override fun computeScrollVectorForPosition(targetPosition: Int): PointF ? {
          return this @CustomLayoutManager.computeScrollVectorForPosition(targetPosition)
        }

        //This returns the milliseconds it takes to scroll one pixel.
        override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
          return MILLISECONDS_PER_INCH / displayMetrics.densityDpi
        }
      }
      smoothScroller.targetPosition = position
      startSmoothScroll(smoothScroller)
    }
  }

দ্রষ্টব্য: উপরের উদাহরণটি HORIZONTAL দিকনির্দেশে সেট করা হয়েছে, আপনি আরম্ভের সময় ভার্টিকাল / HORIZONTAL পাস করতে পারেন।

আপনি যদি ভার্টিকালটির দিকে নির্দেশ করেন তবে আপনার " ক্যালকুলেটডএক্সটোমেকভিজিবল " কে " ক্যালকুলেটডাইটোমেকভিজিবল " এ পরিবর্তন করা উচিত (সুপার টাইপ কল রিটার্ন মানটিও মনে করুন)

ক্রিয়াকলাপ / খণ্ড খণ্ডন :

...
smoothScrollerLayoutManager = CustomLayoutManager(context, LinearLayoutManager.HORIZONTAL)
recyclerView.layoutManager = smoothScrollerLayoutManager
.
.
.
fun onClick() {
  // targetPosition passed from the adapter to activity/fragment
  recyclerView.smoothScrollToPosition(targetPosition)
}

0

সম্ভবত @ জলদেব পদ্ধতির সঠিক উপায়, তবে আমি কেবল কিছুটা আলাদা কিছু প্রকাশ করতে চাই যা মূলত একই কাজ করে এবং লেআউটম্যানেজারের সম্প্রসারণের প্রয়োজন হয় না।

এখানে একটি নোট - আপনার আইটেমটি (তালিকার শীর্ষে যেটি আপনি স্ক্রোল করতে চান) স্ক্রিনে দৃশ্যমান হয় এবং আপনি এটি স্বয়ংক্রিয়ভাবে শীর্ষে স্ক্রোল করতে চান তবে এটি ভাল কাজ করবে। এটি কার্যকর যখন আপনার তালিকার শেষ আইটেমটিতে কিছু ক্রিয়া থাকে, যা একই তালিকায় নতুন আইটেম যুক্ত করে এবং আপনি ব্যবহারকারীকে নতুন যুক্ত হওয়া আইটেমগুলিতে ফোকাস করতে চান:

int recyclerViewTop = recyclerView.getTop();
int positionTop = recyclerView.findViewHolderForAdapterPosition(positionToScroll) != null ? recyclerView.findViewHolderForAdapterPosition(positionToScroll).itemView.getTop() : 200;
final int calcOffset = positionTop - recyclerViewTop; 
//then the actual scroll is gonna happen with (x offset = 0) and (y offset = calcOffset)
recyclerView.scrollBy(0, offset);

ধারণাটি সহজ: 1. আমাদের পুনর্ব্যবহারযোগ্য উপাদানটির শীর্ষ সমন্বয় পেতে হবে; ২. আমাদের যে ভিউ আইটেমের উপরে শীর্ষে স্ক্রোল করতে চাই তার শীর্ষ স্থানাঙ্কী পেতে হবে; ৩. গণনা করা অফসেটটি শেষে আমাদের করা দরকার

recyclerView.scrollBy(0, offset);

200 হ'ল হার্ড কোডড পূর্ণসংখ্যা মান যা উদাহরণস্বরূপ, ভিউহোল্ডার আইটেমটি উপস্থিত না থাকলে আপনি ব্যবহার করতে পারেন, কারণ এটিও সম্ভব।


0

আমি আরও পুরোপুরি স্ক্রোল সময়কাল ইস্যুটি মোকাবিলা করতে চাই , আপনি যদি পূর্বের কোনও উত্তর চয়ন করেন তবে বর্তমান অবস্থান থেকে লক্ষ্য অবস্থানে পৌঁছানোর জন্য প্রয়োজনীয় স্ক্রোলিংয়ের পরিমাণ অনুযায়ী নাটকীয়ভাবে (এবং অগ্রহণযোগ্য) আলাদা হবে।

অভিন্ন স্ক্রোল সময়কাল অর্জন করতে বেগ প্রতিটি গতিবিধিতে (মিলি সেকেন্ডে প্রতি পিক্সেল) অবশ্যই পৃথক আইটেমের আকারের জন্য অ্যাকাউন্ট করে - এবং যখন আইটেমগুলি মানক-না-মাত্রিক হয় তখন জটিলতার একটি সম্পূর্ণ নতুন স্তর যুক্ত হয়।

এই কারণেই রিসাইক্লারভিউ বিকাশকারীরা মসৃণ স্ক্রোলিংয়ের এই গুরুত্বপূর্ণ দিকটির জন্য খুব শক্ত ঝুড়ি স্থাপন করেছিলেন ।

ধরে নিই যে আপনি একটি আধা-ইউনিফর্ম স্ক্রোল সময়কাল চান এবং আপনার তালিকায় অর্ধ-ইউনিফর্ম আইটেম রয়েছে তবে আপনার এর মতো কিছু প্রয়োজন হবে।

/** Smoothly scroll to specified position allowing for interval specification. <br>
 * Note crude deceleration towards end of scroll
 * @param rv        Your RecyclerView
 * @param toPos     Position to scroll to
 * @param duration  Approximate desired duration of scroll (ms)
 * @throws IllegalArgumentException */
private static void smoothScroll(RecyclerView rv, int toPos, int duration) throws IllegalArgumentException {
    int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000;     // See androidx.recyclerview.widget.LinearSmoothScroller
    int itemHeight = rv.getChildAt(0).getHeight();  // Height of first visible view! NB: ViewGroup method!
    itemHeight = itemHeight + 33;                   // Example pixel Adjustment for decoration?
    int fvPos = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
    int i = Math.abs((fvPos - toPos) * itemHeight);
    if (i == 0) { i = (int) Math.abs(rv.getChildAt(0).getY()); }
    final int totalPix = i;                         // Best guess: Total number of pixels to scroll
    RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(rv.getContext()) {
        @Override protected int getVerticalSnapPreference() {
            return LinearSmoothScroller.SNAP_TO_START;
        }
        @Override protected int calculateTimeForScrolling(int dx) {
            int ms = (int) ( duration * dx / (float)totalPix );
            // Now double the interval for the last fling.
            if (dx < TARGET_SEEK_SCROLL_DISTANCE_PX ) { ms = ms*2; } // Crude deceleration!
            //lg(format("For dx=%d we allot %dms", dx, ms));
            return ms;
        }
    };
    //lg(format("Total pixels from = %d to %d = %d [ itemHeight=%dpix ]", fvPos, toPos, totalPix, itemHeight));
    smoothScroller.setTargetPosition(toPos);
    rv.getLayoutManager().startSmoothScroll(smoothScroller);
}

দ্রষ্টব্য: আমি অভিশাপ দিন আমি শুরু করেন নির্বিচারে রূপান্তর ListView করার RecyclerView


0

আপনি আপনার তালিকা list.reverse()এবং ফাইনাল কল দ্বারা বিপরীত করতে পারেনRecylerView.scrollToPosition(0)

    list.reverse()
    layout = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,true)  
    RecylerView.scrollToPosition(0)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.