2011-12-23 1 views
4

J'ai besoin d'une table déroulante avec en-tête fixe, donc j'ai suivi this great blog et tout va bien.Android onLayout() et AsyncTask() ne fonctionnent pas ensemble

L'idée est d'utiliser une table pour l'en-tête, une table pour le contenu ajouté dans scrollview, les deux sont dans un LinearLayout personnalisé. Dans LinearLayout personnalisé, nous remplacerons le onLayout() pour obtenir la largeur maximale de chaque ligne et définir la largeur pour chaque ligne de l'en-tête et de la table de contenu.

est ici l'activité et sa mise en page:

package com.stylingandroid.ScrollingTable; 

import android.content.Context; 
import android.util.AttributeSet; 
import android.view.View; 
import android.widget.LinearLayout; 
import android.widget.TableLayout; 
import android.widget.TableRow; 

public class ScrollingTable extends LinearLayout 
{ 
    public ScrollingTable(Context context) 
    { 
     super(context); 
    } 
public ScrollingTable(Context context, AttributeSet attrs) 
{ 
    super(context, attrs); 
} 

@Override 
protected void onLayout(boolean changed, int l, int t, int r, int b) 
{ 
    super.onLayout(changed, l, t, r, b); 

    TableLayout header = (TableLayout) findViewById(R.id.HeaderTable); 
    TableLayout body = (TableLayout) findViewById(R.id.BodyTable); 

    if (body.getChildCount() > 0) { 
     TableRow bodyRow = (TableRow) body.getChildAt(0); 
     TableRow headerRow = (TableRow) header.getChildAt(0); 

     for (int cellnum = 0; cellnum < bodyRow.getChildCount(); cellnum++){ 
      View bodyCell = bodyRow.getChildAt(cellnum); 
      View headerCell = headerRow.getChildAt(cellnum); 
      int bodyWidth = bodyCell.getWidth(); 
      int headerWidth = headerCell.getWidth(); 
      int max = Math.max(bodyWidth, headerWidth); 
      TableRow.LayoutParams bodyParams = (TableRow.LayoutParams)bodyCell.getLayoutParams(); 
      bodyParams.width = max; 
      TableRow.LayoutParams headerParams = (TableRow.LayoutParams)headerCell.getLayoutParams(); 
      headerParams.width = max; 
     }  
    } 
} 
} 

main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 

    <com.stylingandroid.ScrollingTable.ScrollingTable 
     android:layout_width="match_parent" 
     android:orientation="vertical" 
     android:layout_height="match_parent"> 

     <TableLayout 
      android:layout_height="wrap_content" 
      android:layout_width="match_parent" 
      android:id="@+id/HeaderTable"> 
     </TableLayout> 

     <ScrollView 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content"> 

      <TableLayout 
       android:layout_height="wrap_content" 
       android:layout_width="match_parent" 
       android:id="@+id/BodyTable"> 
      </TableLayout> 

     </ScrollView> 

    </com.stylingandroid.ScrollingTable.ScrollingTable> 

</LinearLayout> 

Activité principale

package com.stylingandroid.ScrollingTable; 

import android.app.Activity; 
import android.app.ProgressDialog; 
import android.graphics.Color; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.widget.TableLayout; 
import android.widget.TableRow; 

    import android.widget.TextView; 

    public class ScrollingTableActivity extends Activity 
    { 
     private String[][] tableData = { 
       {"header11111111111", "header2","header3","header4"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 


    {"column1", "column1", 

"column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"}, 
       {"column1", "column1","column1","column1"} 
     }; 
     /** Called when the activity is first created. */ 
     @Override 
     public void onCreate(Bundle savedInstanceState) 
     { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.main); 
      TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable); 
      TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable); 

     appendRows(tableHeader, tableBody, tableData); 
} 

