Just Simple Info

Pages

Android Scrolling Table with Fixed Header Column, Fixed Row , Header Spans and Pagination

Hello coders, I will share another android code.

Sometimes programmer need to customize the layout of application they are developing.
Like what I have experienced a couple month in developing android application.

I need to develop android table with fixed header column and fixed row.
Android has Table kind of element but it just a table like in Html, no fixed header and row.
Search... search... search and search, but there is nothing such table with fixed header column and fixed row.

I figured out that, that I have to do it by my self.


Watch the actual result.



Then, below is the drawing that I started up.
Android table with fixed header and column.

and here is the result.

Android table with fixed header column, single and double row header and fixed row.

And now here are the codes.

1. MainActivity.java


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      
      Table table = new Table(this);
       
       setContentView(table);
    }


   
}

Nothing special in this code. It is just a simple activity which set our Table as contentView.
By the way, the Table class is not the android table. That table is our own created.

2. Table.java


public class Table extends LinearLayout {

   
 public static final String PREVIOUS_ARROW = "\u2190";
 public static final String NEXT_ARROW = "\u2192";
 public static final  int HEADER_BACKROUND_COLOR = Color.parseColor("#339999");
 public static final  int BODY_BACKROUND_COLOR = Color.parseColor("#99cccc");
 public static String LEFT_BODY_SCROLLVIEW_TAG = "LEFT_BODY_SCROLLVIEW_TAG";
 public static String RIGHT_BODY_SCROLLVIEW_TAG = "RIGHT_BODY_SCROLLVIEW_TAG";
 /**
  * @IS_TWO_COLUMN_HEADER = set this to true if you want two column header with span.
  */
 public static final  boolean IS_TWO_COLUMN_HEADER = true;
 
 LinkedHashMap<Object, Object[]> leftHeaders = new LinkedHashMap<Object, Object[]>();
 LinkedHashMap<Object, Object[]> rightHeaders = new LinkedHashMap<Object, Object[]>();
 
 BodyTable rightTable;
 BodyTable leftTable;
 /**
  * @leftHeaderChildrenWidht = value will be set on adjust header width to match in screen width
  */
 Integer[] leftHeaderChildrenWidth ;
 /**
  * rightHeaderChildrenWidht = value will be set on adjust header width to match in screen width
  */
 Integer[] rightHeaderChildrenWidht ;
 
 
 LoadingDialog loadingDialog;
 
 public Table(Context context) {
  super(context);
  
  this.headers();
  this.properties();
  this.init();
  
  this.resizeFirstLvlHeaderHeight();
  this.resizeSecondLvlHeaderHeight();
  this.resizeHeaderSecondLvlWidhtToMatchInScreen();
  
  this.leftTable.setHeaderChildrenWidth(this.leftHeaderChildrenWidth);
  this.rightTable.setHeaderChildrenWidth(this.rightHeaderChildrenWidht);
  
  
  this.createTestData();
  this.loadData();
  
  
 }
 
 public final static String NAME = "Name";
 public final static String GENDER = "Gender";
 public final static String TICKET_SET_SEQUENCE = "Set Sequence";
 public final static String TICKET_NUMBER = "Ticket Number";
 public final static String TICKET_VALID_UNTIL = "    Valid Until    ";
 public final static String COUNTRY_FROM = "  Country From  ";
 public final static String COUNTRY_TO = "  Country To  ";
 public void headers(){
  leftHeaders.put("Passenger Info", new String[]{NAME,GENDER});
  rightHeaders.put("Ticket Info", new String[]{TICKET_VALID_UNTIL,TICKET_NUMBER,TICKET_SET_SEQUENCE});
  rightHeaders.put("Country Info", new String[]{COUNTRY_FROM,COUNTRY_TO});
  
 }
 

 List<Passenger> testData = new ArrayList<Table.Passenger>();
 List<Passenger> dataToBeLoad = new ArrayList<Table.Passenger>();
 int pagination = 20;
 int totalPage = 0;
 int pageNumber = 1;
 
 public void loadData() {
  
  
  
  // TODO Auto-generated method stub
  this.dataToBeLoad = this.getDataToBeLoad();
  
  leftTable.loadData(dataToBeLoad);
  rightTable.loadData(dataToBeLoad);
  
  
  this.resizeBodyChildrenHeight();
  
 }
 
