SortableTableView


Source link: https://github.com/ISchwarz23/SortableTableView

SortableTableView for Android

An Android library providing a TableView and a SortableTableView.

Minimum SDK-Version: 11 | Compile SDK-Version: 25 | Latest Library Version: 2.8.0

Repository Content

tableview - contains the android library sources and resources
app - contains an example application showing how to use the SortableTableView

Setup

To use the this library in your project simply add the following dependency to your build.gradle file.


 dependencies {

...

compile 'de.codecrafters.tableview:tableview:2.8.0'

...
  
}
 

Support Me

I offer this library and the complete source code of it for free! To develop open source software is not without cost though — it takes technical knowledge, time, and effort. You don't have to be a developer to support my open source work! If you want to receive personal support, or just feel all warm and fuzzy inside from helping open source development, donations are very welcome. Thank you in advance! :)

"Thank's for creating this project, here's a coffee (or some beer) for you!"
Donate 5$ or Donate 5€

"Wow, I am stunned. Let me take you to the movies!"
Donate 10$ or Donate 10€

"I really appreciate your work, let's grab some lunch!"
Donate 15$ or Donate 15€

"That's some awesome stuff you did right there, dinner is on me!"
Donate 25$ or Donate 25€

"I really really want to support this project, great job!"
Donate 50$ or Donate 50€

"You are the man! This project saved me hours (if not days) of struggle and hard work, simply awesome!"
Donate 100$ or Donate 100€

Features

Layouting

Column Count

The provided TableView is very easy to adapt to your needs. To set the column count simple set the parameter inside your XML layout.

<de.codecrafters.tableview.TableView
  xmlns:table="http://schemas.android.com/apk/res-auto"
  android:id="@+id/tableView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  table:tableView_columnCount="4" />

A second possibility to define the column count of your TableView is to set it directly in the code.

TableView tableView = (TableView) findViewById(R.id.tableView);
 tableView.setColumnCount(4);

Column Width

To define the column widths you can set a TableColumnModel that defines the width for each column. You can use a predefined TableColumnModel or implement your custom one.

TableColumnWeightModel
This model defines the column widths in a relative manner. You can define a weight for each column index. The default column weight is 1.

TableColumnWeightModel columnModel = new TableColumnWeightModel(4);
 columnModel.setColumnWeight(1, 2);
 columnModel.setColumnWeight(2, 2);
 tableView.setColumnModel(columnModel);

TableColumnDpWidthModel
This model defines the column widths in a absolute manner. You can define a width in density-independent pixels for each column index. The default column width is 100dp. You can pass a different default to the constructor.

TableColumnDpWidthModel columnModel = new TableColumnDpWidthModel(context, 4, 200);
 columnModel.setColumnWidth(1, 300);
 columnModel.setColumnWidth(2, 250);
 tableView.setColumnModel(columnModel);

TableColumnPxWidthModel
This model defines the column widths in a absolute manner. You can define a width in pixels for each column index. The default column width is 200px. You can pass a different default to the constructor.

TableColumnPxWidthModel columnModel = new TableColumnPxWidthModel(4, 350);
 columnModel.setColumnWidth(1, 500);
 columnModel.setColumnWidth(2, 600);
 tableView.setColumnModel(columnModel);

Showing Data

Simple Data

For displaying simple data like a 2D-String-Array you can use the SimpleTableDataAdapter. The SimpleTableDataAdapter will turn the given Strings to TextViews and display them inside the TableView at the same position as previous in the 2D-String-Array.

public class MainActivity extends AppCompatActivity {

 private static final String[][] DATA_TO_SHOW = {
 {
 "This", "is", "a", "test" 
}
,

 {
 "and", "a", "second", "test" 
}
 
}
;

  @Override
  protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

 TableView<String[]> tableView = (TableView<String[]>) findViewById(R.id.tableView);

tableView.setDataAdapter(new SimpleTableDataAdapter(this, DATA_TO_SHOW));

  
}
 
}

  

Custom Data

For displaying more complex custom data you need to implement your own TableDataAdapter. Therefore you need to implement the getCellView(int rowIndex, int columnIndex, ViewGroup parentView) method. This method is called for every table cell and needs to returned the View that shall be displayed in the cell with the given rowIndex and columnIndex. Here is an example of an TableDataAdapter for a Car object.

