停止ScrollView从自动滚动到EditText

|| 没有找到很好的解决方案,这似乎是一个常见的问题。目标是阻止ѭ0auto自动滚动到具有焦点的
EditText
(或与此相关的任何视图)。 您在
ScrollView
中有很多视图(
Button
、,3ѭ等),其中一个是is1ѭ。单击“ 0”中的“说一个按钮”后,“ 0”向下滚动到“ 1”(屏幕外)。这是不希望的,因为您不希望将其他元素滚动到屏幕之外。 现在,我可以在
ScrollView
中包含其他可聚焦元素来阻止在屏幕首次显示时发生这种情况。但是,一般问题仍然存在。用户手动向下滚动到ѭ1,输入一些数字,然后向上滚动到顶部(现在屏幕上移出
EditText
),然后单击
ScrollView
中的按钮,您猜怎么着?
ScrollView
向下滚动至该1ѭ。 我正在考虑扩展ѭ0并覆盖其中的某些方法(例如
findFocusableViewInBounds
),但是我有种感觉,我只会惹上更多麻烦。 如果可以的话请帮忙。 我一直在玩这样的事情,例如在我的
ScrollView
的顶部具有高度0的
EditText
,在Focus0ѭ的其他项中添加Next Focusable元素属性,等等。我想一个\“ hack \”可能是为了获得
EditText
隐藏虚拟或手动键盘或其他东西时会失去焦点。     
已邀请:
        经过一段时间的努力后,我找到了一个看起来不太丑的解决方案。首先,请确保无论是
ViewGroup
(直接)包含您的
EditText
,还是将
descendantFocusability
设置为\“ Before Descendants \”,“24ѭ设置为\” true \“,并将
focusableInTouchMode
设置为\” true。\“,这将不是
ScrollView
本身,但是里面有各种视图的布局。接下来,在您的
ScrollView
上添加一个
onTouchListener
,只要触摸
EditText
就会将焦点移开,就像这样:
ScrollView scroll = (ScrollView)findViewById(R.id.scrollView1);
scroll.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (myEditText.hasFocus()) {
            myEditText.clearFocus();
        }
        return false;
    }
});
告诉我这是否不能解决问题。应该发生的是布局获得焦点而不是
EditText
,因此不会发生滚动。     
        只需在linearlayout的顶部创建一个空视图
<View android:layout_width=\"fill_parent\" android:id=\"@+id/focus_view\" android:layout_height=\"0dp\" android:focusable=\"true\" android:focusableInTouchMode=\"true\"><requestFocus/></View>
单线解决问题     
        我有同样的问题。我正在使用一个技巧来解决此问题:
public void onClick(View v) {
    button.requestFocusFromTouch(); //prevents from loosing focus and scrolling view down
    ....
}
    
        问题不在Java代码上,而是在清单代码上。 在您的AndroidManifest.xml中向“活动”添加一个属性:
        <activity android:name=\".MyActivity\" android:windowSoftInputMode=\"adjustPan\"> </activity>
    
        在以下位置添加2个参数:
android:focusable=\"true\"
android:focusableInTouchMode=\"true\"
主布局在那里。
<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
    xmlns:tools=\"http://schemas.android.com/tools\"
    android:id=\"@+id/layMain\"
    android:layout_width=\"match_parent\"
    android:layout_height=\"match_parent\"
    android:background=\"@color/background\"
    android:focusable=\"true\"
    android:focusableInTouchMode=\"true\">
EditText
将不会自动对焦。     
        这是我所做的
 <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
    android:layout_width=\"fill_parent\" style=\"@style/measurementTableRowStyle\"
    android:focusable=\"true\" android:layout_height=\"fill_parent\">
    <requestFocus></requestFocus>
    <LinearLayout android:id=\"@+id/linearLayout1\"
        android:orientation=\"horizontal\" android:layout_width=\"fill_parent\"
        android:layout_height=\"wrap_content\">
        <TextView android:id=\"@+id/desc_text\" android:text=\"Value : \"
            style=\"@style/attributeNameTextStyle\" android:layout_width=\"wrap_content\"
            android:focusable=\"true\" android:layout_height=\"wrap_content\">
            <requestFocus></requestFocus>
        </TextView>

        <TextView style=\"@style/attributeValueStyle\" android:id=\"@+id/value_text\"
            android:text=\"TextView\" android:layout_width=\"wrap_content\"
            android:layout_height=\"wrap_content\"></TextView>
    </LinearLayout>