 private void createTestData(){
  for(int x = 0 ; x < 102; x++){
   Passenger passenger = new Passenger();
   passenger.name = "Passenger "+x;
   passenger.gender = x%2 == 0 ? 'F':'M';
   passenger.ticketNum = x;
   passenger.setSequence = "Set "+x;
   passenger.validUntil = "May 01, 2015";
   passenger.countryFrom = "Country "+x;
   passenger.countryTo = x%2 == 0 ? "Philippines" :"Country "+x;
   
   testData.add(passenger);
  }
  
  this.totalPage = this.totalPage(testData, pagination);
  /*this.dataToBeLoad = this.getDataToBeLoad();*/
 }
 private List<Passenger> getDataToBeLoad(){
  List<Passenger> passengers = new ArrayList<Table.Passenger>();
  int startingIndex = (pageNumber -1) * pagination;
  
  int totalPassenger = testData.size();
  //dataToBeLoad.clear();
  
  for(int x = 0 ; x < pagination ; x++){
   
   int index = startingIndex + x;
   
   if(index < totalPassenger){
    
    passengers.add(testData.get(index));
    
   }else{
    Log.e("no data","no data");
   }
   
  }
  
  
  
  return passengers;
 }
 private int totalPage(List<Passenger> testData,int pagination){
  
  int totalPage = testData.size() / pagination;
  totalPage = totalPage + (testData.size() % 20 == 0 ? 0 : 1);
  
  return totalPage;
  
 }
 private void properties(){ 
  this.setBackgroundColor(Color.WHITE);
  this.setOrientation(LinearLayout.HORIZONTAL);
 }
 
