Make a scrollView autoscroll with drag and drop in Android

前端 未结 4 2028
借酒劲吻你
借酒劲吻你 2020-12-17 03:05

I searched all over, but could not find a solution.

I have a view (lets call it myView) inside a scrollview. myView is bigger than the screen. Since I\'m able to get

相关标签:
4条回答
  • 2020-12-17 03:51

    I used a timer in In C#

    ScrollCalendar ScrollCalendar = new ScrollCalendar (yourScrollView);
    

    Inside the drag event

        public bool OnDrag (View v, DragEvent e)
        {
            var dragshadow = new EventDateDragShadow (v);
            switch (e.Action) {
            case DragAction.Started:
                return true;
            case DragAction.Entered:
                break;
            case Android.Views.DragAction.Location:
    
                if (e.GetY () < 90) {
                    ScrollCalendar.StartScroll (-15);
                } else if (e.GetY () > yourScrollView.Height - 90) {
                    ScrollCalendar.StartScroll (15);
                } else
                    ScrollCalendar.StopScroll ();
    
                return (true);
            case DragAction.Exited:
                return true;
            case DragAction.Drop:
                return true;
            case DragAction.Ended:
                ScrollCalendar.StopScroll ();
                v.SetOnDragListener (null);
                return true;
            }
    
            return true;
        }
    

    The ScrollCalendar class

    public class ScrollCalendar
    {
        private ScrollView Calendar;
        private System.Timers.Timer Timer;
        private int ScrollDistance;
    
        public ScrollCalendar(ScrollView calendar)
        {
            Calendar = calendar;
            Timer = new System.Timers.Timer();
            Timer.Elapsed+=new ElapsedEventHandler(Scroll);
            Timer.Interval = 50;
        }
    
        public void StartScroll(int scrollDistance)
        {
            if (Timer.Enabled) {
                return;
            }
            ScrollDistance = scrollDistance;
            Timer.Enabled = true;
        }
    
        public void StopScroll()
        {
            Timer.Enabled = false;
        }
    
        private void Scroll(object source, ElapsedEventArgs e)
        {
            Calendar.SmoothScrollBy (0, ScrollDistance);
        }
    
    }
    

    Change the StartScroll value and the Timer.Interval to adjust the speed of the scroll.

    0 讨论(0)
  • 2020-12-17 03:54

    I have modified answer of Tiago A. I faced the same problem and the solution from Tiago A was small and easy but have some limitation so if others require this may help. Thanks to Tiago A.

    case DragEvent.ACTION_DRAG_LOCATION:
                        ScrollView myScrollView =findViewById(R.id.myScrollView);
                        int topOfDropZone = myScrollView.getChildAt(0).getTop();
                        int bottomOfDropZone = myScrollView.getChildAt(0).getBottom();
    
                        int scrollY = myScrollView.getScrollY();
                        int scrollViewHeight = myScrollView.getMeasuredHeight();
    
                        if (Math.round(event.getY()) > scrollViewHeight - (scrollViewHeight / 45))
                            if (bottomOfDropZone > (scrollY + scrollViewHeight - 100))
                                myScrollView.smoothScrollBy(0, 30);
    
                        if (Math.round(event.getY()) < (scrollViewHeight / 45))
                            if (topOfDropZone < (scrollY + 100))
                                myScrollView.smoothScrollBy(0, -30);
    
                        return true;
    
    0 讨论(0)
  • 2020-12-17 03:56

    I came up with a different solution and I am happy with it.

    I want to be able to drag and drop views inside a ScrollView. The ScrollView then needs to scroll up and down automatically when the shadow reaches the edges of the scroll view.

    I ended up with a solution that detects wether the drop zone is completely visible inside the scrollview (with a 100px margin) and adjust the scroll view otherwise.

    @Override
    public boolean onDrag(View view, DragEvent event) {
    
        MainWidget dropZoneView = (MainWidget) view;
    
        int action = event.getAction();
        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
            //(... other stuff happens here)
            case DragEvent.ACTION_DRAG_LOCATION:
    
                ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scroll);
    
                int topOfDropZone = dropZoneView.getTop();
                int bottomOfDropZone = dropZoneView.getBottom();
    
                int scrollY = mainScrollView.getScrollY();
                int scrollViewHeight = mainScrollView.getMeasuredHeight();
    
                Log.d(LOG_TAG,"location: Scroll Y: "+ scrollY + " Scroll Y+Height: "+(scrollY + scrollViewHeight));
                Log.d(LOG_TAG," top: "+ topOfDropZone +" bottom: "+bottomOfDropZone);
    
                if (bottomOfDropZone > (scrollY + scrollViewHeight - 100))
                    mainScrollView.smoothScrollBy(0, 30);
    
                if (topOfDropZone < (scrollY + 100))
                    mainScrollView.smoothScrollBy(0, -30);
    
                break;
            default:
                break;
        }
        return true;
    }
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-17 04:01

    All right I figured it out by myself.

    First I had to extend the ScrollView class and added an interface OnScrollViewListener.

    public class MyScrollView extends ScrollView {
        private OnScrollViewListener mListener;
    
        public MyScrollView(Context c, AttributeSet attrs) {
           super(c, attrs);
        }
    
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
           super.onScrollChanged(l, t, oldl, oldt);
           if (mListener != null) {
               mListener.onScrollChanged((OnScrollViewListener) this);
           }
        }
    
    
        public void setOnScrollViewListener(OnScrollViewListener listener) {
           mListener = listener;
        }
    
    
        public static interface OnScrollViewListener {
           public void onScrollChanged(OnScrollViewListener listener);
        }
    }
    

    Next in my Activity I inserted a member mScrollDistance that indicates the amount of pixels the user scrolls.

    public class ScrollActivity extends Activity {
       private int mScrollDistance;
    
       @Override
       protected void OnCreate(...) {
         ...
    
         final MyScrollView myScrollView = (MyScrollView) findViewById(R.id.scroll_view);
         myScrollView.setOnScrollViewListener(new MyScrollView.OnScrollViewListener() {
    
              public void onScrollChanged(OnScrollViewListener listener) {
                 mScrollDistance = listener.getScrollY();
              }
         }
    
         // making an drag and drop in an view that is inside the MyScrollView
         final LinearLayout myLayout = (LinearLayout)findViewById(R.id.linear_layout);
         myLayout.setOnDragListener(new View.OnDragListener() {
           public boolean onDrag (View v, DragEvent event) {
             int action = event.getAction();
             switch(action) {
                case DragEvent.ACTION_DRAG_STARTED: {
                }
                case DragEvent.ACTION_DRAG_LOCATION: {
    
                  int y = Math.round(event.getY());
                  int translatedY = y - mScrollDistance;
                  int threshold = 50;
                  // make a scrolling up due the y has passed the threshold
                  if (translatedY < threshold) {
                     // make a scroll up by 30 px
                     myScrollView.scrollBy(0, -30);
                  }
                  // make a autoscrolling down due y has passed the 500 px border
                  if (translatedY + threshold > 500) {
                     // make a scroll down by 30 px
                     myScrollView.scrollBy(0, 30);
                  }
                  // listen for more actions here
                  // ...
                }
             }
           }
         }
    

    Now, mScrollDistance gets always a new value and the drag location will be translated to the view location. I tested this and it works on layouts/views that are bigger than the screen size.

    Hope that helps.

    0 讨论(0)
提交回复
热议问题