2010-06-24 9 views
4

J'ai ce problème étrange qui se passe sur 1.6, 2.2, et une diapositive 3G MyTouch (qui est API # 7, et répertorié comme "2.1-Update1" dans le sélecteur de périphérique Android). Si quelqu'un peut expliquer ce que je fais mal & comment y remédier (ou peut-être confirmer qu'il s'agit d'un bug Android), je l'apprécierais grandement!Pourquoi TextView.setText provoque-t-il le défilement de ScrollView?

L'idée de base pour mon application est de faire un chronomètre-sorte de chose, en ce que l'utilisateur peut appuyer sur un bouton pour démarrer une minuterie, puis appuyez à nouveau pour arrêter (pause) la minuterie; d'autres tapotements alternent entre la reprise de la minuterie et la pause de la minuterie.

J'ai un ScrollView de haut niveau qui contient un RelativelLayout, qui contient un tas de widgets. Le premier widget est un bouton ÉNORME (de sorte qu'il est facile d'appuyer), ce qui pousse tous mes autres widgets au bas de l'écran. C'est intentionnel, car je veux me fier au ScrollView (et à un rappel à l'écran pour l'utilisateur) pour rendre le reste des options de saisie disponibles.

J'ai une configuration de type machine-état simple, où mState est le mode courant (STATE_TIMER_NOT_STARTED avant que l'utilisateur appuie sur des boutons, ... FONCTIONNANT après le premier appui, puis ... PAUSED après le second, retour à ... COURANT après le troisième, etc, etc). Tout cela fonctionne très bien, sauf que lorsque la minuterie est en marche et que l'utilisateur appuie de nouveau sur le bouton marche/arrêt/reprise, le ScrollView défile vers le bas. Je n'émets PAS cette commande (je n'ai même pas de référence à l'objet ScrollView), et je ne sais pas pourquoi c'est ce qu'il fait.

REPRO: Compilez + exécutez les exemples ci-dessous. Lorsque l'application démarre, appuyez sur le bouton 'Start Timing'. Utilisez votre pouce (ou la souris) pour faire glisser l'écran vers le haut (de sorte que vous pouvez voir la RatingBar), puis faites-le glisser vers le bas (de sorte que le bouton est à nouveau complètement à l'écran). Appuyez à nouveau sur le bouton (qui affiche maintenant «PauseTiming»), et il va sauter un peu. Il ne devrait PAS sauter/défiler vers le bas, car il n'y a pas de déclaration (que je peux voir) qui lui dit de faire défiler vers le bas. Aussi près que je peux dire, c'est le setText qui provoque le défilement (quand je commente ces lignes, aucun défilement ne se produit). CE QUE JE DEMANDE POUR: Si je fais quelque chose de stupide & vous pourriez préciser ce que c'est, je l'apprécierais vraiment! :) *** Je me demande si le 'mode tactile' pourrait avoir quelque chose à voir avec cela, car il ne semble pas arriver (dans l'émulateur) quand j'utilise la molette de la souris pour déplacer le panneau vers le haut (ie, le doigt-traînant simulé). Je ne peux pas trouver beaucoup sur le mode tactile, et rien de spécifique sur le focus/sélection en mode tactile dans un ScrollView

Si vous pouvez confirmer que cette erreur se produit pour vous aussi, ce serait bien aussi (depuis la misère aime la compagnie AHEM Je veux dire, car cela pourrait aider à confirmer que ce n'est pas seulement moi :)).

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> 

An droidManifest.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> 

MISE À JOUR 1: Ajout

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

ensuite le réglage des points d'arrêt dans le débogueur confirme que le bouton est toujours en mode tactile (indépendamment du fait que le doigt glisser I le panneau vers le haut/bas ou rouler la souris vers le haut/bas). C'est donc une combinaison d'être en mode tactile ET de faire glisser le doigt après le 2ème appui sur le bouton (c'est-à-dire lorsque l'application est en mode 'arrêt/pause') qui provoque le temps supplémentaire impair dans les pauses suivantes.

MISE À JOUR 2: Je viens de remarquer qu'il fait défiler jusqu'à EditText, et pas plus loin. Il semble que lorsque vous déplacez le panneau vers le bas, EditText obtient la sélection, et après l'événement click, ScrollView revient à la chose qui a la sélection. Semble expliquer pourquoi l'approche de la molette de la souris n'a pas ce problème (il déplace la sélection/focus vers le bouton).

+0

http://stackoverflow.com/questions/5375838/scrollview-disable-focus-move/7114179 # 7114179 – yanchenko

Répondre

3

Ancien fil, mais j'ai pensé que je l'ajouterais au cas où quelqu'un chercherait comme moi. J'ai eu le même problème, mais le fait d'effacer la mise au point n'a pas aidé. C'est ce que finalement résolu pour moi:

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

Espérons que cela aide quelqu'un. TextView docs

2

Ok, j'ai poignée sur ce qui se passe, et assez d'une idée de la façon de travailler autour d'elle que je pensais que je pourrais aussi bien poster cela ici, comme une réponse:

Si vous appelez clearfocus sur le EditText avant tout appel à setText (qui est à la fois le gestionnaire d'événement de bouton, et un couple de minuteurs que je cours via le gestionnaire de threads dans la «vraie» version de ce programme), alors tout fonctionne comme je l'espère (pas bizarre défilement automatique). Si vous vouliez utiliser cette solution, vous devriez vous concentrer sur tout ce qui pourrait attirer l'attention, ce qui en fait une solution boiteuse - j'essaierai de continuer à regarder cela. Sous les docs ScrollView il y a une méthode nommée onRequestFocusInDescendants avec la note énigmatique "Lorsque vous cherchez le focus chez les enfants d'une vue de défilement, vous devez être un peu plus prudent pour ne pas vous concentrer sur quelque chose qui défile hors de l'écran. l'implémentation par défaut de ViewGroup, sinon ce comportement pourrait avoir été fait par défaut. " ce qui peut pointer vers ce qui se passe ici ...

+0

Merci, j'ai juste eu ce problème et l'ai résolu en effaçant le focus ce qui était correct dans ma situation - merci d'avoir posté la réponse à votre propre question. –

0

J'ai essayé des solutions sur cette page et elles n'ont pas fonctionné pour moi. J'avais un scrollview qui défilait chaque fois que je cliquais sur un bouton d'actualisation dans la vue. Ce que j'ai fini par faire était de faire un titre qui est juste à la gauche du bouton focalisable et de mettre cet objet à focaliser dans le rappel de mon bouton.

Une partie de mon onCreateView dans mon Fragment:

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

Version simplifiée de ma mise en page:

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