 private void init(){
  
  this.loadingDialog = new LoadingDialog(this.getContext());
  this.rightTable = new BodyTable(this.getContext(),this, rightHeaders, RIGHT_BODY_SCROLLVIEW_TAG);
  this.leftTable = new BodyTable(this.getContext(),this,leftHeaders, LEFT_BODY_SCROLLVIEW_TAG);
  
  
  
  this.addView(this.leftTable);
  this.addView(this.rightTable);
 }
 private void resizeFirstLvlHeaderHeight(){
  int rightHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
  
  int rightHeaderFirstLvlHeighestHeight = 0;
  int rightHeaderFirstLvlHighestHeightIndex = 0;
  
  for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
   
   HeaderRow row = (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
   
   int height = ViewSizeUtils.getViewHeight(row.firtLvlLinearLayout);
   
   if(rightHeaderFirstLvlHeighestHeight  <= height){
    
    rightHeaderFirstLvlHeighestHeight = height;
    rightHeaderFirstLvlHighestHeightIndex = x;
   }
  }
  
  int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
  
  int leftHeaderFirstLvlHeighestHeight = 0;
  int leftHeaderFirstLvlHighestHeightIndex = 0;
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
   
   HeaderRow row = (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
   
   int height = ViewSizeUtils.getViewHeight(row.firtLvlLinearLayout);
   
   if(leftHeaderFirstLvlHeighestHeight  <= height){
    
    leftHeaderFirstLvlHeighestHeight = height;
    leftHeaderFirstLvlHighestHeightIndex = x;
   }
  }
  
  boolean isHighestHighInLeft = false;
  
 
  
  if(leftHeaderFirstLvlHeighestHeight < rightHeaderFirstLvlHeighestHeight){
   // apply right header height in left and right except for the index in highest height
   
   isHighestHighInLeft = false;
   
   
  }else{
   
   isHighestHighInLeft = true;
   
  }
  
  for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
   
   LinearLayout firstLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).firtLvlLinearLayout;
   
   
   if(isHighestHighInLeft){
    
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
    params.weight = 1;
    
    firstLvlLinearLayout.setLayoutParams(params);
    
   }else{
    
    if(rightHeaderFirstLvlHeighestHeight  != rightHeaderFirstLvlHighestHeightIndex){
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
     params.weight = 1;
     
     firstLvlLinearLayout.setLayoutParams(params);
       
    }
    
   }
   
   
  }
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
   
   LinearLayout firstLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).firtLvlLinearLayout;
   
   
   if(isHighestHighInLeft){
    
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
    params.weight = 1;
    
    firstLvlLinearLayout.setLayoutParams(params);
    
   }else{
    
    if(leftHeaderFirstLvlHeighestHeight  != leftHeaderFirstLvlHighestHeightIndex){
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
     params.weight = 1;
     
     firstLvlLinearLayout.setLayoutParams(params);
       
    }
    
   }
   
   
  }
  
 }
 
 private void resizeSecondLvlHeaderHeight(){
  int rightHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
  
  int rightHeaderFirstLvlHeighestHeight = 0;
  int rightHeaderFirstLvlHighestHeightIndex = 0;
  
  for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
   
   HeaderRow row = (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
   
   int height = ViewSizeUtils.getViewHeight(row.secondLvlLinearLayout);
   
   if(rightHeaderFirstLvlHeighestHeight  <= height){
    
    rightHeaderFirstLvlHeighestHeight = height;
    rightHeaderFirstLvlHighestHeightIndex = x;
   }
  }
  
  int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
  
  int leftHeaderFirstLvlHeighestHeight = 0;
  int leftHeaderFirstLvlHighestHeightIndex = 0;
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
   
   HeaderRow row = (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
   
   int height = ViewSizeUtils.getViewHeight(row.secondLvlLinearLayout);
   
   if(leftHeaderFirstLvlHeighestHeight  <= height){
    
    leftHeaderFirstLvlHeighestHeight = height;
    leftHeaderFirstLvlHighestHeightIndex = x;
   }
  }
  
  boolean isHighestHighInLeft = false;
  
 
  
  if(leftHeaderFirstLvlHeighestHeight < rightHeaderFirstLvlHeighestHeight){
   // apply right header height in left and right except for the index in highest height
   
   isHighestHighInLeft = false;
   
   
  }else{
   
   isHighestHighInLeft = true;
   
  }
  
  
  for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
   
   LinearLayout secondLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
   
   
   if(isHighestHighInLeft){
    
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
    params.weight = 1;
    
    secondLvlLinearLayout.setLayoutParams(params);
    
   }else{
    
    if(rightHeaderFirstLvlHeighestHeight  != rightHeaderFirstLvlHighestHeightIndex){
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
     params.weight = 1;
     
     secondLvlLinearLayout.setLayoutParams(params);
       
    }
    
   }
   
   
  }
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
   
   LinearLayout secondLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
   
   
   if(isHighestHighInLeft){
    
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
    params.weight = 1;
    
    secondLvlLinearLayout.setLayoutParams(params);
    
   }else{
    
    if(leftHeaderFirstLvlHeighestHeight  != leftHeaderFirstLvlHighestHeightIndex){
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
     params.weight = 1;
     
     secondLvlLinearLayout.setLayoutParams(params);
       
    }
    
   }
   
   
  }
  
 }
 
 private void resizeHeaderSecondLvlWidhtToMatchInScreen(){
  int screenWidth = ScreenUtils.getScreenWidth(this.getContext());
  int leftHeaderChildrenTotalWidth = this.leftSecondLvlHeaderChildrenTotalWidth();
  int rightHeaderChildrenTotalWidth = this.rightHeaderChildrenTotalWidth();
  int leftHeaderSecondLvlChildrenCount = this.leftSecondLvlHeaderChildrenCount();
  int rightHeaderSecondLvlChildrenCount = this.rightSecondLvlHeaderChildrenCount();
  float availableWidth = screenWidth - (leftHeaderChildrenTotalWidth + rightHeaderChildrenTotalWidth);
  
  if(availableWidth <=0){
   // set the header width
   this.leftHeaderChildrenWidth = this.getLeftHeaderChildrenWidth();
   this.rightHeaderChildrenWidht = this.getRightHeaderChildrenWidth();
   
   return;
  }
  
  int widthForEachHeaderChild = (int) Math.ceil(availableWidth / (leftHeaderSecondLvlChildrenCount + rightHeaderSecondLvlChildrenCount));
  
  
  this.addWidthForEachHeaderLeftAndRightChild(widthForEachHeaderChild);
  // set the header width
  this.leftHeaderChildrenWidth = this.getLeftHeaderChildrenWidth();
  this.rightHeaderChildrenWidht = this.getRightHeaderChildrenWidth();
  
 }
 /**
  * get children count in left header
  * @return
  */
 private int leftSecondLvlHeaderChildrenCount(){
  int totalChildren = 0;
  int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
   
   LinearLayout secondLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
   totalChildren += secondLvlLinearLayout.getChildCount();
   
  
  }
  
  return totalChildren;
 }
 /**
  * get children count in right header
  * @return
  */
 private int rightSecondLvlHeaderChildrenCount(){
  int totalChildren = 0;
  int leftHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
   
   LinearLayout secondLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
   totalChildren += secondLvlLinearLayout.getChildCount();
   
  
  }
  
  return totalChildren;
 }
 /**
  * Compute total header width in left header
  * @return
  */
 private int leftSecondLvlHeaderChildrenTotalWidth(){
  int totalWidth = 0;
  int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
   
   LinearLayout secondLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
   int leftColumnChildrenCount = secondLvlLinearLayout.getChildCount();
   
   for(int y = 0 ; y < leftColumnChildrenCount ; y++){
    View view  = secondLvlLinearLayout.getChildAt(y);
    LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
    
    int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) : params.width;
    
    totalWidth += width;
    
   }
   
  }
  
  return totalWidth;
 }
 /**
  * Compute total right header children width
  * @return
  */
 private int rightHeaderChildrenTotalWidth(){
  int totalWidth = 0;
  int leftHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
  
  for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
   
   LinearLayout secondLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
   int leftColumnChildrenCount = secondLvlLinearLayout.getChildCount();
   
   for(int y = 0 ; y < leftColumnChildrenCount ; y++){
    View view  = secondLvlLinearLayout.getChildAt(y);
    LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
    
    int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) : params.width;
    
    totalWidth += width;
    
   }
   
  }
  
  return totalWidth;
 }
 /**
  * Add width in left and right children width if needed to match screen width.
  * @param widthToBeAdded
  */
 private void addWidthForEachHeaderLeftAndRightChild(int widthToBeAdded){
  
  int leftHeaderColumnCount = leftTable.headerHorizontalLinearLayout.getChildCount();
  int rightHeaderColumnCount = rightTable.headerHorizontalLinearLayout.getChildCount();
  
  for(int x = 0 ; x < leftHeaderColumnCount ; x++){
   
   HeaderRow tableRow =  (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
   int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
   
   for(int y = 0 ; y < headerRowChildCount ; y++){
    
    View view = tableRow.secondLvlLinearLayout.getChildAt(y);
    
    LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
    
    int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) + widthToBeAdded : params.width +widthToBeAdded;
    params.width = width;
   }
   
   
  }
  
  for(int x = 0 ; x < rightHeaderColumnCount ; x++){
   
   HeaderRow tableRow =  (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
   int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
   
   for(int y = 0 ; y < headerRowChildCount ; y++){
    
    View view = tableRow.secondLvlLinearLayout.getChildAt(y);
    
    LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
    
    int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) + widthToBeAdded : params.width +widthToBeAdded;
    params.width = width;
   }
   
   
  }
   
 }
 /**
  * Get each width of left header child
  * @return
  */
 private Integer[] getLeftHeaderChildrenWidth(){
  
  List<Integer> headerChildrenWidth = new ArrayList<Integer>();
  
  int leftHeaderColumnCount = leftTable.headerHorizontalLinearLayout.getChildCount();
  
  
  for(int x = 0 ; x < leftHeaderColumnCount ; x++){
   
   HeaderRow tableRow =  (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
   int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
   
   for(int y = 0 ; y < headerRowChildCount ; y++){
    
    View view = tableRow.secondLvlLinearLayout.getChildAt(y);
    
    LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
    
    int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view): params.width ;
    
    headerChildrenWidth.add(width);
    
   }
   
   
  }
  
  
  return headerChildrenWidth.toArray(new Integer[headerChildrenWidth.size()]);
 }
 /**
  * Get each width of right header child
  * @return
  */
 private Integer[] getRightHeaderChildrenWidth(){
  
  List<Integer> headerChildrenWidth = new ArrayList<Integer>();
  
  int rightHeaderColumnCount = rightTable.headerHorizontalLinearLayout.getChildCount();
  
  for(int x = 0 ; x < rightHeaderColumnCount ; x++){
   
   HeaderRow tableRow =  (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
   int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
   
   for(int y = 0 ; y < headerRowChildCount ; y++){
    
    View view = tableRow.secondLvlLinearLayout.getChildAt(y);
    
    LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
    
    int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) : params.width ;
    
    headerChildrenWidth.add(width);
   }
   
   
  }
 
  return headerChildrenWidth.toArray(new Integer[headerChildrenWidth.size()]);
 }
 /**
  * Resize each body column to match each other
  */
 private  void resizeBodyChildrenHeight(){
  
  int leftHeaderFirstLvlHighestHeight = 0;
  
  
  for(LinearLayout lin : leftTable.bodyLinearLayoutTempMem){
   
   int childCount = lin.getChildCount();
   
   for(int x = 0 ; x < childCount; x++){
    int width = ViewSizeUtils.getViewHeight(lin.getChildAt(x));
    if(leftHeaderFirstLvlHighestHeight < width){
     leftHeaderFirstLvlHighestHeight = width;
     
    }
   }
   
   
  }
  
  int rightHeaderFirstLvlHighestHeight = 0;
  //int rightHeaderFirstLvlHighestHeightIndex = 0;
  for(LinearLayout lin : rightTable.bodyLinearLayoutTempMem){
   
   int childCount = lin.getChildCount();
   
   for(int x = 0 ; x < childCount; x++){
    int width = ViewSizeUtils.getViewHeight(lin.getChildAt(x));
    if(rightHeaderFirstLvlHighestHeight < width){
     rightHeaderFirstLvlHighestHeight = width;
     //rightHeaderFirstLvlHighestHeightIndex = x;
    }
   }
   
   
  }
  
  boolean isHighestHighInLeft = leftHeaderFirstLvlHighestHeight > rightHeaderFirstLvlHighestHeight;
  
  
  for(LinearLayout lin : leftTable.bodyLinearLayoutTempMem){
   
   int childCount = lin.getChildCount();
   
   for(int x = 0 ; x < childCount; x++){
    LinearLayout.LayoutParams params = (LayoutParams) lin.getChildAt(x).getLayoutParams();
    params.height = isHighestHighInLeft ? leftHeaderFirstLvlHighestHeight : rightHeaderFirstLvlHighestHeight;
    
   }
   
   
  }
  
  for(LinearLayout lin : rightTable.bodyLinearLayoutTempMem){
   
   int childCount = lin.getChildCount();
   
   for(int x = 0 ; x < childCount; x++){
    LinearLayout.LayoutParams params = (LayoutParams) lin.getChildAt(x).getLayoutParams();
    params.height = isHighestHighInLeft ? leftHeaderFirstLvlHighestHeight : rightHeaderFirstLvlHighestHeight;
    
   }
   
   
  }
  
 }
 /**
  * 
  * @author lau
  *
  */
 class LoadingDialog extends Dialog{

   LoadingDialog(Context context) {
   super(context);
   this.setCancelable(false);
   this.requestWindowFeature(Window.FEATURE_NO_TITLE);
   this.init(context);
  }
  
   private void init(Context context){
    TextView textView = new TextView(context);
    textView.setText("Please wait loading data..");
    
    this.setContentView(textView);
    
   }
 }
 class Passenger{
  String name;
  char gender;
  int ticketNum;
  String validUntil;
  String setSequence;
  String countryFrom;
  String countryTo;
 }
}