public class CarTableDataAdapter extends TableDataAdapter<Car> {

public CarTableDataAdapter(Context context, List<Car> data) {

super(context, data);

  
}

@Override
  public View getCellView(int rowIndex, int columnIndex, ViewGroup parentView) {

Car car = getRowData(rowIndex);

View renderedView = null;

 switch (columnIndex) {

 case 0:

  renderedView = renderProducerLogo(car);

  break;

 case 1:

  renderedView = renderCatName(car);

  break;

 case 2:

  renderedView = renderPower(car);

  break;

 case 3:

  renderedView = renderPrice(car);

  break;

}

 return renderedView;
  
}

}

The TableDataAdapter provides several easy access methods you need to render your cell views like:

  • getRowData()
  • getContext()
  • getLayoutInflater()
  • getResources()

Sortable Data

If you need to make your data sortable, you should use the SortableTableView instead of the ordinary TableView. To make a table sortable by a column, all you need to do is to implement a Comparator and set it to the specific column.

@Override protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  // ...
  sortableTableView.setColumnComparator(0, new CarProducerComparator());
 
}
  private static class CarProducerComparator implements Comparator<Car> {

  @Override
  public int compare(Car car1, Car car2) {

return car1.getProducer().getName().compareTo(car2.getProducer().getName());

  
}
 
}

By doing so the SortableTableView will automatically display a sortable indicator next to the table header of the column with the index 0. By clicking this table header, the table is sorted ascending with the given Comparator. If the table header is clicked again, it will be sorted in descending order.

Empty Data Indicator

If you want to show a certain view if there is no data available in the table, you can use the setEmptyDataIndicatorView method. Therefore you first have to add this view to your layout (preferable with visibility gone) and then pass it to the TableView.

@Override protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  // ...
  tableView.setEmptyDataIndicatorView(findViewById(R.id.empty_data_indicator));
 
}

This view is automatically shown if no data is available and hidden if there is some data to show.

Header Data

Setting data to the header views is identical to setting data to the table cells. All you need to do is extending the TableHeaderAdapter which is also providing the easy access methods that are described for the TableDataAdapter.
If all you want to display in the header is the column title as String (like in most cases) the SimpleTableHeaderAdapter will fulfil your needs. To show simple Strings inside your table header, use the following code:

public class MainActivity extends AppCompatActivity {

 private static final String[] TABLE_HEADERS = {
 "This", "is", "a", "test" 
}
;

  @Override
  protected void onCreate(Bundle savedInstanceState) {

// ...

tableView.setHeaderAdapter(new SimpleTableHeaderAdapter(this, TABLE_HEADERS));

  
}
 
}
  

To show Strings from resources inside your table header, use the following code:

public class MainActivity extends AppCompatActivity {

 private static final int[] TABLE_HEADERS = {
 R.string.header_col1, R.string.header_col2, R.string.header_col3 
}
;

  @Override
  protected void onCreate(Bundle savedInstanceState) {

// ...

tableView.setHeaderAdapter(new SimpleTableHeaderAdapter(this, TABLE_HEADERS));

  
}
 
}
  

Interaction Listening

Data Click Listening

To listen for clicks on data items you can register a TableDataClickListener. The TableView provides a method called addDataClickListener() to register this listeners.

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ...
  tableView.addDataClickListener(new CarClickListener());
 
}
  private class CarClickListener implements TableDataClickListener<Car> {

  @Override
  public void onDataClicked(int rowIndex, Car clickedCar) {

String clickedCarString = clickedCar.getProducer().getName() + " " + clickedCar.getName();

Toast.makeText(getContext(), clickedCarString, Toast.LENGTH_SHORT).show();

  
}
 
}

Long Data Click Listening

To listen for clicks on data items you can register a TableDataLongClickListener. The TableView provides a method called addDataLongClickListener() to register this columns.

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ...
  tableView.addDataLongClickListener(new CarLongClickListener());
 
}
  private class CarLongClickListener implements TableDataLongClickListener<Car> {

  @Override
  public boolean onDataLongClicked(int rowIndex, Car clickedCar) {

String clickedCarString = clickedCar.getProducer().getName() + " " + clickedCar.getName();

Toast.makeText(getContext(), clickedCarString, Toast.LENGTH_SHORT).show();

return true;
  
}
 
}

