49

私が見つけた素晴らしい解決策がない一般的な問題のようです。目標は、フォーカスのある (またはその問題の任意のビュー)ScrollViewへの自動スクロールを停止することです。EditText

にたくさんのビュー ( ButtonTextViewなど) がありScrollView、そのうちの 1 つが ですEditText。内のボタンをクリックすると、 (オフスクリーン)まで下ScrollViewScrollViewスクロールします。EditText画面からスクロールしたくない要素が他にもあるため、これは望ましくありません。

に他のフォーカス可能な要素を配置することで、画面が最初に表示されたときにこれを防ぐことができますScrollView。ただし、一般的な問題は依然として存在します。ユーザーは手動で まで下にスクロールしEditText、いくつかの数字を入力してから、一番上までスクロールし (EditText今は画面外)、 のボタンをクリックしてScrollView、何を推測しますか? そのScrollViewくそまでスクロールダウンしEditTextます。

を拡張して、ScrollViewのようないくつかのメソッドをオーバーライドすることを考えてfindFocusableViewInBoundsいますが、さらに問題が発生するだけだと感じています。

できれば助けてください。

EditTextの上部に0 の高さを設定しScrollViewたり、 Next Focusable 要素のプロパティを の他のアイテムに追加したりするScrollViewなど、いろいろ試してみました。1 つの「ハック」はEditText、仮想または手動キーボードが隠れるか何かになります。

4

21 に答える 21

38

かなり長い間その問題に苦しんだ後、あまり醜くならずにうまくいくように見える解決策を見つけました。まず、ViewGroup(直接) 含まれてEditTextいるものはすべてdescendantFocusability、"Before Descendants" にfocusable設定され、"true" にfocusableInTouchMode設定され、さらに "true" に設定されていることを確認します。これはScrollViewそれ自体ではなく、さまざまなビューがある内部のレイアウトです。次に、次のように、タッチされるたびにからフォーカスを削除するを に追加onTouchListenerします。ScrollViewEditText

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ことです。そのため、スクロールは発生しません。

于 2011-06-26T19:56:28.127 に答える
10

私も同じ問題を抱えていました。この問題に対処するために私が使用しているトリックが1つあります。

public void onClick(View v) {
    button.requestFocusFromTouch(); //prevents from loosing focus and scrolling view down
    ....
}
于 2011-05-30T14:01:28.000 に答える
9

問題は Java コードではなく、マニフェスト コードにあります。

AndroidManifest.xml で、Activity に属性を追加します。

        <activity android:name=".MyActivity" android:windowSoftInputMode="adjustPan"> </activity>
于 2013-05-28T15:15:12.517 に答える
7

以下に 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オートフォーカスされなくなります。

于 2016-06-23T05:57:37.770 に答える
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"and thenによってフォーカス可能にする必要があるためです<requestFocus></requestFocus> 。これはIMOのたびに機能するはずです

于 2011-09-11T05:45:57.947 に答える
2

この最も恐ろしいバグに対する私の修正 (これは 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;
    }
}
于 2013-12-04T17:55:08.943 に答える
2

私は同様の問題を抱えていて、最終的にそれを機能させました。私のスクロールビューには、一連のカスタマイズされたボタンが含まれており、その後にEditText(通常はフォーカスがありますが、フォーカスを失いたくありません) が続きます。ボタンがクリックされるたびに、スクロール ビューはフォーカスされたEditText. オーバーライドpublic boolean requestChildRectangleOnScreen(final View child, final Rect rectangle, final boolean immediate)して常に返すfalse( a のデフォルトの動作ViewGroup) がうまくいきました。あなたの状況にも役立つことを願っています。

于 2014-10-30T20:24:13.107 に答える
2

thomas88wp の回答、https://stackoverflow.com/a/6486348/528746がうまくいきました。しかし、私には 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;
        }

    });
于 2012-08-14T07:06:42.200 に答える
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;
    }
});
于 2013-04-04T13:17:08.437 に答える
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>
于 2016-12-14T06:20:16.490 に答える
1

カスタム ScrollView を作成し (クラスを作成し、それに Horizo​​ntalScrollView を拡張させます)、スクロール可能なゲッター セッターを作成します。次に、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>
于 2014-02-19T15:25:11.200 に答える
1

アプリが向きの変更を処理するときに、この問題がよく発生します。

その場合、次の種類のコードを使用します。

@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);
        }
    });
    ...
}
于 2012-01-13T18:15:19.947 に答える
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);
}
于 2011-12-30T23:56:38.547 に答える
1

descendantFocusabilityScrollView を含む LinearLayout に属性を追加して、この問題を解決しました。値は ですblocksDescendants

例えば:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:descendantFocusability="blocksDescendants" >
于 2019-02-23T21:37:18.430 に答える
0

私の解決策は以下のとおりです。ソースコードをトレースし、いくつかの機能をオーバーライドして、フォーカスされたアイテムによる自動スクロールを停止します。

またはfocusedViewを使用して、が TextView であるか、その子が TextView であるかを確認できます。focusedView.findViewById(R.id.textview_id_you_defined) != nullfocusedView 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);
        }
    }
}
于 2015-06-13T06:44:41.623 に答える