That is the Table. It hold everything.

3. HeaderRow.java


public class HeaderRow extends LinearLayout{
 
 protected final static int NEXT_PAGINATION_TAG = 19860116;
 protected final static int PREVIUOS_PAGINATION_TAG = 19860117;
 final int PADDING = 5;
 LinearLayout firtLvlLinearLayout;
 LinearLayout secondLvlLinearLayout;
 
 /**
  * @nextTextView and @previousTextView = for pagination
  */
 TextView nextTextView;
 TextView previousTextView;
 
 Object firstLvlLabel;
 Object[] secondLvlLabel;
 String scrollViewTag;
 
 OnClickListenerOfPagination onClickListenerOfPagination;
 Table table;
 public HeaderRow(Table table, Object firstLvlLabel, Object[] secondLvlLabel, String scrollViewTag) {
  super(table.getContext());
  this.table = table;
  this.firstLvlLabel = firstLvlLabel;
  this.secondLvlLabel = secondLvlLabel;
  this.scrollViewTag = scrollViewTag;
  
  
  this.properties();
  this.init();
  this.initFirstLvlHeaders();
  this.initSecondLvlHeader();
  this.analizeFirstAndSecondHeaderWidth();
 }
 
 private void properties(){
  
  this.setOrientation(LinearLayout.VERTICAL);
 }
 /**
  * initialization
  */
 private void init(){
  
  this.onClickListenerOfPagination = new OnClickListenerOfPagination(table);
  this.firtLvlLinearLayout = new LinearLayout(this.getContext());
  this.firtLvlLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
  
  this.secondLvlLinearLayout = new LinearLayout(this.getContext());
  this.secondLvlLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
  
  
  if(Table.IS_TWO_COLUMN_HEADER){
   
   this.addView(firtLvlLinearLayout);
   this.addView(secondLvlLinearLayout);
  
  }else{
   
   this.addView(secondLvlLinearLayout);
   
  }
  
  
 }
 /**
  * top most header column
  */
 private void initFirstLvlHeaders(){
  LinearLayout.LayoutParams firstLvlTextViewParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
  firstLvlTextViewParams.setMargins(1, 1, 1, 1);
  firstLvlTextViewParams.weight = 1;
  
  TextView firstLvlTextView = new TextView(this.getContext());
  firstLvlTextView.setText(firstLvlLabel.toString());
  firstLvlTextView.setPadding(PADDING, PADDING, PADDING, PADDING);
  firstLvlTextView.setBackgroundColor(Table.HEADER_BACKROUND_COLOR);
  firstLvlTextView.setGravity(Gravity.CENTER);
  firstLvlTextView.setLayoutParams(firstLvlTextViewParams);
  
  this.firtLvlLinearLayout.addView(firstLvlTextView);
 }
 
