停止ScrollView从自动滚动到EditText

似乎没有我find的一个很好的解决scheme是一个常见的问题。 目标是阻止ScrollView从自动滚动到有焦点的EditText(或任何视图)。

在滚动视图中有一堆视图(button,文字视图等),其中一个是EditText。 在滚动视图中点击一个button后,滚动视图向下滚动到EditText(它的closures屏幕)。 这是不希望的,因为还有其他元素,你不想滚动屏幕。

现在,我可以通过在滚动视图中显示其他可聚焦元素来显示屏幕,从而避免发生这种情况。 但是,一般问题依然存在。 用户手动向下滚动到EditText,input一些数字,然后滚动到顶部(现在EditText离开屏幕),他们点击ScrollView中的一个button,然后猜测是什么? ScrollView向下滚动到那个Edit EditText。

我正在考虑子类Scrollview,并重写一些像findFocusableViewInBounds私有方法,但我有一种感觉,我只是让自己陷入更多的麻烦。

如果可以的话请帮忙。

我已经玩过了,比如在ScrollView的顶部有一个0高度的EditText,在ScrollView的其他项目中添加了Next Focusable元素属性等等。我猜想一个“破解”可能是让EditText失去焦点当虚拟或手动键盘被隐藏或什么的时候。

经过相当长时间的努力,我发现了一个似乎没有太难看的解决scheme。 首先,确保无论ViewGroup(直接)包含您的EditText,DescendantFocusability都设置为“Before Descendants之前”,Focusable设置为“true”,FocusableInTouchMode设置为“true”。 这不会是滚动视图本身,而是您有各种视图的布局。 接下来将一个onTouchListener添加到您的ScrollView中,每次触摸时都会从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顶部创build一个空视图

 <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:

  <activity android:name=".MyActivity" android:windowSoftInputMode="adjustPan"> </activity> 

这是我做的

  <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" focusable android:focusable="true" ,然后是<requestFocus></requestFocus> ,使所有其他视图在scrollview内部android:focusable="true" 。 这应该每次IMO工作

通过添加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不会被自动聚焦。

thomas88wp答案, https: //stackoverflow.com/a/6486348/528746为我工作。 但是我有两个问题:1.滚动时,我想隐藏键盘
2.我有很多的EditText视图,并不想为它们中的每一个都写
(我做getActivity(),因为我正在写一个片段而不是一个活动)

  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之前,他们修改了扔方法不愚蠢)。

旧的方法发现下一个焦点,它会得到..这不是真的有帮助。 这个类的其他版本并没有真正的工作,因为当用户从键盘真正遍历表单时,它们停止焦点工作。

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

我做了一个testing项目,尝试各种解决scheme,如果有人想玩。 https://github.com/marchold/EditText-ErrorPopup-Scroll-View

我遇到了类似的问题,终于把它工作了。 我的滚动视图包含一系列自定义的button,其次是一个EditText (通常有焦点,但我不希望它失去焦点)。 任何时候点击button,滚动视图自动滚动到聚焦的EditText 。 覆盖public boolean requestChildRectangleOnScreen(final View child, final Rect rectangle, final boolean immediate)并始终返回falseViewGroup默认行为)做了诀窍。 希望它也可以帮助你的情况。

只有这个代码适用于我:

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

所有学分都转到这个原始答案 。

我的应用程序处理方向更改时,我经常遇到这个问题。

在这种情况下,我使用以下代码:

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

创build一个自定义的ScrollView(创build一个类,并扩展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> 

对我来说,它不能覆盖ScrollView onTouch。 也没有工作android:descendantFocusability =“beforeDescendants”android:focusableInTouchMode =“true”这和另外提到的解决scheme只有第一次工作 – 只有当EditText没有被选中,但一旦你select它,滚动视图自动滚动再次。

因为我已经写了一个隐藏键盘的代码,所以我只是添加了两行代码,就像一个冠军:

 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" 

也许它不是很好的解决scheme,但它的工作。

最好的解决scheme是为您的滚动视图的子项添加焦点选项:

 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> 

我的解决scheme如下,跟踪源代码,并重写一些function,以停止自动滚动的焦点项目。

您可以通过使用focusedView.findViewById(R.id.textview_id_you_defined) != nullfocusedView instanceof TextView == true来检查focusedView是TextView还是其子focusedView是TextView。

 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)Runnable来保留当前所需的滚动位置ScrollView.scrollTo(x,y)都是由Android完成的IGNORED!

我分享我的解决scheme,希望它可以节省别人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; } });