tener tabla ssrs services salto repetir pagina las grupos encabezado dinamicas dinamica debe columnas cabecera android android-layout android-gridview

android - ssrs - Crear una tabla/grilla con una columna congelada y encabezados congelados



salto de pagina en reporting services (3)

Fuera de mi cabeza, así es como me acercaría a esto:

1) Cree una interfaz con un método que su actividad implementaría para recibir coordenadas de desplazamiento y que su ScrollView pueda devolver cuando se produzca un desplazamiento:

public interface ScrollCallback { public void scrollChanged(int newXPos, int newYPos); }

2) Implemente esto en su actividad para desplazar las dos vistas de desplazamiento restringidas a la posición a la que se desplazó la vista de desplazamiento principal:

@Override public void scrollChanged(int newXPos, int newYPos) { mVerticalScrollView.scrollTo(0, newYPos); mHorizontalScrollView.scrollTo(newXPos, 0); }

3) Subclase ScrollView para anular el método onScrollChanged () y agregar un método y una variable miembro para devolver la llamada a la actividad:

private ScrollCallback mCallback; //... @Override protected void onScrollChanged (int l, int t, int oldl, int oldt) { mCallback.scrollChanged(l, t); super.onScrollChanged(l, t, oldl, oldt); } public void setScrollCallback(ScrollCallback callback) { mCallback = callback; }

4) Reemplace el stock ScrollView en su XML con su nueva clase y llame a setScrollCallback(this) en onCreate() .

Estoy trabajando en una pequeña aplicación de Android. Parte de lo que necesito para esta aplicación de Android es tener una grilla que se pueda desplazar horizontal y verticalmente. Sin embargo, la columna de la izquierda debe estar congelada (siempre en la pantalla, y no como parte del desplazamiento horizontal). Del mismo modo, la fila del encabezado superior debe estar congelada (no forma parte del desplazamiento vertical)

Esta imagen con suerte lo describirá claramente si lo anterior no tiene demasiado sentido:

Clave :

  1. Blanco: no desplazarse en absoluto
  2. Azul: desplazarse verticalmente
  3. Rojo: desplazarse horizontalmente
  4. Púrpura: desplazarse tanto vertical como horizontalmente

Hacer una de estas dimensiones es bastante fácil, y lo he hecho. Sin embargo, tengo problemas para lograr que estas dos dimensiones funcionen. (es decir, puedo hacer que la parte inferior sea toda azul, o puedo obtener la parte derecha para que sea roja, pero no del todo como se indicó anteriormente) El código que tengo está debajo, y básicamente generará lo siguiente:

result_grid.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/lightGrey"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_below="@id/summaryTableLayout" android:layout_weight="0.1" android:layout_marginBottom="50dip" android:minHeight="100dip"> <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TableLayout android:id="@+id/frozenTable" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginTop="2dip" android:layout_marginLeft="1dip" android:stretchColumns="1" /> <HorizontalScrollView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/frozenTable" android:layout_marginTop="2dip" android:layout_marginLeft="4dip" android:layout_marginRight="1dip"> <TableLayout android:id="@+id/contentTable" android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="1"/> </HorizontalScrollView> </LinearLayout> </ScrollView> </LinearLayout> <LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent" android:orientation="vertical" android:layout_weight="0.1" android:layout_alignParentBottom="true"> <Button android:id="@+id/backButton" android:layout_height="wrap_content" android:layout_width="fill_parent" android:text="Return"/> </LinearLayout> </RelativeLayout>

Código Java:

private boolean showSummaries; private TableLayout summaryTable; private TableLayout frozenTable; private TableLayout contentTable; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.result_grid); Button backButton = (Button)findViewById(R.id.backButton); frozenTable = (TableLayout)findViewById(R.id.frozenTable); contentTable = (TableLayout)findViewById(R.id.contentTable); ArrayList<String[]> content; // [Removed Code] Here I get some data from getIntent().getExtras() that will populate the content ArrayList PopulateMainTable(content); } private void PopulateMainTable(ArrayList<String[]> content) { // [Removed Code] There is some code here to style the table (so it has lines for the rows) for (int i = 0; i < content.size(); i++){ TableRow frozenRow = new TableRow(this); // [Removed Code] Styling of the row TextView frozenCell = new TextView(this); frozenCell.setText(content.get(i)[0]); // [Removed Code] Styling of the cell frozenRow.addView(frozenCell); frozenTable.addView(frozenRow); // The rest of them TableRow row = new TableRow(this); // [Renoved Code] Styling of the row for (int j = 1; j < content.get(0).length; j++) { TextView rowCell = new TextView(this); rowCell.setText(content.get(i)[j]); // [Removed Code] Styling of the cell row.addView(rowCell); } contentTable.addView(row); } }