原因是在这种情况下,您必须使所有其他视图在滚动视图内可聚焦,分别由显式的
android:focusable=\"true\"
<requestFocus></requestFocus>
聚焦。这应该在每次IMO时都有效     
        thomas88wp回答,https://stackoverflow.com/a/6486348/528746为我工作。 但是我有两个问题: 1.滚动时,我想隐藏键盘 2.我有很多EditText视图,不想为每个视图写它 (我这样做是getActivity(),因为我是在Fragment(而不是活动)中编写的)
    ScrollView scroll = (ScrollView)view.findViewById(R.id.layout_scroll);
    scroll.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // Check if the view with focus is EditText
            if (getActivity().getCurrentFocus() instanceof EditText)
            {
                EditText ed = (EditText)getActivity().getCurrentFocus();
                if (ed.hasFocus()) {

                    // Hide the keyboard
                    InputMethodManager inputManager = (InputMethodManager)
                            getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); 
                    inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
                            InputMethodManager.HIDE_NOT_ALWAYS);
                    // Clear the focus
                    ed.clearFocus();
                }
            }
            return false;
        }

    });
    
        我对这个最可怕的错误的修复(值得注意的是,这是API11之前的版本,仅在他们将fling方法修改为不愚蠢的地方)。 旧的fling方法找到了将要到达的下一个焦点。该类的其他版本不能真正起作用,因为当用户真正从键盘上遍历表单时,它们将停止焦点工作。
public class NonFocusingScrollView extends ScrollView {

    private boolean mBlockRequestFocusOnFling = false;

    public NonFocusingScrollView(Context context) {
        super(context);
    }

    public NonFocusingScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public ArrayList<View> getFocusables(int direction) {
        if(mBlockRequestFocusOnFling)
            return new ArrayList<View>();
        return super.getFocusables(direction);
    }

    @Override
    public void requestChildFocus(View child, View focused) {
        if(!mBlockRequestFocusOnFling)
        super.requestChildFocus(child, focused);
    }


    @Override
    public void fling(int velocityY) {
        mBlockRequestFocusOnFling = true;
        super.fling(velocityY);
        mBlockRequestFocusOnFling = false;
    }
}
    
        我们可以编写一个自定义ScrollView并重写onScrollChanged方法,并从焦点视图中清除焦点,还可以选择隐藏键盘。
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    View v = getFocusedChild();
    if (v != null) {
        InputMethodManager imm = (InputMethodManager) getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
        v.clearFocus();
    }
    super.onScrollChanged(l, t, oldl, oldt);
}
    
        thomas88wp的代码的另一个版本:
ScrollView scroll = (ScrollView)getActivity().findViewById(R.id.scrollView_addNewBill);
    scroll.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {        
            View focussedView = getCurrentFocus(); 
            if( focussedView != null ) focussedView.clearFocus();
                
            return false;
    }
});
    
        如果有人愿意,我做了一个测试项目来尝试各种解决方案。 https://github.com/marchold/EditText-ErrorPopup-Scroll-View     
        创建一个自定义ScrollView(创建一个类,并使它扩展Horizo​​ntalScrollView),并使getter setter成为可滚动的。然后覆盖computeScrollDeltaToGetChildRectOnScreen。 工作原理:每次android都在屏幕外出现一个编辑文本或焦点所在的内容时,它都会调用方法computeScrollDeltaToGetChildRectOnScreen将其显示。如果您覆盖它并在禁用它时返回0,则它将不会滚动... 因此,您将获得一个自定义滚动视图,如下所示:
    public class TrackableHorizontalScrollView extends HorizontalScrollView {


    // true if we can scroll (not locked)
    // false if we cannot scroll (locked)
    private boolean mScrollable = true;

    public TrackableHorizontalScrollView(Context context) {
        super(context);
    }

    public TrackableHorizontalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TrackableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setScrollingEnabled(boolean enabled) {
        mScrollable = enabled;
    }

    public boolean isScrollable() {
        return mScrollable;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // if we can scroll pass the event to the superclass
                if (mScrollable) return super.onTouchEvent(ev);
                // only continue to handle the touch event if scrolling enabled
                return mScrollable; // mScrollable is always false at this point
            default:
                return super.onTouchEvent(ev);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // Don\'t do anything with intercepted touch events if
        // we are not scrollable
        if (!mScrollable) return false;
        else return super.onInterceptTouchEvent(ev);
    }

    @Override
    public void scrollTo(int x, int y){
        if (!mScrollable) return;
        super.scrollTo(x, y);
    }


    //Custom smooth scroll method since norm is final and cannot be overridden
    public final void smooothScrollToIfEnabled(int x, int y){
         if (!mScrollable) return;
         smoothScrollTo(x, y);
    }

    @Override
    protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect rect){
        if (!mScrollable) return 0;
        return super.computeScrollDeltaToGetChildRectOnScreen(rect);
    }


}
您可以像下面这样在XML中使用它:
<com.your.package.ui.widget.TrackableHorizontalScrollView
            android:id=\"@+id/wi_et_credit_scroller\"
            android:layout_toRightOf=\"@id/wi_et_credit_iv\"
            android:layout_width=\"fill_parent\"
            android:scrollbars=\"none\"
            android:layout_height=\"wrap_content\"
            android:paddingRight=\"5dp\"
            android:layout_gravity=\"center_vertical\">

