Почему TextView.setText вызывает прокрутку вмещающего ScrollView? - PullRequest
4 голосов
/ 25 июня 2010

У меня есть странная проблема, которая возникает в 1.6, 2.2 и MyTouch 3G Slide (это API # 7, и в списке «Выбор устройств Android» указано «2.1-Update1»).Если кто-то может объяснить, что я делаю неправильно и как это исправить (или, возможно, подтвердить, что это ошибка Android), я был бы очень признателен!

Основная идея для моего приложения - сделатьсекундомер - что-то вроде того, что пользователь может нажать кнопку, чтобы запустить таймер, а затем снова нажать ее, чтобы остановить (приостановить) таймер;дальнейшие нажатия чередуются между возобновлением таймера и его приостановкой.

У меня есть ScrollView верхнего уровня, который содержит RelativelLayout, который содержит несколько виджетов.Первый виджет - ОГРОМНАЯ кнопка (чтобы ее было легко нажимать), которая толкает все остальные мои виджеты ниже нижней части экрана.Это сделано намеренно, так как я хочу положиться на ScrollView (и экранное напоминание для пользователя), чтобы сделать остальные параметры ввода доступными.

У меня есть простая настройка типа конечного автоматагде mState - текущий режим (STATE_TIMER_NOT_STARTED до того, как пользователь нажимает какие-либо кнопки, ... RUNNING после первого нажатия, а затем ... PAUSED после второго, возврат в ... RUNNING после третьего и т. д. и т. д.).

Все это прекрасно работает, за исключением того, что, когда таймер работает, и пользователь снова нажимает кнопку пуска / остановки / возобновления, ScrollView будет прокручиваться вниз.Я НЕ запускаю эту команду (у меня даже нет ссылки на объект ScrollView), и я не уверен, почему он это делает.

REPRO: Компилировать + запустить приведенные ниже примеры.Когда приложение запустится, нажмите кнопку «Start Timing».Используйте большой палец (или мышь) для перетаскивания экрана вверх (чтобы вы могли увидеть панель оценок), затем перетащите его вниз (чтобы кнопка снова полностью появилась на экране).Нажмите кнопку (которая теперь читает «PauseTiming») еще раз, и она немного подпрыгнет.Он НЕ должен прыгать / прокручиваться вниз, так как нет оператора (который я вижу), который говорит ему прокручивать вниз.Насколько я могу судить, именно setText вызывает прокрутку (когда я закомментирую эти строки, прокрутка не происходит).

ЧТО Я ЗАПРОСУ: Если я делаю что-то глупое, и вы могли быукажите, что это такое, я бы очень признателен!:) *** Интересно, может ли «сенсорный режим» как-то иметь к этому отношение, поскольку это не происходит (в эмуляторе), когда я использую колесо прокрутки мыши для перемещения панели вверх (т. Е. Вместосимуляция перетаскивания пальцев).Я не могу найти много всего в сенсорном режиме, и ничего особенного в фокусировке / выборе в сенсорном режиме в ScrollView

Если вы можете подтвердить, что эта ошибка возникает и для вас, это тоже будет хорошо(поскольку несчастье любит компанию. AHEM Я имею в виду, поскольку это может помочь подтвердить, что это не только я :)).

MyTestApp.java

package bug.android.scrollview;

import android.app.Activity;
import android.os.Bundle;
import android.text.format.Time;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;

public class MyTestApp extends Activity {

    public final static int STATE_TIMER_NOT_STARTED = 1;
    public final static int STATE_TIMER_RUNNING = 2;
    public final static int STATE_TIMER_PAUSED = 3;
    private int mState;

    Time t = new Time();

    private Time data = new Time();