Esto es lo que parece:

Así que esto es lo que parece con un poco de desplazamiento horizontal

Esto es lo que parece cuando se desplaza verticalmente, ¡tenga en cuenta que pierde los encabezados! ¡Esto es un problema!

¡Dos últimas cosas para notar!

En primer lugar, no puedo creer que esto no exista en algún lugar. (No tengo un Android, así que no he podido buscar aplicaciones que puedan hacer esto). Sin embargo, he buscado al menos dos días dentro de StackOverflow y en Internet en general buscando una solución para GridView o TableLayout que me proporcione lo que me gustaría hacer y aún no he encontrado una solución. Tan avergonzado como me sentiría por haberlo perdido, si alguien sabe de un recurso que describe cómo hacerlo, ¡le estaría muy agradecido!

En segundo lugar, traté de "forzar" una solución para esto, en el sentido de que agregué dos LinearLayouts, uno que capturaba la parte "Encabezado" de la cuadrícula que quiero crear, y otro para la parte inferior de "contenido" de la cuadrícula que quiero crear. Puedo publicar este código, pero esto ya es bastante largo y espero que lo que quiero decir sea obvio. Esto funcionó parcialmente, pero el problema aquí es que los encabezados y las columnas de contenido nunca se alinearon. Quería usar getWidth () y setMinimumWidth () en las TextViews dentro de las TableRows, pero como se describe aquí, esta información era inaccesible durante onCreate (y también era inaccesible dentro de onPostCreate). No he podido encontrar la manera de hacer que esto funcione, ¡y una solución en este ámbito también sería maravillosa!

Si has llegado tan lejos hasta el final, felicitaciones para ti!


Hace aproximadamente una semana revisé este problema y se me ocurrió una solución. La solución requiere que realice una gran cantidad de ajustes de ancho manual para las columnas en esta cuadrícula, y considero que es extremadamente bajo en este día y edad. Desafortunadamente, también he seguido buscando una solución más completa, nativa de la plataforma Android, pero no he inventado nada.

El siguiente es el código para crear esta misma grilla, si alguien que me sigue lo necesita. Explicaré algunos de los detalles más pertinentes a continuación.

El diseño: grid.xml :

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/lightGrey"> <TableLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_marginBottom="2dip" android:layout_weight="1" android:minHeight="100dip"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TableLayout android:id="@+id/frozenTableHeader" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginTop="2dip" android:layout_marginLeft="1dip" android:stretchColumns="1" /> <qvtcapital.mobile.controls.ObservableHorizontalScrollView android:id="@+id/contentTableHeaderHorizontalScrollView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/frozenTableHeader" android:layout_marginTop="2dip" android:layout_marginLeft="4dip" android:layout_marginRight="1dip"> <TableLayout android:id="@+id/contentTableHeader" android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="1"/> </qvtcapital.mobile.controls.ObservableHorizontalScrollView> </LinearLayout> <ScrollView android:id="@+id/verticalScrollView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TableLayout android:id="@+id/frozenTable" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginTop="2dip" android:layout_marginLeft="1dip" android:stretchColumns="1" /> <qvtcapital.mobile.controls.ObservableHorizontalScrollView android:id="@+id/contentTableHorizontalScrollView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/frozenTable" android:layout_marginTop="2dip" android:layout_marginLeft="4dip" android:layout_marginRight="1dip"> <TableLayout android:id="@+id/contentTable" android:layout_width="fill_parent" android:layout_height="wrap_content" android:stretchColumns="1"/> </qvtcapital.mobile.controls.ObservableHorizontalScrollView> </LinearLayout> </ScrollView> </TableLayout>

La actividad: Grid.java :