private void appendRows(TableLayout tableHeader ,TableLayout tableContent, String[][] amortization) { 
    int rowSize=amortization.length; 
    int colSize=(amortization.length > 0)?amortization[0].length:0; 
    for(int i=0; i<rowSize; i++) { 
     TableRow row1 = new TableRow(this); 

     for(int j=0; j<colSize; j++) { 
      TextView c = new TextView(this); 
      c.setText(amortization[i][j]); 
      c.setPadding(3, 3, 3, 3); 
      if (i == 0) { 
       c.setTextColor(Color.BLACK); 
      } 
      row1.addView(c); 
     } 

     if (i == 0) { 
      row1.setBackgroundColor(Color.LTGRAY); 
      tableHeader.addView(row1, new TableLayout.LayoutParams()); 
     } else { 
      tableContent.addView(row1, new TableLayout.LayoutParams()); 
     } 
    } 
} 

Cependant, le travail de code ci-dessus parfaitement (expected), lorsque J'utilise AnysnTask pour obtenir des données du serveur et ajouter des données à la table plus tard, le onLayout() dans mon custo m vue ne fonctionne plus. Je Simuler l'obtention de données par vous déconnecter un certain nombre:

public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     new MyTask().execute(); 
    } 

    private class MyTask extends AsyncTask<Void, Void, Void> { 

     private ProgressDialog progressDialog; 
     protected void onPreExecute() { 
       progressDialog = ProgressDialog.show(ScrollingTableActivity.this, 
            "", "Loading. Please wait...", true); 
     } 
     @Override 
     protected Void doInBackground(Void... reportTypes) { 
      for (int i = 0; i < 500; i++) { 
       System.out.println(i); 
      } 
      return null; 
     } 
     @Override 
     protected void onPostExecute(Void result) { 
      progressDialog.dismiss(); 
      TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable); 
      TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable); 

      appendRows(tableHeader, tableBody, tableData); 
     } 

    } 