 /**
  * second header column
  */
 private void initSecondLvlHeader(){
  
  int secondLvlHeaderLblCount = this.secondLvlLabel.length;
  
 
  
  for(int x = 0 ; x < secondLvlHeaderLblCount ; x++){
   LinearLayout.LayoutParams firstLvlTextViewParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
   firstLvlTextViewParams.setMargins(1, 1, 1, 1);
   
   String labelString = secondLvlLabel[x].toString();
   
   if(labelString.equalsIgnoreCase(Table.NAME)){
    
    
    LinearLayout paginationLinearLayout = this.paginationLinearLayout(labelString);
    
    paginationLinearLayout.setPadding(PADDING, PADDING, PADDING, PADDING);
    paginationLinearLayout.setBackgroundColor(Table.HEADER_BACKROUND_COLOR);
    
    paginationLinearLayout.setLayoutParams(firstLvlTextViewParams);
    
    this.secondLvlLinearLayout.addView(paginationLinearLayout);
    
   }else{
    TextView secondLvlTextView = new TextView(this.getContext());
    secondLvlTextView.setText(labelString.equalsIgnoreCase("Product") ? "Product": labelString);
    secondLvlTextView.setPadding(PADDING, PADDING, PADDING, PADDING);
    secondLvlTextView.setBackgroundColor(Table.HEADER_BACKROUND_COLOR);
    secondLvlTextView.setGravity(Gravity.CENTER);
    secondLvlTextView.setLayoutParams(firstLvlTextViewParams);
    
    this.secondLvlLinearLayout.addView(secondLvlTextView);
    
   }
   
  }
 }
 /**
  * layout for pagination
  * @param label
  * @return
  */
 private LinearLayout paginationLinearLayout(String label){
  
  LinearLayout paginationLinearLayout = new LinearLayout(this.getContext());
  
  TextView labelTextView = new TextView(this.getContext());
  labelTextView.setGravity(Gravity.CENTER);
  labelTextView.setText(label);
  LinearLayout.LayoutParams labelTextViewParams = new LinearLayout.LayoutParams(0,LayoutParams.MATCH_PARENT);
  labelTextViewParams.weight = 1;
  
  this.nextTextView = new TextView(this.getContext());
  this.nextTextView.setText("   "+Table.NEXT_ARROW+"   ");
  this.nextTextView.setGravity(Gravity.CENTER);
  this.nextTextView.setTag(NEXT_PAGINATION_TAG);
  this.nextTextView.setBackgroundDrawable(new CustomStateListDrawable(nextTextView));
  this.nextTextView.setOnClickListener(this.onClickListenerOfPagination);
  
  LinearLayout.LayoutParams nextTextViewParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
  
  this.previousTextView = new TextView(this.getContext());
  this.previousTextView.setText("   "+Table.PREVIOUS_ARROW+"   ");
  this.previousTextView.setGravity(Gravity.CENTER);
  this.previousTextView.setTag(PREVIUOS_PAGINATION_TAG);
  this.previousTextView.setTextColor(Table.HEADER_BACKROUND_COLOR);
  this.previousTextView.setBackgroundDrawable(new CustomStateListDrawable(previousTextView));
  this.previousTextView.setOnClickListener(this.onClickListenerOfPagination);
  
  LinearLayout.LayoutParams previousTextViewParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
  
  paginationLinearLayout.addView(previousTextView,previousTextViewParams);
  paginationLinearLayout.addView(labelTextView,labelTextViewParams);
  paginationLinearLayout.addView(nextTextView,nextTextViewParams);
  
  return paginationLinearLayout;
 }
 /**
  * adjust the width of headers to match in screen size
  */
 private void analizeFirstAndSecondHeaderWidth(){

  int headerSecondLvlChildrenCount = secondLvlLinearLayout.getChildCount();
  /**
   * LEFT = 1;
   * RIGHT = 1;
   * get first lvl header width + (number of second lvl * (PADDING * (LEFT + RIGHT)) )
   */
  int headerFirstLvlWidth = ViewSizeUtils.getViewWidth(firtLvlLinearLayout.getChildAt(0)) + (headerSecondLvlChildrenCount * (PADDING * 2));
  
  
  int headerSecondLvlChildrenTotalWidth = 0;
  
  for(int x = 0 ; x < headerSecondLvlChildrenCount ;x++){
    
   headerSecondLvlChildrenTotalWidth += ViewSizeUtils.getViewWidth(secondLvlLinearLayout.getChildAt(x));
  }
  
  

  int availableWidht = headerFirstLvlWidth - headerSecondLvlChildrenTotalWidth;
  int widhtForEachChild = (int) Math.ceil(availableWidht / headerSecondLvlChildrenCount);
  
  
  if(availableWidht <= 0){
   // if no available width, do nothing
   return;
  }
  
  for(int x = 0 ; x < headerSecondLvlChildrenCount ;x++){
   View view = secondLvlLinearLayout.getChildAt(x);
   LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
   params.width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) + widhtForEachChild : params.width + widhtForEachChild;
  }
  
 }
}