public class ResultGrid extends Activity implements HorizontalScrollViewListener { private TableLayout frozenHeaderTable; private TableLayout contentHeaderTable; private TableLayout frozenTable; private TableLayout contentTable; Typeface font; float fontSize; int cellWidthFactor; ObservableHorizontalScrollView headerScrollView; ObservableHorizontalScrollView contentScrollView; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.result_grid); font = Typeface.createFromAsset(getAssets(), "fonts/consola.ttf"); fontSize = 11; // Actually this is dynamic in my application, but that code is removed for clarity final float scale = getBaseContext().getResources().getDisplayMetrics().density; cellWidthFactor = (int) Math.ceil(fontSize * scale * (fontSize < 10 ? 0.9 : 0.7)); Button backButton = (Button)findViewById(R.id.backButton); frozenTable = (TableLayout)findViewById(R.id.frozenTable); contentTable = (TableLayout)findViewById(R.id.contentTable); frozenHeaderTable = (TableLayout)findViewById(R.id.frozenTableHeader); contentHeaderTable = (TableLayout)findViewById(R.id.contentTableHeader); headerScrollView = (ObservableHorizontalScrollView) findViewById(R.id.contentTableHeaderHorizontalScrollView); headerScrollView.setScrollViewListener(this); contentScrollView = (ObservableHorizontalScrollView) findViewById(R.id.contentTableHorizontalScrollView); contentScrollView.setScrollViewListener(this); contentScrollView.setHorizontalScrollBarEnabled(false); // Only show the scroll bar on the header table (so that there aren''t two) backButton.setOnClickListener(backButtonClick); InitializeInitialData(); } protected void InitializeInitialData() { ArrayList<String[]> content; Bundle myBundle = getIntent().getExtras(); try { content = (ArrayList<String[]>) myBundle.get("gridData"); } catch (Exception e) { content = new ArrayList<String[]>(); content.add(new String[] {"Error", "There was an error parsing the result data, please try again"} ); e.printStackTrace(); } PopulateMainTable(content); } protected void PopulateMainTable(ArrayList<String[]> content) { frozenTable.setBackgroundResource(R.color.tableBorder); contentTable.setBackgroundResource(R.color.tableBorder); TableLayout.LayoutParams frozenRowParams = new TableLayout.LayoutParams( TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT); frozenRowParams.setMargins(1, 1, 1, 1); frozenRowParams.weight=1; TableLayout.LayoutParams tableRowParams = new TableLayout.LayoutParams( TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT); tableRowParams.setMargins(0, 1, 1, 1); tableRowParams.weight=1; TableRow frozenTableHeaderRow=null; TableRow contentTableHeaderRow=null; int maxFrozenChars = 0; int[] maxContentChars = new int[content.get(0).length-1]; for (int i = 0; i < content.size(); i++){ TableRow frozenRow = new TableRow(this); frozenRow.setLayoutParams(frozenRowParams); frozenRow.setBackgroundResource(R.color.tableRows); TextView frozenCell = new TextView(this); frozenCell.setText(content.get(i)[0]); frozenCell.setTextColor(Color.parseColor("#FF000000")); frozenCell.setPadding(5, 0, 5, 0); if (0 == i) { frozenCell.setTypeface(font, Typeface.BOLD); } else { frozenCell.setTypeface(font, Typeface.NORMAL); } frozenCell.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize); frozenRow.addView(frozenCell); if (content.get(i)[0].length() > maxFrozenChars) { maxFrozenChars = content.get(i)[0].length(); } // The rest of them TableRow row = new TableRow(this); row.setLayoutParams(tableRowParams); row.setBackgroundResource(R.color.tableRows); for (int j = 1; j < content.get(0).length; j++) { TextView rowCell = new TextView(this); rowCell.setText(content.get(i)[j]); rowCell.setPadding(10, 0, 0, 0); rowCell.setGravity(Gravity.RIGHT); rowCell.setTextColor(Color.parseColor("#FF000000")); if ( 0 == i) { rowCell.setTypeface(font, Typeface.BOLD); } else { rowCell.setTypeface(font, Typeface.NORMAL); } rowCell.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize); row.addView(rowCell); if (content.get(i)[j].length() > maxContentChars[j-1]) { maxContentChars[j-1] = content.get(i)[j].length(); } } if (i==0) { frozenTableHeaderRow=frozenRow; contentTableHeaderRow=row; frozenHeaderTable.addView(frozenRow); contentHeaderTable.addView(row); } else { frozenTable.addView(frozenRow); contentTable.addView(row); } } setChildTextViewWidths(frozenTableHeaderRow, new int[]{maxFrozenChars}); setChildTextViewWidths(contentTableHeaderRow, maxContentChars); for (int i = 0; i < contentTable.getChildCount(); i++) { TableRow frozenRow = (TableRow) frozenTable.getChildAt(i); setChildTextViewWidths(frozenRow, new int[]{maxFrozenChars}); TableRow row = (TableRow) contentTable.getChildAt(i); setChildTextViewWidths(row, maxContentChars); } } private void setChildTextViewWidths(TableRow row, int[] widths) { if (null==row) { return; } for (int i = 0; i < row.getChildCount(); i++) { TextView cell = (TextView) row.getChildAt(i); int replacementWidth = widths[i] == 1 ? (int) Math.ceil(widths[i] * cellWidthFactor * 2) : widths[i] < 3 ? (int) Math.ceil(widths[i] * cellWidthFactor * 1.7) : widths[i] < 5 ? (int) Math.ceil(widths[i] * cellWidthFactor * 1.2) :widths[i] * cellWidthFactor; cell.setMinimumWidth(replacementWidth); cell.setMaxWidth(replacementWidth); } } public void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY) { if (scrollView==headerScrollView) { contentScrollView.scrollTo(x, y); } else if (scrollView==contentScrollView) { headerScrollView.scrollTo(x, y); } }