The main difference to the TableDataClickListener#onDataClicked() method is, that the onDataLongClicked() method has a boolean as return value. This boolean indicates, if the TableDataLongClickListener has "consumed" the click event. If none of the registered TableDataLongClickListeners has consumed the click event, the TableDataClickListeners are informed in addition.

Header Click Listening

To listen for clicks on headers you can register a TableHeaderClickListner. The TableView provides a method called addHeaderClickListener() to do so.

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ...
  tableView.addHeaderClickListener(new MyHeaderClickListener());
 
}
  private class MyHeaderClickListener implements TableHeaderClickListener {

  @Override
  public void onHeaderClicked(int columnIndex) {

String notifyText = "clicked column " + (columnIndex+1);

Toast.makeText(getContext(), notifyText, Toast.LENGTH_SHORT).show();

  
}
 
}

On Scroll Listening

To listen for scroll or scroll state changes you can register a OnScrollListener. The TableView provides a method called addOnScrollListener() to do so.

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ...
  tableView.addOnScrollListener(new MyOnScrollListener());
 
}
  private class MyOnScrollListener implements OnScrollListener {

  @Override
  public void onScroll(final ListView tableDataView, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) {

// listen for scroll changes
  
}

  @Override
  public void onScrollStateChanged(final ListView tableDateView, final ScrollState scrollState) {

// listen for scroll state changes
  
}
 
}

In addition this library provides an EndlessOnScrollListener which allows the loading of further data when the user scrolls to the end of the table. Therefore you can give an row threshold which defines when the data shall be reloaded. A threshold of 3 would mean, that the loading shall be triggered when the user reaches the 3rd last row. The default threshold is 5.

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ...
  tableView.addOnScrollListener(new MyEndlessOnScrollListener());
 
}
  private class MyEndlessOnScrollListener extends EndlessOnScrollListener {

 @Override
  public void onReloadingTriggered(final int firstRowItem, final int visibleRowCount, final int totalRowCount) {

// show a loading view to the user

// reload some data

// add the loaded data to the adapter

// hide the loading view
  
}
 
}

Styling

Header Styling

The table view provides several possibilities to style its header. One possibility is to set a color for the header. Therefore you can adapt the XML file or add it to your code.

<de.codecrafters.tableview.TableView
  xmlns:table="http://schemas.android.com/apk/res-auto"
  android:id="@+id/tableView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  table:tableView_headerColor="@color/primary" />
tableView.setHeaderBackgroundColor(getResources().getColor(R.color.primary));

For more complex header styles you can also set a drawable as header background using the following method.

tableView.setHeaderBackground(R.drawable.linear_gradient);

In addition you can set an elevation of the table header. To achieve this you have the possibility to set the elevation in XML or alternatively set it in your code.

<de.codecrafters.tableview.TableView
  xmlns:table="http://schemas.android.com/apk/res-auto"
  android:id="@+id/tableView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  table:tableView_headerElevation="10" />
tableView.setHeaderElevation(10);

NOTE: This elevation is realized with the app-compat version of elevation. So it is also applicable on pre-lollipop devices

For SortableTableViews it is also possible to replace the default sortable indicator icons by your custom ones. To do so you need to implement the SortStateViewProvider and set it to your SortableTableView.

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // ...
  sortableTableView.setHeaderSortStateViewProvider(new MySortStateViewProvider());
 
}
  private static class MySortStateViewProvider implements SortStateViewProvider {

private static final int NO_IMAGE_RES = -1;

@Override
  public int getSortStateViewResource(SortState state) {

switch (state) {

 case SORTABLE:

  return R.mipmap.ic_sortable;

 case SORTED_ASC:

  return R.mipmap.ic_sorted_asc;

 case SORTED_DESC:

  return R.mipmap.ic_sorted_desc;

 default:

  return NO_IMAGE_RES;

}

  
}
 
}

There is also a factory class existing called SortStateViewProviders where you can get some predefined implementations of the SortStateViewProvider.

Data Row Styling