Ainsi, le OnLayout() ne fonctionnent que quand je l'appelle (appendRows) de thread principal de l'interface utilisateur en le mettant dans la méthode onCreate(). Si j'appelle d'un autre thread UI (dans onPostExecute() de AsyncTask), onLayout() est appelé (je l'ai vérifié en créant des logs) mais cela n'affecte pas l'interface graphique. J'ai essayé avec invalidate(), forceLayout(), requestLayout() mais ne change rien. wrong

Je pense que nous avons besoin d'appeler une méthode pour rafraîchir l'interface graphique mais je ne sais pas ce que c'est, j'ai cherché et essayé beaucoup de façons en 2 jours mais je n'ai rien, donc ce sera très apprécié vous pouvez donner une idée à ce sujet. Merci beaucoup.

+0

Il n'y a pas d'autre "thread" d'interface utilisateur. Le 'onPostExecute' est appelé sur le même thread que' onCreate'. – inazaruk

+0

Si c'est le cas, pourquoi cela fonctionne-t-il quand je mets l'appendRow dans onCreate. – thanhbinh84

+0

Je ne sais pas. Je n'ai pas regardé votre code en profondeur. Mais vous voudrez peut-être penser au problème sans tenir compte des discussions. – inazaruk

Répondre

1

Je trouve enfin la réponse, le setColumnCollapsed() rend la mise à jour de la table, mais nous devons la mettre dans une autre AsyncTask, sinon cela ne fonctionnera pas, étrange :(.Je mets ici le dernier code, donc espoir C'est utile pour quelqu'un, d'ailleurs, c'est juste une solution de contournement, n'hésitez pas à poster votre réponse s'il y a lieu ...

private class MyTask extends AsyncTask<Void, Void, Void> { 

    private ProgressDialog progressDialog; 
    protected void onPreExecute() { 
      progressDialog = ProgressDialog.show(ScrollingTableActivity.this, 
           "", "Loading. Please wait...", true); 
    } 
    @Override 
    protected Void doInBackground(Void... reportTypes) { 
     for (int i = 0; i < 500; i++) { 
      System.out.println(i); 
     } 
     return null; 
    } 
    @Override 
    protected void onPostExecute(Void result) { 
     progressDialog.dismiss(); 
     appendRows(tableHeader, tableBody, tableData); 

     new My1Task().execute(); 
    } 
} 

private class My1Task extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected Void doInBackground(Void... reportTypes) { 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     tableHeader.setColumnCollapsed(0, false); 
     tableBody.setColumnCollapsed(0, false); 
    } 
} 
0

La réponse est que vous devez déclarer votre TableLayouts hors de la méthode onCreate() et les instancier dans onCreate(). Voici la solution. Ça marche bien.

public class ScrollingTableActivity extends Activity { 
    TableLayout tableHeader; 
    TableLayout tableBody; 

    private String[][] tableData = { 
      { "header11111111111", "header2", "header3", "header4" }, 
      { "column1", "column1", "column1", "column1" }, 
      { "column1", "column1", "column1", "column1" }, 
      { "column1", "column1", "column1", "column1" }, 
      { "column1", "column1", "column1", "column1" } }; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     tableHeader = (TableLayout) findViewById(R.id.HeaderTable); 
     tableBody = (TableLayout) findViewById(R.id.BodyTable); 
     Log.d("ScrollingTable", "Before appendRows"); 
     //appendRows(tableHeader, tableBody, tableData); 
     new MyTask().execute(); 
    } 

    private void appendRows(TableLayout tableHeader, TableLayout tableContent, 
      String[][] amortization) { 
     int rowSize = amortization.length; 
     int colSize = (amortization.length > 0) ? amortization[0].length : 0; 
     for (int i = 0; i < rowSize; i++) { 
      TableRow row1 = new TableRow(this); 

      for (int j = 0; j < colSize; j++) { 
       TextView c = new TextView(this); 
       c.setText(amortization[i][j]); 
       c.setPadding(3, 3, 3, 3); 
       if (i == 0) { 
        c.setTextColor(Color.BLACK); 
       } 
       row1.addView(c); 
      } 

      if (i == 0) { 
       row1.setBackgroundColor(Color.LTGRAY); 
       tableHeader.addView(row1, new TableLayout.LayoutParams()); 
      } else { 
       tableContent.addView(row1, new TableLayout.LayoutParams()); 
      } 
     } 
    } 


    private class MyTask extends AsyncTask<Void, Void, Void> { 

     private ProgressDialog progressDialog; 
     protected void onPreExecute() { 
       progressDialog = ProgressDialog.show(ScrollingTableActivity.this, 
            "", "Loading. Please wait...", true); 
     } 
     @Override 
     protected Void doInBackground(Void... reportTypes) { 
      for (int i = 0; i < 500; i++) { 
       System.out.println(i); 
      } 
      return null; 
     } 
     @Override 
     protected void onPostExecute(Void result) { 
      progressDialog.dismiss(); 
      TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable); 
      TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable); 

      appendRows(tableHeader, tableBody, tableData); 
     } 
    } 
} 
+0

Merci Yury, mais ça ne marche pas, j'ai essayé votre code mais les colonnes ne sont pas alignées comme prévu. J'ai ajouté une capture d'écran dans ma question, s'il vous plaît jeter un oeil – thanhbinh84

+0

Oui, désolé. Maintenant, je comprends où est le problème. Désolé pour la réponse incorrecte. – Yury

2

Vous pouvez regarder cette réponse: Android Set textview layout width dynamically

mais, au fond, essayez de régler la largeur de chaque TextView être le même que l'en-tête.

Cela peut nécessiter que vous fassiez tout deux fois, vous devrez probablement laisser le système faire la mise en page, utilisez View.INVISIBLE, puis vous devrez quitter l'AsyncTask, en appelant un autre, afin que le travail de mise en page puisse avoir lieu. Ensuite, dans la seconde, vous pouvez obtenir les tables invisibles, faire une boucle pour trouver la largeur la plus grande dans cette colonne, puis définir tous les TextViews dans cette colonne au plus grand.

Ce n'est pas la meilleure solution, mais devrait fonctionner.

Je pense que votre problème principal dans le cas d'AsyncTask est que la mise en page doit être faite, alors vous pouvez faire la réparation.

+0

Merci James de m'avoir donné l'idée d'appeler un autre AsyncTask, mais utiliser setColumnCollapsed() peut être meilleur. Quoi qu'il en soit, je vais faire de cette réponse comme acceptée pour donner 50 réputation pour vous. :) – thanhbinh84

Questions connexes