2011-12-23 51 views
4

我需要一个带有固定标题的可滚动表,所以我遵循this great blog,一切都很好。Android的onLayout()和AsyncTask()不能一起工作

这个想法是使用一个表格作为标题,一个表格用于在scrollview中添加的内容,它们都在自定义的LinearLayout中。在定制的LinearLayout中,我们将覆盖onLayout()以获取每行的最大宽度,并为标题和内容表的每一行设置宽度。

这里是活动及其布置:

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> 

主要业务

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

上述代码工作完美(expected),然而,当我使用AnysnTask从服务器获取数据并将数据添加到表中,onLayout()在我的习惯米视图不再工作。我模拟由登出了一些数量获取数据:

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

    } 

所以onLayout()时,我打电话从主UI线程appendRows(),将其置于onCreate()方法才有效。如果我从另一个UI线程(在AsyncTask的onPostExecute()中调用),调用onLayout()(我通过创建一些日志来检查它),但它不影响GUI。我试着用invalidate(),forceLayout(),requestLayout()但不改变任何东西。 wrong

我想我们需要调用一个方法来刷新GUI,但不知道它是什么,我已经在2天内搜索并尝试了很多方法,但没有任何东西,所以它会非常感激如果你可以对此有任何想法。非常感谢。

+0

没有“另一个”UI线程。 'onPostExecute'在与'onCreate'相同的线程上被调用。 – inazaruk 2011-12-23 08:14:15

+0

如果是这样,为什么只要将appendRow放入onCreate中就可以工作。 – thanhbinh84 2011-12-23 08:31:12

+0

我不知道。我没有深入查看你的代码。但是你可能想考虑这个问题而不考虑线程。 – inazaruk 2011-12-23 09:17:09

回答

1

我终于找到答案了,setColumnCollapsed()使表格布局刷新,但是我们需要把它放在另一个AsyncTask中,否则它不会工作,奇怪:(我把最新的代码放在这里,所以希望它对某人有帮助。此外,这只是解决方法,所以随时发布您的答案,如果有...

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

答案是你应该在onCreate()方法外声明你的TableLayouts并在onCreate()中实例化它们。这是解决方案。它运作良好。

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

谢谢Yury,但它不起作用,我试过你的代码,但列没有像预期的那样对齐。我添加了一些截图到我的问题,请看看 – thanhbinh84 2011-12-26 10:04:57

+0

是的,对不起。现在我明白问题所在。抱歉,不正确的答案。 – Yury 2011-12-26 13:30:27

2

你可能想看看这个答案: Android Set textview layout width dynamically

但是,基本上,尽量设置每个TextView的宽度是一样的头。

这可能需要你做所有事情两次,因为你可能需要让系统做布局,所以使用View.INVISIBLE,那么你需要退出AsyncTask,调用另一个,这样布局工作才会发生。

然后在第二个中,您可以获取不可见表格,循环查找该列中的最大宽度,然后将该列中的所有TextView设置为最大。

这不是最好的解决方案,但应该工作。

我认为你的AsyncTask之一的主要问题是布局需要完成,然后你可以进行修复。

+0

感谢James给我关于调用另一个AsyncTask的想法,但是使用setColumnCollapsed()可能会更好。无论如何,我会将此作为公认的答案给予你50个声望。 :) – thanhbinh84 2011-12-28 04:06:57