That is the HeaderRow.java. This is a left and right header of our table.

4. OnClickListenerOfPagination.java


class OnClickListenerOfPagination implements OnClickListener {

 Table table;
 OnClickListenerOfPagination(Table table){
  this.table = table;
 }
 @Override
 public void onClick(View view) {
  

  // show loading dialog
  table.loadingDialog.show();
  
  int tag = (Integer) view.getTag();
    
  switch (tag) {
  case HeaderRow.NEXT_PAGINATION_TAG:
   
   
   
   table.pageNumber++;
   
   table.loadData();
   
   
   table.leftTable.headerRow.previousTextView.setTextColor(Color.BLACK);
   table.leftTable.headerRow.previousTextView.setEnabled(true);
   
   if(table.pageNumber == table.totalPage){
    table.leftTable.headerRow.nextTextView.setEnabled(false);
    table.leftTable.headerRow.nextTextView.setTextColor(Table.HEADER_BACKROUND_COLOR);
   }
   
   break;
  case HeaderRow.PREVIUOS_PAGINATION_TAG:
   
   
   
   table.pageNumber--;
   table.loadData();
   
   // set text color black
   table.leftTable.headerRow.nextTextView.setTextColor(Color.BLACK);
   table.leftTable.headerRow.nextTextView.setEnabled(true);
   
   if(table.pageNumber ==  1){
    table.leftTable.headerRow.previousTextView.setEnabled(false);
    table.leftTable.headerRow.previousTextView.setTextColor(Table.HEADER_BACKROUND_COLOR);
    
   }
   
   break;
  default:
   break;
  }  
  
  table.loadingDialog.dismiss();
  
 }

}