El oyente de la vista de desplazamiento (para unir los dos): HorizontalScrollViewListener.java :

public interface HorizontalScrollViewListener { void onScrollChanged(ObservableHorizontalScrollView scrollView, int x, int y, int oldX, int oldY); }

La clase ScrollView que implementa este oyente: ObservableHorizontalScrollView.java :

public class ObservableHorizontalScrollView extends HorizontalScrollView { private HorizontalScrollViewListener scrollViewListener=null; public ObservableHorizontalScrollView(Context context) { super(context); } public ObservableHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ObservableHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public void setScrollViewListener(HorizontalScrollViewListener scrollViewListener) { this.scrollViewListener = scrollViewListener; } @Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y, oldX, oldY); if (null!=scrollViewListener) { scrollViewListener.onScrollChanged(this, x, y, oldX, oldY); } } }

La parte realmente importante de esto es una especie de triple:

  1. El ObservableHorizontalScrollView permite que la tabla de encabezado y la tabla de contenido se desplacen sincronizados. Básicamente, esto proporciona todo el movimiento horizontal para la grilla.
  2. La forma en que permanecen alineados es mediante la detección de la cadena más grande que estará en una columna. Esto se hace al final de PopulateMainTable() . Mientras examinamos cada una de las TextViews y las agregamos a las filas, observará que hay dos matrices maxFrozenChars y maxContentChars que hacen un seguimiento de cuál es el valor de cadena más grande que hemos visto. Al final de PopulateMainTable() recorremos cada una de las filas y para cada una de las celdas establecemos su ancho mínimo y máximo en función de la cadena más grande que vimos en esa columna. Esto es manejado por setChildTextViewWidths .
  3. El último elemento que hace que esto funcione es utilizar una fuente monoespaciada. Notarás que en onCreate estoy cargando una fuente consola.ttf y luego aplicándola a cada una de las vistas de texto de la cuadrícula que actúan como las celdas de la grilla. Esto nos permite estar razonablemente seguros de que el texto no se volverá más grande de lo que hemos establecido el ancho mínimo y máximo en el paso anterior. Estoy haciendo un poco de fantasía aquí, con todo el cellWidthFactor y el tamaño máximo de esa columna. Esto es realmente para que las cadenas más pequeñas se ajusten con seguridad, mientras que podemos minimizar el espacio en blanco para cadenas más grandes que (para mi sistema) no van a ser todas letras mayúsculas. Si te encontraste en problemas para usar esto y obtuviste cadenas que no encajaban en el tamaño de columna que configuraste, aquí es donde te gustaría editar las cosas. ¡Desea cambiar la variable replacementWidth con alguna otra fórmula para determinar el ancho de la celda, como 50 * widths[i] que sería bastante grande! Pero te dejaría con una buena cantidad de espacios en blanco en algunas columnas. Básicamente, dependiendo de lo que planeas poner en tu grilla, esto puede necesitar ser retocado. Arriba es lo que funcionó para mí.

¡Espero que esto ayude a alguien más en el futuro!