<!--Whatever you have inside the scrollview-->

</com.your.package.ui.widget.TrackableHorizontalScrollView>
    
我遇到了类似的问题,终于让它起作用了。我的滚动视图包含一系列自定义按钮,后跟一个
EditText
(通常具有焦点,但我不希望它失去焦点)。任何时候单击按钮,滚动视图都会自动滚动到焦点ѭ1。覆盖
public boolean requestChildRectangleOnScreen(final View child, final Rect rectangle, final boolean immediate)
并始终返回
false
(default21ѭ的默认行为)可以解决问题。希望它也对您的情况有所帮助。     
        最好的解决方案是为您的scrollview的子项添加焦点选项:
android:descendantFocusability=\"beforeDescendants\"
android:focusable=\"true\"
android:focusableInTouchMode=\"true\"
然后,您的xml文件将如下所示:
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"
    android:id=\"@+id/scrollView\"
    android:layout_width=\"match_parent\"
    android:layout_height=\"match_parent\" >

    <LinearLayout
        android:layout_width=\"match_parent\"
        android:layout_height=\"match_parent\"
        android:layout_marginRight=\"50dp\"
        android:descendantFocusability=\"beforeDescendants\"
        android:focusable=\"true\"
        android:focusableInTouchMode=\"true\"
        android:orientation=\"vertical\" >

        <EditText
            android:id=\"@+id/editText_one\"
            android:layout_width=\"match_parent\"
            android:layout_height=\"100dp\"
            android:text=\"TestApp 1\" />

        <EditText
            android:id=\"@+id/editText_two\"
            android:layout_width=\"match_parent\"
            android:layout_height=\"100dp\"
            android:text=\"TestApp 2\" />

       <EditText
            android:id=\"@+id/editText_three\"
            android:layout_width=\"match_parent\"
            android:layout_height=\"100dp\"
            android:text=\"TestApp 3\" />


    </LinearLayout>

</ScrollView>
    
        当我的应用程序处理方向更改时,我经常遇到此问题。 在这种情况下,我使用以下类型的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // to avoid the scrollview to scroll to this element automatically
    mEditTextSearch.setFocusable(false);
    // Get the saved scroll position
    final int scrolly = savedInstanceState.getInt(\"scrolly\");
    mScrollView.post(new Runnable() {
        @Override
        public void run() {
            mScrollView.scrollTo(0, scrolly);
            // Restore the initial state of the EditText
            mEditTextSearch.setFocusable(true);
            mEditTextSearch.setFocusableInTouchMode(true);
            mEditTextSearch.setClickable(true);
        }
    });
    ...
}
    
        对我来说,覆盖ScrollView onTouch无效。 android:descendantFocusability =“ \” beforeDescendants \“也不起作用 android:focusableInTouchMode = \“ true \” 该解决方案和其他提到的解决方案仅在第一次使用时有效-仅当未选择EditText时才有效,但是一旦选择它,scrollview就会再次自动滚动。 因为我已经编写了在触摸其他视图时隐藏键盘的代码,所以我只添加了两行代码,它的工作原理很简单:
