停止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)
并始终返回false
( ViewGroup
默认行为)做了诀窍。 希望它也可以帮助你的情况。
只有这个代码适用于我:
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一个类,并扩展HorizontalScrollView),并为可滚动的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) != null
或focusedView 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; } });