    private Button btnStartStopResume;
    private TextView lblSpacer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.new_time_entry);

        btnStartStopResume = (Button) findViewById(R.id.btnStartStopResume);

        // Set the button's size so that the other info will also be visible
        Display display = ((WindowManager) getSystemService(WINDOW_SERVICE))
                .getDefaultDisplay();
        // This is such a hack, but the windowScroller doesn't appear to
        // have a height at this point in the lifecycle (nor in 'onResume' :( )
        btnStartStopResume.setHeight(display.getHeight() - 200);

        lblSpacer = (TextView) findViewById(R.id.lblSpacer);

        reset();
    }

    public void doStartStopResume(View v) {
        if (mState == MyTestApp.STATE_TIMER_NOT_STARTED) {

            mState = MyTestApp.STATE_TIMER_RUNNING;

            data.setToNow();

        } else if (mState == MyTestApp.STATE_TIMER_RUNNING) {
            mState = MyTestApp.STATE_TIMER_PAUSED;

            String s = getString(R.string.add_scroll_down_to_add);
            lblSpacer.setText(s);
        } else if (mState == MyTestApp.STATE_TIMER_PAUSED) {

            mState = MyTestApp.STATE_TIMER_RUNNING;
        }
    }
    public void doReset(View v) {
    }

    public void doNewRunClick(View v) {
    }

    public void doAddTiming(View v) {
    }

    public void reset() {
        mState = STATE_TIMER_NOT_STARTED;
    }
}

new_time_entry.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/windowScroller"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
>
    <RelativeLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
    >
        <Button
            android:id="@+id/btnStartStopResume"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dip"
            android:text="Start Timing"
            android:textSize="40dp"
            android:height="290dp"
            android:onClick="doStartStopResume" />

        <TextView
            android:id="@+id/lblSpacer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/btnStartStopResume"
            android:layout_centerHorizontal="true"
            android:text="@string/add_scroll_down_for_more" />

        <TextView
            android:id="@+id/lblTimeStartLabel"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblSpacer"
            android:layout_alignParentLeft="true"
            android:clickable="true"
            android:onClick="adjustStartTime"
            android:text="Start of this run:"
            android:textSize="8dp" />

        <TextView
            android:id="@+id/lblTimeStart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblTimeStartLabel"
            android:layout_alignParentLeft="true"
            android:clickable="true"
            android:onClick="adjustStartTime"
            android:text="--:--:-- --"
            android:textColor="#FFFFFF"
            android:textSize="26dp" />

        <TextView
            android:id="@+id/lblElapsedLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblSpacer"
            android:layout_alignRight="@id/lblSpacer"
            android:layout_marginRight="5dp"
            android:text="Elapsed Time:"
            android:textSize="8dp" />

        <TextView
            android:id="@+id/lblTimeElapsed"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblElapsedLabel"
            android:layout_alignRight="@id/lblSpacer"
            android:layout_marginRight="5dp"
            android:textColor="#99ff66"
            android:text="-- m -- sec"
            android:textSize="26dp" 
            android:layout_marginBottom="10dip"/>

        <CheckBox
            android:id="@+id/chkNewRun"
            android:onClick="doNewRunClick"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblTimeElapsed"
            android:text="This is a new run of timings"
            android:layout_marginBottom="10dip" />

        <TextView
            android:id="@+id/lblIntensity"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Intensity (1 = none 5 = max)"
            android:layout_below="@id/chkNewRun" />

        <RatingBar
            android:id="@+id/rbIntensity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/lblIntensity"
            android:numStars="5"
            android:rating="2"
            android:layout_marginBottom="5dip" />

        <TextView
            android:id="@+id/lblNotes"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Notes:"
            android:layout_below="@id/rbIntensity" />

        <EditText
            android:id="@+id/txtNotes"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@android:drawable/editbox_background"
            android:layout_below="@id/lblNotes"
            android:layout_marginBottom="10dip" />


        <Button
            android:id="@+id/btnReset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/txtNotes"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="10dip"
            android:text="Reset"
            android:onClick="doReset" />

        <Button
            android:id="@+id/btnOk"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/txtNotes"
            android:layout_toRightOf="@id/btnReset"
            android:layout_alignParentRight="true"
            android:layout_marginLeft="10dip"
            android:layout_marginRight="10dip"
            android:text="Add Timing To List"
            android:onClick="doAddTiming" />
    </RelativeLayout>