public static void setupUI(final Activity activity, final View view) {
    //view is the parent view in your layout
    OnTouchListener mTouchListener = new OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            try {
                View vFocused = null;
                vFocused = activity.getCurrentFocus();

                if (vFocused != null) {
                    hideSoftKeyboard(activity, v);
                    if (vFocused instanceof EditText) {
                        vFocused.clearFocus();//this is the trick to avoid ScrollView autoscroll
                    }
                }
            } catch (Exception e) {
            }
            return false;
        }
    };

    // Set up touch listener for non-text box views to hide keyboard.
    if (!(view instanceof EditText) && !(view instanceof ViewGroup)) {
        view.setOnTouchListener(mTouchListener);
    }

    // If a layout container, iterate over children and seed recursion.
    if (view instanceof ViewGroup) {
        view.setOnTouchListener(mTouchListener);
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            View innerView = ((ViewGroup) view).getChildAt(i);
            setupUI(activity, innerView);
        }
    }
}
public static void hideSoftKeyboard(Context context, View v) {
    InputMethodManager inputMethodManager = (InputMethodManager) context
            .getSystemService(Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
在根视图中也添加了此内容:
android:descendantFocusability=\"beforeDescendants\" android:focusableInTouchMode=\"true\"
也许它不是很好的解决方案,但是可以正常工作。     
        我的解决方案是在下面,以跟踪源代码并覆盖某些功能以停止按焦点项目自动滚动。 您可以检查ѭ​​57ѭ是TextView还是其子级是TextView, 用
focusedView.findViewById(R.id.textview_id_you_defined) != null
focusedView instanceof TextView == true
public class StopAutoFocusScrollView extends ScrollView {

    private View focusedView;
    private ScrollMonitorListener listener;

    public interface ScrollMonitorListener {
        public boolean enableScroll(View view);
    }
    public StopAutoFocusScrollView(Context context) {
        super(context);
    }

    public StopAutoFocusScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public StopAutoFocusScrollView(Context context, AttributeSet attrs, 
           int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setScrollMonitorListener(ScrollMonitorListener listener) {
        this.listener = listener;
    }

    @Override
    public void requestChildFocus(View child, View focused) {
        focusedView = focused
        super.requestChildFocus(child, focused);
    }
    //flow : requestChildFocus -> scrollToChild -> scrollBy
    //Therefore, you can give listener to determine you want scroll to or not
    @Override
    public void scrollBy(int x, int y) {
        if (listener == null || listener.enableScroll(focusedView)) {
            super.scrollBy(x, y);
        }
    }
}
    
        对于这种令人毛骨悚然的缺陷,我有不同的反对意见。每当我点击EditTexts下面的多个RadioButton之一时,滚动位置就会跳转,以适应Android确定为可见且聚焦的EditText。 所有试图通过发布
ScrollView.scrollTo(x,y)
的ѭ61to保持当前所需滚动位置的尝试都被Android完全否决了! 我分享我的解决方案,希望它可以为其他人节省8(八)小时的浪费。
/* This interesting little \'hack\' prevents unwanted scroll \'jump\' occurring when
 user touches a RadioButton for example
[ Causes focus to change - but maybe this is a lesser evil! ] */
mScrollView.setOnTouchListener(new View.OnTouchListener() {
    @Override public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() != MotionEvent.ACTION_UP) 
            return false;

        mScrollView.clearFocus();
        return false;
    }
});
    
        只有以下代码对我有用:
public static void preventScrollViewFromScrollingToEdiText(ScrollView view) {
    view.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
    view.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            v.requestFocusFromTouch();
            return false;
        }
    });
}
所有学分归功于这个原始答案。     
        试试这个:)
public class CustomHorizontalScrollView extends HorizontalScrollView {

    public CustomHorizontalScrollView(Context context) {
    super(context);
    }

    public CustomHorizontalScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
    }

    public CustomHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    return super.onInterceptTouchEvent(ev);
    }

    @Override
    public void scrollTo(int x, int y) {
    super.scrollTo(x, y);
    }


    //Custom smooth scroll method since norm is final and cannot be overridden
    public final void smooothScrollToIfEnabled(int x, int y) {
    smoothScrollTo(x, y);
    }

    @Override
    protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect rect) {
/*  if (getContext() != null && getContext() instanceof Activity) {
        Activity activity = (Activity) getContext();
        if (!activity.isFinishing()) {
        View view = activity.getCurrentFocus();
        if (view != null) {
            if (view instanceof EditText) {
            return 0;
            }
        }
        }
    }
    return super.computeScrollDeltaToGetChildRectOnScreen(rect);

*/
return 0;
    }

}
    
        我解决了这个问题,将
descendantFocusability
属性添加到包含LinearLayout的ScrollView \中,值为
blockDescendants
。 例如:
<LinearLayout
    android:layout_width=\"match_parent\"
    android:layout_height=\"wrap_content\"
    android:orientation=\"vertical\"
    android:descendantFocusability=\"blocksDescendants\" >
    

要回复问题请先登录注册