That is OnClickListenerOfPagination. This class is responsible for pagination.

That are the important java file in our custom android table with fixed header, header with column span and fixed row.

Download Source Code Here

Happy coding everyone.

71 comments:

  1. Hi! Thanks for the useful code. Would you mind stating the license for it?
    We'd love to use it in our opensource project but for that to happen it needs to be GPLv3+ compatible.

    ReplyDelete
  2. I don't know how to apply/create license in source code. By the way, you can use the source code.

    ReplyDelete
    Replies
    1. Thank you!

      P.S. If you want your code to be used as widely as possible, with reference to you as its author, it makes sense to choose one of the permissive opensource licenses (like MIT or BSD license). They are easy to read and understand, and come with instructions how to apply them to your code.
      There's more info - https://opensource.org/faq#apply-license

      Delete
  3. Can not download this code.

    ReplyDelete
  4. please share the source code with me on lokesh@altius.cc

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. please share the code with me on joylobo404@gmail.com

    ReplyDelete
  7. please share the source code with me on kamdem.yves@gmail.com

    ReplyDelete
  8. Could you please share the source code with me on ntanduc2288@gmail.com.
    Thanks,

    ReplyDelete
  9. Please help, could you please just post here or send me by email the source code of the class BodyTable? I think the rest will be fine. I had no answer since my last query here and on google+. please. Thanks

    ReplyDelete
  10. Would you please share the cource code with me on nasper.2458@gmail.com.
    Thank you so much.

    ReplyDelete
  11. please share the code with me on apnair007@gmail.com

    ReplyDelete
  12. please share the code with me on chengpanchng@gmail.com

    ReplyDelete
  13. Very impressive and useful.
    A Direct download link would be nice...
    Thanks

    ReplyDelete
  14. please share the code with me on cristianpreciado93@gmail.com

    ReplyDelete
  15. Hi, share the code on my email, nalinapowlika99@gmail.com.

    ReplyDelete
  16. please send me this code .my email is rumeshdissanayaka@gmil.com

    ReplyDelete
  17. please send me code madhurashetty95@gmail.com

    ReplyDelete
  18. Please send me code on aeshashah1310@gmail.com

    ReplyDelete
  19. This comment has been removed by the author.

    ReplyDelete
  20. This comment has been removed by the author.

    ReplyDelete
  21. nguyenthanhluan.ntc@gmail.com.. tks

    ReplyDelete
  22. Well done! and thank you for sharing - please email me the direct D/L link at frederique.martines@gmail.com

    ReplyDelete
  23. This comment has been removed by the author.

    ReplyDelete
  24. please share the code with me on bransonlee0426@gmail.com
    ty~

    ReplyDelete
  25. This is an awesome article. One quick question, will it work on all APIs?

    ReplyDelete
  26. This comment has been removed by the author.

    ReplyDelete
  27. source code please crudoperational@gmail.com

    ReplyDelete
  28. Please share your source code to pictaro@gmail.com
    Thank you.

    ReplyDelete
  29. hi, please share the source code to haalikes216@gmail.com
    Thank you!

    ReplyDelete
  30. Hi, Can you please share source code with rajaeshwar@gmai.com

    ReplyDelete
  31. please share source code with phuochuudo@gmai.com

    ReplyDelete
  32. Thanks for the code...it really helped me a lot..just one question..how to make header width size to its maximum length of text in that column i.e wrap content

    ReplyDelete
  33. can you please send me source code as soon as possible, I need this code for my project.

    ReplyDelete
  34. Hi,
    Nice post. Please share the code.
    email ID : telang.trupti@gmail.com

    Regards,

    ReplyDelete
  35. Very nice Table! I was looking for something like this!
    Could you send me the Source Code?
    email: giopromolla@gmail.com

    ReplyDelete
  36. Good idea!.
    please share the code with me on Email : porntep@gmail.com

    Thank You.^^

    ReplyDelete
  37. Hai,
    This is kalyan Email billstash14@gmail.com can u share Code

    ReplyDelete
  38. Hi, excelent code. I really appreciate if you can share your code with me too. Thanks in advance. My email abnerh69@gmail.com

    ReplyDelete
  39. hi, please share the source code to pankajdhomkar007@gmail.com
    Thank you

    ReplyDelete
  40. Please share the code to disha.aseum@gmail.com
    Thank you

    ReplyDelete
  41. Please share the source code on pankajdhomkar@gmail.com
    Thank you.

    ReplyDelete
  42. HELLO SIR. VERY NICE CODE... Can you guide me on how to change each cell's data ??? i want to edit each rows and columns data .. you can put a mail at deepgagan100@hotmail.coom

    ReplyDelete
  43. This comment has been removed by the author.

    ReplyDelete
  44. hii,how can i get this code amitmehta.babbu07@gmail.com

    ReplyDelete
  45. Could you please share me your source code? my email is: ttdat.0410@gmail.com .. Thanks so much.:)

    ReplyDelete
  46. please share the code with itclubonline@gmail.com

    ReplyDelete
  47. Please share the code. jawagag@gmail.com

    ReplyDelete
  48. From Indonesia, its a great thanks if you send me the code samueltambunan1991@gmail.com

    ReplyDelete
  49. please share the code with newrcname@gmail.com

    ReplyDelete
  50. please share the code with me on satenterus@gmail.com

    ReplyDelete
  51. Great project. Please share the code with me on thmstong@gmail.com. Thanks a lot

    ReplyDelete
  52. Great Project, Thank You For The Information, Can You Share The Source Code In My E-mail rigelarmanda@gmail.com
    Thank You

    ReplyDelete
  53. Nice code, but I have a question. But I have problem, I need the table starting not on top of the layout, coz there is a menu on top. How modify the code???

    ReplyDelete
  54. This comment has been removed by the author.

    ReplyDelete
  55. Hi, Can you please send me code with adding spinner for one column to the same table. It will be great help.
    thanks in advance.
    my E-mail:sharath.shetty.r@gmail.com

    ReplyDelete
  56. Please send me the code to my e-mai:sharath.shetty.r@gmail.com

    ReplyDelete
  57. how can we add new row in this table?

    ReplyDelete