</ScrollView>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Timer</string>
    <string name="dlg_edit_timing_title">Edit A Timing</string>
    <string name="add_scroll_down_for_more">&lt; Scroll down for more options! &gt;</string>
    <string name="add_scroll_down_to_add">&lt; Scroll down to save this timing! &gt;</string>
    <string name="start_timing">Start Timing\n\n</string>
    <string name="stop_timing">Pause Timing\n\n</string>
    <string name="resume_timing">Resume Timing\n\n</string>
</resources>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="bug.android.scrollview"
    android:versionCode="1"
    android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".MyTestApp"
        android:label="@string/app_name">
        <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="5" />
</manifest>

ОБНОВЛЕНИЕ 1: добавление

        if(  btnStartStopResume.isInTouchMode() )
            Toast.makeText(this, "TOUCH MODE", 2000);
        else
            Toast.makeText(this, "NOT touch mode", 2000);

, а затем установка точек останова в отладчике подтверждает, что кнопка всегда находится в сенсорном режиме (независимо от того, перетаскиваю ли я панель вверх / вниз,или колесико мыши вверх / вниз).Таким образом, это сочетание того, что вы находитесь в сенсорном режиме и перетаскиваете панель пальцем после 2-го нажатия кнопки (т. Е. Когда приложение находится в режиме «остановка / пауза»), что вызывает странное дополнительное время в последующих паузах.

ОБНОВЛЕНИЕ 2: Я только что заметил, что он прокручивается до EditText, и не дальше.Похоже, что когда вы перемещаете панель вниз, EditText получает выделение, а после события щелчка ScrollView прокручивает обратно к объекту, у которого есть выделение.Кажется, объясняет, почему подход с колесом мыши не имеет этой проблемы (он перемещает выделение / фокус обратно на кнопку).

Ответы [ 3 ]

5 голосов
/ 04 февраля 2013

Старая тема, но я подумал, что добавлю это на случай, если кто-нибудь будет искать, как я.У меня была та же проблема, но просто очистка фокуса не помогла.Вот что окончательно решило это для меня:

editText.clearFocus();
editText.setTextKeepState(text);

Надеюсь, это кому-нибудь поможет. Документы TextView

2 голосов
/ 26 июня 2010

Хорошо, у меня есть представление о том, что происходит, и достаточно идеи о том, как обойти это, что я подумал, что я мог бы также опубликовать это здесь, как ответ:

Если вы вызываете clearFocus для EditText перед любым вызовом setText (который является одновременно обработчиком события кнопки и несколькими таймерами, которые я запускаю через обработчик потока в «реальной» версии этой программы), тогда все работает так, как я ожидаю (без странной автопрокрутки).

Если вы хотите использовать это решение, вам нужно очистить фокус от всего, что могло бы его сфокусировать, что делает его неудачным решением - я постараюсь продолжать смотреть на это. Под документами ScrollView есть метод с именем onRequestFocusInDescendants с загадочной пометкой «При поиске фокуса у дочерних элементов вида прокрутки нужно быть немного более осторожным, чтобы не фокусироваться на чем-то, что прокручивается за пределы экрана. реализация ViewGroup по умолчанию, в противном случае это поведение могло бы быть сделано по умолчанию. " что может указывать на то, что здесь происходит ...

0 голосов
/ 12 августа 2015

Я пробовал решения на этой странице, и они не работали для меня. У меня был вид прокрутки, который прокручивался каждый раз, когда я нажимал кнопку обновления в представлении. Я закончил тем, что сделал заголовок, который находится слева от фокусируемой кнопки, и установил фокус этого элемента в моем обратном вызове кнопки.

Часть моего onCreateView в моем фрагменте:

