Why does TextView.setText cause scrolling of an enclosing ScrollView?

I have this strange problem that happens on 1.6, 2.2 and MyTouch 3G Slide (which is API # 7 and is listed as “2.1-Update1” in the Android Device Chooser). If anyone can explain what I'm doing wrong and how to fix it (or maybe confirm that it is an Android error), I would really appreciate it!

The main idea for my application is to make a stopwatch - something like the user can press a button to start a timer, and then press it again to stop (pause) a timer; additional taps alternate between resuming the timer and pausing the timer.

I have a top-level ScrollView that contains a RelativelLayout that contains a bunch of widgets. The first widget is the HUGE button (so it's easy to press), which pushes all my other widgets below the bottom of the screen. This is intentional because I want to rely on ScrollView (and a screen reminder to the user) to make the rest of the input options available.

I have a simple state type setting, where mState is the current mode (STATE_TIMER_NOT_STARTED before the user presses any buttons, ... RUNNING after the first press, and then ... PAUSED after the second, back ... RUNNING after the third, etc. etc., etc.).

This all works great. EXCEPT that when the timer is started and the user presses the start / stop / resume button again, ScrollView will scroll down the path. I DO NOT issue this command (I don’t even have a reference to the ScrollView object), and I'm not sure why it does this.

REPRO: Compile + follow the examples below. When the application starts, click the "Start Timing" button. Use your thumb (or mouse) to touch the screen up (so you can see the RatingBar), and then drag it down (so that the button is fully on the screen again). Press the button (which now reads "PauseTiming") again and it will jump a little. He should NOT jump / scroll down, as there is no instruction (which I see) that tells her to scroll down. As far as I can tell, this is setText, which causes scrolling (when I comment on these lines, scrolling does not happen).

WHAT I ASK: If I do something dumb, and you can indicate what it is, I would really appreciate it :) :) I wonder if the “touch mode” can have something to do with it, since it’s DOES NOT happen (in the emulator) when I use the mouse scroll wheel to move the panel up (i.e. instead of a simulated finger -dragging). I can not find much in touch mode, and nothing special in focus / selection in touch mode in ScrollView

If you can confirm that this error occurs for you too, it will be good too (because poverty loves the .AHEM company, I mean, because it can help confirm that it is not only me :)).

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

UPDATE 1: Addendum

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

then setting breakpoints in the debugger confirms that the button is always in touch mode (regardless of whether I drag the panel up / down or the mouse wheel up / down). Thus, this is a combination of the fact that you are in touch-touch mode and drag the panel after pressing the second button (i.e., when the application is in the stop / pause time mode), which causes odd additional timers in subsequent pauses.

UPDATE 2: I just noticed that it scrolls to EditText, and no further. It looks like when you move the panel down, the EditText gets the selection, and after the click event, the ScrollView returns to what it has the choice. It seems to explain why the mouse-wheel approach does not have this problem (it moves the selection / focus back to the button).

+4
source share
3 answers

Old thread, but I thought I'd add this if someone would look for me like me. I had the same problem, but just cleaning the focus didn't help. This is what finally resolved this for me:

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

Hope this helps someone. TextView Documents

+3
source

Well, I dealt with what was going on and there was enough idea on how to get around this, that I thought I could also post this here as an answer:

If you call clearFocus on EditText before any call to setText (which is both a button event handler and several timers that I run through the stream handler in the "real" version of this program), then everything works as I expect (there is no strange auto-scroll )

If you want to use this solution, you will need to clear the focus for everything that the focus can get, although this makes it a lame solution - I will try to continue to look at it. ScrollView docs have a method called onRequestFocusInDescendants with the cryptic notation “When looking for children's focus as a scroll, you need to be a little more careful not to focus on something that scrolls from the screen. This is more expensive than the default ViewGroup, otherwise this behavior could be done by default. " which may indicate what is happening here ...

+2
source

I tried the solutions on this page and they did not work for me. I had a scrollview that scrolled every time I clicked the refresh button in the view. What I ended up doing is making the title that is to the left of the button focusable and setting that the element will focus on the button’s callback.

Part of my onCreateView in my snippet:

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

A simplified version of my layout:

 <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> 
0
source

Source: https://habr.com/ru/post/1313796/


All Articles