【问题标题】:Make a scrollView autoscroll with drag and drop in Android在 Android 中通过拖放创建一个 scrollView 自动滚动
【发布时间】:2011-09-08 17:37:42
【问题描述】:

我找遍了,但找不到解决办法。

我在滚动视图中有一个视图(我们称之为 myView)。 myView 比屏幕大。由于我能够在 myView 中获得手指的 relative x,y 位置,因此我希望当我的手指进入某个顶部/底部阈值时,让 scrollView 自动滚动到顶部/底部。 我有一些想法,即将拖动位置转换为屏幕位置,但这并没有解决这个问题。

提前致谢

干杯

【问题讨论】:

    标签: android android-scrollview


    【解决方案1】:

    好吧,我自己想通了。

    首先我必须扩展 ScrollView 类并添加一个接口 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);
        }
    }
    

    接下来在我的 Activity 中,我插入了一个成员 mScrollDistance,它表示 用户滚动的像素。

    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
                  // ...
                }
             }
           }
         }
    

    现在,mScrollDistance 总是获得一个新值,并且拖动位置将被转换为视图位置。 我对此进行了测试,它适用于大于屏幕尺寸的布局/视图。

    希望对您有所帮助。

    【讨论】:

    • 感谢您的想法,尽管您不必为自定义 ScrollView 付出全部努力。在计算 translateY 变量时,您可以简单地使用普通 ScrollView 的 getScrollY() 方法,而不是使用自定义 ScrollView 和侦听器等来获取 mScrollDistance。
    • 我意识到你的解决方案只有在只有一个元素被拖动并且最终基于覆盖dispatchDragEvent() 方法而得到一个完全不同的解决方案时才有效。如果有人对细节感兴趣,请在这里评论。
    • @Ridcully 当我们尝试向下拖放时,此解决方案不起作用。此外,如果尝试向下拖放,然后尝试向上拖放其他元素,这不起作用。如果您能提供相同的解决方案,那将会很有帮助。
    【解决方案2】:

    我想出了一个不同的解决方案,我很满意。

    我希望能够在 ScrollView 中拖放视图。当阴影到达滚动视图的边缘时,ScrollView 需要自动上下滚动。

    我最终得到了一个解决方案,它可以检测拖放区在滚动视图内是否完全可见(具有 100 像素的边距),否则调整滚动视图。

    @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;
    }
    

    希望这会有所帮助!

    【讨论】:

    • 感谢您的解决方案,但在我的情况下,它仅适用于向上滚动。不能在底部自动滚动中工作你能帮我做同样的事情吗?
    • 这个解决方案是 7 年前的。从那以后,我对原生 Android 并没有做太多事情,并且很久以前就离开了这个项目。所以...不...抱歉,它不适合您。
    【解决方案3】:

    我在 C# 中使用了一个计时器

    ScrollCalendar ScrollCalendar = new ScrollCalendar (yourScrollView);
    

    拖动事件内部

        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;
        }
    

    ScrollCalendar 类

    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);
        }
    
    }
    

    更改 StartScroll 值和 Timer.Interval 以调整滚动速度。

    【讨论】:

      【解决方案4】:

      我修改了 Tiago A 的答案。 我遇到了同样的问题,Tiago A 的解决方案既小又简单,但有一些限制,所以如果其他人需要,这可能会有所帮助。 感谢 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;
      

      【讨论】:

      • 你能补充更多细节吗,比如限制是什么?你的解决方案是什么?
      猜你喜欢
      • 1970-01-01
      • 2011-07-22
      • 2013-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多