final View view = inflater.inflate(R.layout.fragment_diagnostic, container, false);
view.findViewById(R.id.button_refresh_bluetooth_device).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        updateBluetoothDevice();
        view.findViewById(R.id.bluetooth_device_title).requestFocus();
    }
});
view.findViewById(R.id.button_refresh_network).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        updateNetworkSection();
        view.findViewById(R.id.android_network_title).requestFocus();
    }
});

Упрощенная версия моего макета:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/parentPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/alert_dialog_padding_material"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/topPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:paddingLeft="@dimen/alert_dialog_padding_material"
        android:paddingRight="@dimen/alert_dialog_padding_material"
        android:paddingBottom="@dimen/floating_action_button_margin">

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/button_refresh"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_alignParentRight="true"
            android:padding="@dimen/floating_action_button_margin"
            android:src="@drawable/ic_fab_refresh"
            android:contentDescription="@string/content_description_refresh"
            app:elevation="4dp"
            app:borderWidth="0dp"
            app:fabSize="mini"/>

        <TextView
            android:id="@+id/alertTitle"
            style="?android:attr/windowTitleStyle"
            android:singleLine="true"
            android:ellipsize="end"
            android:layout_toLeftOf="@id/button_refresh"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:paddingBottom="@dimen/floating_action_button_margin"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/title_diagnostics"/>
    </RelativeLayout>

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:layout_weight="1"
        android:orientation="vertical"
        android:minHeight="48dp"
        android:paddingLeft="@dimen/alert_dialog_padding_material"
        android:paddingRight="@dimen/alert_dialog_padding_material"
        android:paddingBottom="@dimen/alert_dialog_padding_material">

        <TableLayout
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:clipChildren="false"
            android:shrinkColumns="1"
            android:stretchColumns="1,2">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

                <TextView
                    android:id="@+id/bluetooth_device_title"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:textAppearance="?android:attr/textAppearanceLarge"
                    android:text="@string/title_bluetooth_device"
                    android:focusable="true"
                    android:focusableInTouchMode="true"/>

                <android.support.design.widget.FloatingActionButton
                    android:id="@+id/button_refresh_bluetooth_device"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="@dimen/floating_action_button_margin"
                    android:src="@drawable/ic_fab_refresh"
                    android:contentDescription="@string/content_description_refresh"
                    app:elevation="4dp"
                    app:borderWidth="0dp"
                    app:fabSize="mini"/>
            </LinearLayout>

            <TableRow>

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="5dp"
                    android:layout_gravity="center_vertical"
                    android:id="@+id/bt_connection_status_image"
                    tools:src="@drawable/ic_check"
                    android:contentDescription="@string/content_description_diagnostic_status"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:layout_gravity="center_vertical"
                    android:text="@string/label_state"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:layout_gravity="center_vertical"
                    tools:text="Connected"
                    android:id="@+id/bt_connection_status"/>

            </TableRow>

            <LinearLayout
                android:id="@+id/android_network_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:textAppearance="?android:attr/textAppearanceLarge"
                    android:text="@string/title_android_to_network"
                    android:focusable="true"
                    android:focusableInTouchMode="true"/>

                <android.support.design.widget.FloatingActionButton
                    android:id="@+id/button_refresh_network"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="@dimen/floating_action_button_margin"
                    android:src="@drawable/ic_fab_refresh"
                    android:contentDescription="@string/content_description_refresh"
                    app:elevation="4dp"
                    app:borderWidth="0dp"
                    app:fabSize="mini"/>
            </LinearLayout>
            <TableRow>

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="5dp"
                    android:layout_gravity="center_vertical"
                    android:id="@+id/android_network_state_image"
                    tools:src="@drawable/ic_check"
                    android:contentDescription="@string/content_description_diagnostic_status"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:layout_gravity="center_vertical"
                    android:text="@string/label_state"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:layout_gravity="center_vertical"
                    tools:text="Connected"
                    android:id="@+id/android_network_state"/>

            </TableRow>
        </TableLayout>
    </ScrollView>
</LinearLayout>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...