In general you can do all your styling of data content in your custom TableDataAdapter. But if you want to add a background for the whole table rows you can use the TableDataRowBackgroundProvider. There are already some implementations of the TableDataRowBackgroundProvider existing in the library. You can get them by using the Factory class TableDataRowBackgroundProviders.
This Factory contains for example an alternating-table-data-row-row provider that will color rows with even index different from rows with odd index.

@Override protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  // ...
  int colorEvenRows = getResources().getColor(R.color.white);

  int colorOddRows = getResources().getColor(R.color.gray);

  tableView.setDataRowBackgroundProvider(TableDataRowBackgroundProviders.alternatingRowColors(colorEvenRows, colorOddRows));
 
}

If the implementations of TableDataRowBackgroundProvider contained in the TableDataRowBackgroundProviders factory don't fulfil you needs you can create your own implementation of TableDataRowBackgroundProvider. Here is a small example of how to do so.

@Override protected void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  // ...
  tableView.setDataRowBackgroundProvider(new CarPriceRowColorProvider());
 
}

private static class CarPriceRowColorProvider implements TableDataRowBackgroundProviders<Car> {

  @Override
  public Drawable getRowBackground(final int rowIndex, final Car car) {

int rowColor = getResources(R.color.white);

 if(car.getPrice() < 50000) {

 rowColor = getResources(R.color.light_green);

}
 else if(car.getPrice() > 100000) {

 rowColor = getResources(R.color.light_red);

}

  return new ColorDrawable(rowColor);

  
}
 
}

This background provider will set the background color of each row corresponding to the price of the car that is displayed at in this row. Cheap cars (less then 50,000) get a green background, expensive cars (more then 100,000) get a red background and all other cars get a white background.

Seperator Styling

If you want to have a seperator between the data rows you can do so by specifying it in the XML like known from the ListView.

<de.codecrafters.tableview.TableView
  android:id="@+id/tableView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:divider="@color/black"
  android:dividerHeight="1dip"
  ...  /> 

As for the ListView you can specify divider as a drawable and dividerHeight as the vertical size of the divider.

Swipe to Refresh

The TableView has a build in SwipeToRefresh action. By default this is disabled, but you can easily enable it using the follwing line.

tableView.setSwipeToRefreshEnabled( true );

This enables the user to trigger the table refresh on a single swipe. To listen for this user interaction you have to set an SwipeToRefreshListener to your tableview.

carTableView.setSwipeToRefreshListener(new SwipeToRefreshListener() {

  @Override
  public void onRefresh(final RefreshIndicator refreshIndicator) {

// your async refresh action goes here
  
}
 
}
);

The callback method has the RefreshIndicator that is shown to the user passed as parameter. So if you finished your refresh action simply call RefreshIndicator.hide().

Hide Table Header

To hide the header of the TableView just call the setHeaderVisible( false ) method. You can do this also with animation calling setHeaderVisibile( false, 1000 ) where the second parameter is the duration of the animation. To make the header visible again just call setHeaderVisible( true ) or setHeaderVisible( true, 1000 ).

Hide/Show Table Header on Scroll

To hide an show the table header when the user is scrolling, just use the TableHeaderCollapseOnScrollListener.

carTableView.setOnScrollListener(new TableHeaderCollapseOnScrollListener( carTableView ));

By default the TableHeaderCollapseOnScrollListener will hide the header, when the user scrolls two rows to the bottom or shows it again when scrolling two rows to top. To change this you can call TableHeaderCollapseOnScrollListener#setRowOffset( int ) with your preferred offset. To enable animation you can call TableHeaderCollapseOnScrollListener#setAnimationDuration( int ) with your preferred animation duration.

State Persistence

The TableView as well as the SortableTableView will persist its state automatically (e.g. on orientation change). If you want to disable this behaviour you can do so using the following code snipped.

tableView.setSaveEnabled( false );

License

Copyright 2015 Ingo Schwarz

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Resources

Take a screenshot of your view layout, programmatically!

Showcase application of SQLDelight and SQLBrite working together based on SQLBrite's sample.

It is a lightweight library which helps to create a custom view.

Nice and simple customizable implementation of Google style up/down arrow.

WindView is an Android Library to show Weather's Wind & pressure Status.

A small routing library for Android with easy back button management and code generation to write less code.

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes