evrencoskun / TableView

TableView is a powerful Android library for displaying complex data structures and rendering tabular data composed of rows, columns and cells.
MIT License
3.14k stars 459 forks source link

First row header expands over all row headers #280

Closed ehsanTC closed 4 years ago

ehsanTC commented 4 years ago

Hi all

I have used version 0.8.9 on the SDK version 21. I followed the instruction on the library page step by step (so i haven't post them here again). The problem i have is, the first row header item expands over the other row headers.

Do you what is happening? (The stackoverflow question is here

evrencoskun commented 4 years ago

Hi @ehsanTC

Probably, there is something wrong with your implementation. Could you please share your codes?

ehsanTC commented 4 years ago

Of course. But let me explain the code. The table is used to show some data (user blood sugar test value) for a month. Each month has 30 days. and the day number will be the row header

This is the adapter:

public class DetailsTableAdapter extends AbstractTableAdapter<ColumnHeader, RowHeader, Cell>
    {
    Context mContext;

    public DetailsTableAdapter(Context context) {
        mContext = context;
    }

    @Override
    public int getColumnHeaderItemViewType(int position) {
        return 0;
    }

    @Override
    public int getRowHeaderItemViewType(int position) {
        return 0;
    }

    @Override
    public int getCellItemViewType(int position) {
        return 0;
    }

    @NonNull
    @Override
    public AbstractViewHolder onCreateCellViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Get cell xml layout
        View layout = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.report_table_cell, parent, false);
        return new MyCellViewHolder(layout);
    }

    @Override
    public void onBindCellViewHolder(@NonNull AbstractViewHolder holder, @Nullable Cell cellItemModel, int columnPosition, int rowPosition) {
        Cell cell = cellItemModel;

        // Get the holder to update cell item text
        MyCellViewHolder viewHolder = (MyCellViewHolder) holder;
        viewHolder.setData(cellItemModel);

        // If your TableView should have auto resize for cells & columns.
        // Then you should consider the below lines. Otherwise, you can ignore them.

        // It is necessary to remeasure itself.
        viewHolder.cell_textview.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
        viewHolder.cell_textview.getLayoutParams().height = LinearLayout.LayoutParams.MATCH_PARENT;
        viewHolder.cell_textview.requestLayout();
    }

    @NonNull
    @Override
    public AbstractViewHolder onCreateColumnHeaderViewHolder(@NonNull ViewGroup parent, int viewType) {
        // The header for the columns can be replaced by a new layout
        View layout = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.report_table_column, parent, false);

        // Create a ColumnHeader ViewHolder
        return new MyColumnHeaderViewHolder(layout);
    }

    @Override
    public void onBindColumnHeaderViewHolder(@NonNull AbstractViewHolder holder, @Nullable ColumnHeader columnHeaderItemModel, int columnPosition) {
        ColumnHeader columnHeader = columnHeaderItemModel;

        // Get the holder to update cell item text
        MyColumnHeaderViewHolder columnHeaderViewHolder = (MyColumnHeaderViewHolder) holder;
        columnHeaderViewHolder.cell_textview.setText(columnHeader.getData());

        // If your TableView should have auto resize for cells & columns.
        // Then you should consider the below lines. Otherwise, you can ignore them.

        // It is necessary to remeasure itself.
        columnHeaderViewHolder.cell_textview.getLayoutParams().width = LinearLayout
                .LayoutParams.WRAP_CONTENT;
        columnHeaderViewHolder.cell_textview.requestLayout();
    }

    @NonNull
    @Override
    public AbstractViewHolder onCreateRowHeaderViewHolder(@NonNull ViewGroup parent, int viewType) {
        View layout = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.report_table_row_header, parent, false);

        // Create a Row Header ViewHolder
        return new MyRowHeaderViewHolder(layout);
    }

    @Override
    public void onBindRowHeaderViewHolder(@NonNull AbstractViewHolder holder, @Nullable RowHeader rowHeaderItemModel, int rowPosition) {
        RowHeader rowHeader = rowHeaderItemModel;

        // Get the holder to update row header item text
        MyRowHeaderViewHolder rowHeaderViewHolder = (MyRowHeaderViewHolder) holder;
        rowHeaderViewHolder.cell_textview.setText(rowHeader.getData());

        // It is necessary to remeasure itself.
        // rowHeaderViewHolder.cell_textview.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
        // rowHeaderViewHolder.cell_textview.getLayoutParams().height = LinearLayout.LayoutParams.WRAP_CONTENT;
        // rowHeaderViewHolder.cell_textview.requestLayout();
    }

    @NonNull
    @Override
    public View onCreateCornerView(@NonNull ViewGroup parent) {
        return LayoutInflater.from(mContext).inflate(R.layout.tableview_corner_layout, null, false);
    }

    class MyCellViewHolder extends AbstractViewHolder {

        public final TextView cell_textview;
        public final TextView bs_indicator;

        public MyCellViewHolder(View itemView) {
            super(itemView);
            cell_textview = itemView.findViewById(R.id.cell_data);
            bs_indicator = itemView.findViewById(R.id.bs_value_indicator);
        }

        public void setData(Cell cell) {
            try {
                int value = Integer.valueOf(cell.getData().toString());
                BloodSugarRange range = BloodSugarRange.getRange(value);
                if (range == BloodSugarRange.Bad_High ) {
                    int color = BloodSugarColor.getColor(mContext, value);
                    // Make text bold and italic
                    SpannableString spanString = new SpannableString("H");
                    spanString.setSpan(new StyleSpan(Typeface.BOLD), 0, spanString.length(), 0);
                    spanString.setSpan(new StyleSpan(Typeface.ITALIC), 0, spanString.length(), 0);
                    bs_indicator.setText(spanString);

                    bs_indicator.setTextColor(color);
                    cell_textview.setBackgroundColor(color);
                }
                else if (range == BloodSugarRange.Bad_Low) {
                    // Make text bold and italic
                    SpannableString spanString = new SpannableString("L");
                    spanString.setSpan(new StyleSpan(Typeface.BOLD), 0, spanString.length(), 0);
                    spanString.setSpan(new StyleSpan(Typeface.ITALIC), 0, spanString.length(), 0);
                    bs_indicator.setText(spanString);

                    int color = BloodSugarColor.getColor(mContext, value);
                    bs_indicator.setTextColor(color);
                    cell_textview.setBackgroundColor(color);
                }

                cell_textview.setText(Integer.toString(value));
            } catch (Exception ex) {
                cell_textview.setText(cell.getData().toString());
            }
        }
    }
    class MyColumnHeaderViewHolder extends AbstractViewHolder {

        public final TextView cell_textview;

        public MyColumnHeaderViewHolder(View itemView) {
            super(itemView);
            cell_textview = (TextView) itemView.findViewById(R.id.cell_data);
        }
    }
    class MyRowHeaderViewHolder extends AbstractViewHolder {

        public final TextView cell_textview;

        public MyRowHeaderViewHolder(View itemView) {
            super(itemView);
            cell_textview = (TextView) itemView.findViewById(R.id.cell_data);
        }
    }
}

and i set the data by calling:



    public void setData(Map<PersianDate, List<BsLevelDataModel>> dataset) {
        // set header columns
        List<ColumnHeader> columnHeaders = new ArrayList<>();
        for (BloodSugarType type : BloodSugarType.values())
            columnHeaders.add(new ColumnHeader(ApplicationGlobals.getStringResourceByName(type.toString())));

        // set row header
        List<RowHeader> rowHeaders = new ArrayList<>();
        for (PersianDate day : dataset.keySet())
            rowHeaders.add(new RowHeader(Integer.toString(day.getDayOfMonth())));

       // set cells
        List<List<Cell>> cells = new ArrayList<>();
        for (PersianDate day : dataset.keySet()){
            // some lengthy code for filling cells
        }

    mTableAdapter.setAllItems(columnHeaders, rowHeaders, cells);
}```
evrencoskun commented 4 years ago

Hi @ehsanTC

Could you please share your layouts of your ViewHolders as well?

ehsanTC commented 4 years ago

For cell layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container">

    <TextView
        android:id="@+id/bs_value_indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="@dimen/horizontal_margin_between_views_in_row"
        android:paddingEnd="4dp"
        />

    <TextView
        android:id="@+id/cell_data"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:maxLines="10"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

For column header layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/cell_data"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textStyle="bold"
        android:textColor="@color/black"
        android:lines="1"
        android:layout_marginStart="@dimen/horizontal_margin_between_views_in_row"
        android:layout_marginEnd="@dimen/horizontal_margin_between_views_in_row"/>
</androidx.constraintlayout.widget.ConstraintLayout>

For row header layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/cell_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:textStyle="bold"
        android:textColor="@color/black"
        android:layout_marginStart="@dimen/horizontal_margin_between_views_in_row"
        android:layout_marginEnd="@dimen/horizontal_margin_between_views_in_row"/>
</androidx.constraintlayout.widget.ConstraintLayout>

And finally, for the corner layout:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="@dimen/table_view_row_header_width"
                android:layout_height="@dimen/table_view_cell_height"
                android:background="@color/unselected_header_background_color">

    <View
        android:layout_width="1px"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:background="@color/separator_color"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_alignParentBottom="true"
        android:background="@color/separator_color"/>
</RelativeLayout>```

Thanks in advanced
evrencoskun commented 4 years ago

I don't recommend you to use constraint layout in RecyclerView because of providing low performance. Besides, You need to consider layouts of the sample app,

 // It is necessary to remeasure itself.
        cell_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
        cell_textview.requestLayout();

But you got these which may cause the problem;

  viewHolder.cell_textview.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
        viewHolder.cell_textview.getLayoutParams().height = LinearLayout.LayoutParams.MATCH_PARENT;
        viewHolder.cell_textview.requestLayout();
ehsanTC commented 4 years ago

Thanks. Changing the row header layout removed the problem. The new layout is:

`<RelativeLayout android:id="@+id/root" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/unselected_header_background_color">

<LinearLayout
    android:id="@+id/row_header_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:orientation="vertical"
    android:background="@color/unselected_header_background_color">

    <TextView
        android:id="@+id/cell_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold"
        android:ellipsize="end"

        android:gravity="center"
        android:textColor="@color/black"
        android:layout_marginStart="@dimen/horizontal_margin_between_views_in_row"
        android:layout_marginEnd="@dimen/horizontal_margin_between_views_in_row"
        />

</LinearLayout>

`