如何在Xamarin android中使用FastScroller调整RecyclerView中的滚动条?

时间:2017-12-11 12:36:32

标签: android xamarin xamarin.android recyclerview-layout fast-scroller

我想在xamarin.android中使用bubble text view实现快速滚动。我从以下链接中获取了参考资料

https://github.com/xamarin/monodroid-samples/tree/master/FastScroll

此示例无法正常使用较少的项目。在此示例中,为快速滚动创建了5000个项目并且其正常工作但在我的情况下,只有20个项目。 滚动条无法滚动页面末尾及其波动。

FastScoller.cs

public class FastScroller : LinearLayout
    {
        private static int BUBBLE_ANIMATION_DURATION=100;
        private static int TRACK_SNAP_RANGE=5;

        private TextView bubble;
        private View handle;
        private RecyclerView recyclerView;
        private MyScrollListener scrollListener;
        private int height;
        private ObjectAnimator currentAnimator = null;

        public FastScroller(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
        {
            init(context);
        }
        public FastScroller(Context context) : base(context)
        {
            init(context);
        }
        public FastScroller(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            init(context);
        }

        private void init(Context context)
        {
            scrollListener = new MyScrollListener(this);

            Orientation = Orientation.Horizontal;
            SetClipChildren(false);
            LayoutInflater inflater = LayoutInflater.FromContext(context);
            inflater.Inflate(Resource.Layout.FastScroller, this, true);

            bubble = FindViewById<TextView>(Resource.Id.fastscroller_bubble);
            handle = FindViewById<View>(Resource.Id.fastscroller_handle);
            bubble.Visibility = ViewStates.Invisible;
        }

        protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
        {
            base.OnSizeChanged(w, h, oldw, oldh);
            height = h;
        }

        public override bool OnTouchEvent(MotionEvent e)
        {
            var action = e.Action;
            switch (action) {
            case MotionEventActions.Down:
                if (e.GetX() < handle.GetX())
                    return false;
                if (currentAnimator != null)
                    currentAnimator.Cancel();
                if (bubble.Visibility == ViewStates.Invisible)
                    showBubble();
                handle.Selected = true;
                setPosition(e.GetY());
                setRecyclerViewPosition(e.GetY());
                return true;

            case MotionEventActions.Move:
                setPosition(e.GetY());
                setRecyclerViewPosition(e.GetY());
                return true;

            case MotionEventActions.Up:
            case MotionEventActions.Cancel:
                handle.Selected = false;
                hideBubble();
                return true;
            }

            return base.OnTouchEvent(e);
        }

        public void SetRecyclerView(RecyclerView rv)
        {
            this.recyclerView = rv;
            this.recyclerView.SetOnScrollListener(scrollListener);
        }

        private void setRecyclerViewPosition(float y)
        {
            if (recyclerView != null) {
                var itemCount = recyclerView.GetAdapter().ItemCount;
                float proportion;
                if ((int)handle.GetY() == 0)
                    proportion = 0f;
                else if (handle.GetY() + handle.Height >= height - TRACK_SNAP_RANGE)
                    proportion = 1f;
                else
                    proportion = y / (float)height;

                int targetPos = getValueInRange(0, itemCount - 1, (int)(proportion * (float)itemCount));
                recyclerView.ScrollToPosition(targetPos);

                var adapter = recyclerView.GetAdapter() as BaseRecyclerAdapter;
                bubble.Text = adapter.GetTextToShowInBubble(targetPos);
            }
        }

        private int getValueInRange(int min,int max,int value)
        {
            int minimum=Math.Max(min,value);
            return Math.Min(minimum,max);
        }

        private void setPosition(float y)
        {
            int bubbleHeight=bubble.Height;
            int handleHeight=handle.Height;
            handle.SetY(getValueInRange(0,height-handleHeight,(int)(y-handleHeight/2)));
            bubble.SetY(getValueInRange(0,height-bubbleHeight-handleHeight/2,(int)(y-bubbleHeight)));
        }

        private void showBubble()
        {
            bubble.Visibility = ViewStates.Visible;
            if(currentAnimator!=null)
                currentAnimator.Cancel();
            currentAnimator = (ObjectAnimator)ObjectAnimator.OfFloat(bubble, "alpha", 0f, 1f).SetDuration(BUBBLE_ANIMATION_DURATION);
            currentAnimator.Start();
        }

        private void hideBubble()
        {
            if(currentAnimator != null)
                currentAnimator.Cancel();
            currentAnimator = (ObjectAnimator)ObjectAnimator.OfFloat(bubble,"alpha",1f,0f).SetDuration(BUBBLE_ANIMATION_DURATION);
            currentAnimator.AddListener(new MyListener(this));
            currentAnimator.Start();
        }

        internal class MyListener : AnimatorListenerAdapter
        {
            private FastScroller scroll;

            public MyListener(FastScroller scroller)
            {
                this.scroll = scroller;
            }

            public override void OnAnimationEnd(Animator animation)
            {
                base.OnAnimationEnd(animation);
                scroll.bubble.Visibility = ViewStates.Invisible;
                scroll.currentAnimator = null;
            }
            public override void OnAnimationCancel(Animator animation)
            {
                base.OnAnimationCancel(animation);
                scroll.bubble.Visibility = ViewStates.Invisible;
                scroll.currentAnimator = null;
            }
        }

        internal class MyScrollListener : RecyclerView.OnScrollListener
        {
            private readonly FastScroller scroll;

            public MyScrollListener(FastScroller scroller)
            {
                this.scroll = scroller;
            }

            public override void OnScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                View firstVisibleView   = recyclerView.GetChildAt(0);
                int firstVisiblePosition = recyclerView.GetChildPosition(firstVisibleView);
                int visibleRange        = recyclerView.ChildCount;
                int lastVisiblePosition = firstVisiblePosition + visibleRange;
                int itemCount           = recyclerView.GetAdapter().ItemCount;
                int position;

                if(firstVisiblePosition==0)
                    position=0;
                else if(lastVisiblePosition==itemCount-1)
                    position = itemCount-1;
                else
                    position = firstVisiblePosition;

                float proportion=(float)position/(float)itemCount;
                this.scroll.setPosition(scroll.height*proportion);
            }
        }
    }

上述课程中有些计算错误。

如何正确调整滚动条?

0 个答案:

没有答案