【问题标题】:How can I prevent focus changes on scroll/fling for a HorizontalScrollView?如何防止 Horizo​​ntalScrollView 的滚动/翻转焦点更改?
【发布时间】:2019-08-27 17:11:06
【问题描述】:

HorizontalScrollView 中存在 EditText 或其他可聚焦视图时,它会在投掷时获得焦点。

深入源码,你会明白为什么:

    /**
     * Fling the scroll view
     *
     * @param velocityX The initial velocity in the X direction. Positive
     *                  numbers mean that the finger/cursor is moving down the screen,
     *                  which means we want to scroll towards the left.
     */
    public void fling(int velocityX) {
        if (getChildCount() > 0) {
            int width = getWidth() - mPaddingRight - mPaddingLeft;
            int right = getChildAt(0).getWidth();

            mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0,
                    Math.max(0, right - width), 0, 0, width/2, 0);

            final boolean movingRight = velocityX > 0;

            View currentFocused = findFocus();
            View newFocused = findFocusableViewInMyBounds(movingRight,
                    mScroller.getFinalX(), currentFocused);

            if (newFocused == null) {
                newFocused = this;
            }

            if (newFocused != currentFocused) {
                newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT);
            }

            postInvalidateOnAnimation();
        }
    }

一些建议的解决方法涉及使用以下属性:

   android:descendantFocusability="beforeDescendants"
   android:focusable="true"
   android:focusableInTouchMode="true"

这适用于一些简单的情况,但如果您的 HorizontalScrollView 嵌套在另一个 ScrollView 中,它可能会导致奇怪的行为(例如,外部滚动视图将跳转到现在被聚焦的容器)。

同样根据尝试此解决方案的经验,它可能需要将其添加到 每个 包含可聚焦视图的父容器(例如 EditText)。如果你有任何复杂的焦点逻辑,这一切都会失控。

还有其他变通的解决方案吗?

【问题讨论】:

    标签: android android-scrollview horizontalscrollview


    【解决方案1】:

    另一种解决方案是继承HorizontalScrollView 并进行以下修改:

    
    /**
     * Class which modifies default focus logic so that children aren't focused
     * when scrolling/flinging.
     */
    class NoFocusHorizontalScrollView(context: Context, attrs: AttributeSet) : HorizontalScrollView(context, attrs) {
    
      private var flingCallInProgress: Boolean = false
    
      override fun onRequestFocusInDescendants(direction: Int, previouslyFocusedRect: Rect?): Boolean {
        return true
      }
    
      override fun fling(velocityX: Int) {
        // Mark that the fling is in progress before calling the fling logic. 
        // This should be fairly safe given we're on the UI thread.
    
        flingCallInProgress = true
        super.fling(velocityX)
        flingCallInProgress = false
      }
    
      override fun getFocusables(direction: Int): ArrayList<View> {
        // During a fling HSV will try to focus on a child. This helps prevents that behavior.
    
        return if (flingCallInProgress) {
          ArrayList(0)
        } else {
          super.getFocusables(direction)
        }
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多