如果没有我找到的出色解决方案,似乎是一个常见问题。目标是阻止ScrollView
自动滚动到具有焦点的EditText
(或任何视图)。
Button
中有一堆观看(TextView
s,ScrollView
等),其中一个是EditText
。点击ScrollView
内的按钮后,ScrollView
向下滚动到EditText
(其关闭屏幕)。这是不可取的,因为您不希望其他元素滚动离开屏幕。
现在,我可以通过在ScrollView
中显示其他可聚焦元素来首先显示屏幕时阻止这种情况发生。但是,一般问题仍然存在。用户手动向下滚动到EditText
,输入一些数字,然后向上滚动到顶部(EditText
关闭屏幕),他们点击ScrollView
中的按钮,猜猜是什么? ScrollView
向下滚动到该徽标EditText
。
我正在考虑扩展ScrollView
并覆盖某些方法,例如findFocusableViewInBounds
,但我有一种感觉,我会让自己陷入更多麻烦。
如果可以,请帮忙。
我已经玩过EditText
顶部有0高ScrollView
之类的内容,将{Next {1}}中的其他项添加Next Focusable元素属性等。我认为一个“黑客”可能是让ScrollView
在虚拟或手动键盘被隐藏或其他东西时失去焦点。
答案 0 :(得分:35)
经过一段时间的努力解决这个问题之后,我找到了一个似乎不会太难看的解决方案。首先,请确保ViewGroup
(直接)包含EditText
descendantFocusability
设置为“在后人之前”,focusable
设置为“true”和focusableInTouchMode
设为“true”。这不是ScrollView
本身,而是您拥有各种视图的布局。接下来向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
,因此不应该进行滚动。
答案 1 :(得分:19)
只需在linearlayout
的顶部创建一个空视图<View android:layout_width="fill_parent" android:id="@+id/focus_view" android:layout_height="0dp" android:focusable="true" android:focusableInTouchMode="true"><requestFocus/></View>
单行解决问题
答案 2 :(得分:9)
我遇到了同样的问题。我正在使用一个技巧来处理这个问题:
public void onClick(View v) {
button.requestFocusFromTouch(); //prevents from loosing focus and scrolling view down
....
}
答案 3 :(得分:8)
问题不在于java代码,而是在清单代码上。
在AndroidManifest.xml中为Activity添加一个属性:
<activity android:name=".MyActivity" android:windowSoftInputMode="adjustPan"> </activity>
答案 4 :(得分:7)
在:
中添加2个参数android:focusable="true"
android:focusableInTouchMode="true"
那里有Main布局。
<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
不会自动关注。
答案 5 :(得分:4)
这就是我做的事情
<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
答案 6 :(得分:2)
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;
}
});
答案 7 :(得分:2)
我对这个最恐怖的错误的修复,(值得注意的是,只有在他们修改了fling方法而不是愚蠢的情况下,这只是API11之前的版本。)
旧的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;
}
}
答案 8 :(得分:1)
我做了一个测试项目,试验各种解决方案,如果有人想玩它。 https://github.com/marchold/EditText-ErrorPopup-Scroll-View
答案 9 :(得分:1)
最佳解决方案是为您的滚动视图的子项添加焦点选项:
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>
答案 10 :(得分:1)
我遇到了类似的问题,最后还是开始工作了。我的滚动视图包含一系列自定义按钮,后跟EditText
(通常具有焦点,但我不希望它失去焦点)。只要单击按钮,滚动视图就会自动滚动到焦点EditText
。覆盖public boolean requestChildRectangleOnScreen(final View child, final Rect rectangle, final boolean immediate)
并始终返回false
(ViewGroup
的默认行为)就可以了。希望它也有助于你的情况。
答案 11 :(得分:1)
创建一个自定义ScrollView(创建一个类并让它扩展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>
答案 12 :(得分:1)
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;
}
});
答案 13 :(得分:1)
我们可以编写自定义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);
}
答案 14 :(得分:0)
对我来说,它无法覆盖ScrollView onTouch。也没有工作android:descendantFocusability =&#34; beforeDescendants&#34; 机器人:focusableInTouchMode =&#34;真&#34; 这个和另一个提到的解决方案只在第一次工作 - 只有当没有选择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"
也许它不是很好的解决方案,但它的工作原理。
答案 15 :(得分:0)
我的解决方案如下,跟踪源代码并覆盖某些功能以停止按焦点项目自动滚动。
您可以检查focusedView
是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);
}
}
}
答案 16 :(得分:0)
当我的应用处理方向更改时,我经常遇到此问题。
在这种情况下,我使用以下类型的代码:
@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);
}
});
...
}
答案 17 :(得分:0)
我对这种令人愤怒的缺陷略有不同。每当我点击EditTexts下面的一些RadioButton时,滚动位置就会跳跃,以适应Android确定的可见和聚焦的EditText。
所有尝试通过发出WebDriver driver = new FirefoxDriver();
Runnable
的{{1}}保留当前所需的滚动位置都是由Android尽职尽责!
我分享我的解决方案,希望它可以节省别人8(8)浪费的时间。
ScrollView.scrollTo(x,y)
答案 18 :(得分:0)
只有这段代码适用于我:
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;
}
});
}
所有积分均转至this original answer。
答案 19 :(得分:0)
试试这个:)
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;
}
}
答案 20 :(得分:0)
我解决了这个问题,将descendantFocusability
属性添加到ScrollView包含LinearLayout的值blockDescendants
。
例如:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants" >