{"id":15131510,"url":"https://github.com/ischwarz23/sortabletableview","last_synced_at":"2025-05-16T16:04:53.535Z","repository":{"id":65954511,"uuid":"39255205","full_name":"ISchwarz23/SortableTableView","owner":"ISchwarz23","description":"An Android library containing a simple TableView and an advanced SortableTableView providing a lot of customisation possibilities to fit all needs.","archived":false,"fork":false,"pushed_at":"2021-04-17T13:39:26.000Z","size":3284,"stargazers_count":1057,"open_issues_count":51,"forks_count":237,"subscribers_count":43,"default_branch":"master","last_synced_at":"2025-05-16T16:04:06.049Z","etag":null,"topics":["android","android-library","android-ui","material-design","sortabletableview","tableview"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ISchwarz23.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-17T13:23:54.000Z","updated_at":"2025-05-13T23:17:22.000Z","dependencies_parsed_at":"2023-02-18T08:25:30.064Z","dependency_job_id":null,"html_url":"https://github.com/ISchwarz23/SortableTableView","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ISchwarz23%2FSortableTableView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ISchwarz23%2FSortableTableView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ISchwarz23%2FSortableTableView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ISchwarz23%2FSortableTableView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ISchwarz23","download_url":"https://codeload.github.com/ISchwarz23/SortableTableView/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254564123,"owners_count":22092122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-library","android-ui","material-design","sortabletableview","tableview"],"created_at":"2024-09-26T03:42:35.458Z","updated_at":"2025-05-16T16:04:53.516Z","avatar_url":"https://github.com/ISchwarz23.png","language":"Java","readme":"[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-SortableTableView-brightgreen.svg?style=flat)](http://android-arsenal.com/details/1/2200) [![API](https://img.shields.io/badge/API-11%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=11) [![Build Status](https://travis-ci.org/ISchwarz23/SortableTableView.svg?branch=master)](https://travis-ci.org/ISchwarz23/SortableTableView)  \n# SortableTableView for Android\nAn Android library providing a TableView and a SortableTableView. \n\n![SortableTableView Example](https://raw.githubusercontent.com/ISchwarz23/SortableTableView/develop/README/SortableTableView-Example.gif)\n\n**Minimum SDK-Version:** 11  |  **Compile SDK-Version:** 25  |  **Latest Library Version:** 2.8.0  \n\n**New version available!** Check [version 3.1.0](http://www.sortabletableview.com) of the pro version.\n\n## Repository Content\n**tableview** - contains the android library sources and resources  \n**app** - contains an example application showing how to use the SortableTableView  \n\n[![Example App](http://www.clintonfitch.com/wp-content/uploads/2015/06/Google-Play-Button.jpg)](https://play.google.com/store/apps/details?id=de.codecrafters.tableviewexample)\n\n## Setup\nAdd it in your root build.gradle at the end of repositories:\n```\n    allprojects {\n        repositories {\n            ...\n            maven { url 'https://jitpack.io' }\n        }\n    }\n```\nThen add the dependency:\n```\n    dependencies {\n        ...\n        implementation 'com.github.ISchwarz23:SortableTableView:2.8.1'\n        ...\n    }\n```\n\n## Pro Version\nIf you want to have the best TableView experience, we offer you the possibility to get the [pro version](http://www.sortabletableview.com) \nof the SortableTableView. This is what the pro version offers you:\n\n| | Open-Source Version | Pro Version |\n| --- | --- | --- |\n| render simple data | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| render custom data | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| header styling | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| data row styling | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| data sorting | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| data loading | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| searching | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| paging | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| selection | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| view recycling | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| support | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| maintenance | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| quick start guide | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n| full documentation | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/cross-mark_274c.png\" height=\"24\"\u003e | \u003cimg src=\"https://emojipedia-us.s3.amazonaws.com/thumbs/120/microsoft/106/heavy-check-mark_2714.png\" height=\"24\"\u003e |\n\nTo get more information visit the [SortableTableView-Page](http://www.sortabletableview.com).\n\n\u003c!---\n## Support the open-source version\nAs the open-source version brings a lot of work to maintain, you can support me with a small donation in order\nto keep the free version alive.\n\n*\"Thank's for creating this project, here's a coffee (or some beer) for you!\"*  \n[Donate 5$](https://www.paypal.me/ISchwarz23/5USD) or  [Donate 5€](https://www.paypal.me/ISchwarz23/5EUR)\n\n*\"Wow, I am stunned. Let me take you to the movies!\"*  \n[Donate 10$](https://www.paypal.me/ISchwarz23/10USD) or  [Donate 10€](https://www.paypal.me/ISchwarz23/10EUR)\n\n*\"I really appreciate your work, let's grab some lunch!\"*  \n[Donate 15$](https://www.paypal.me/ISchwarz23/15USD) or  [Donate 15€](https://www.paypal.me/ISchwarz23/15EUR)\n\n*\"That's some awesome stuff you did right there, dinner is on me!\"*  \n[Donate 25$](https://www.paypal.me/ISchwarz23/25USD) or  [Donate 25€](https://www.paypal.me/ISchwarz23/25EUR)\n\n*\"I really really want to support this project, great job!\"*  \n[Donate 50$](https://www.paypal.me/ISchwarz23/50USD) or  [Donate 50€](https://www.paypal.me/ISchwarz23/50EUR)\n\n*\"You are the man! This project saved me hours (if not days) of struggle and hard work, simply awesome!\"*  \n[Donate 100$](https://www.paypal.me/ISchwarz23/100USD) or  [Donate 100€](https://www.paypal.me/ISchwarz23/100EUR)\n---\u003e\n  \n## Features\n### Layouting\n#### Column Count\nThe provided TableView is very easy to adapt to your needs. To set the column count simple set the parameter inside your XML layout.  \n```xml\n\u003cde.codecrafters.tableview.TableView\n    xmlns:table=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/tableView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    table:tableView_columnCount=\"4\" /\u003e\n```\nA second possibility to define the column count of your TableView is to set it directly in the code.\n```java\nTableView tableView = (TableView) findViewById(R.id.tableView);\ntableView.setColumnCount(4);\n```\n\n#### Column Width\nTo define the column widths you can set a `TableColumnModel` that defines the width for each column. You can use a\npredefined `TableColumnModel` or implement your custom one.\n\n**TableColumnWeightModel**  \nThis model defines the column widths in a relative manner. You can define a weight for each column index.\nThe default column weight is 1.\n```java\nTableColumnWeightModel columnModel = new TableColumnWeightModel(4);\ncolumnModel.setColumnWeight(1, 2);\ncolumnModel.setColumnWeight(2, 2);\ntableView.setColumnModel(columnModel);\n```\n\n**TableColumnDpWidthModel**  \nThis model defines the column widths in a absolute manner. You can define a width in density-independent pixels for each column index.\nThe default column width is 100dp. You can pass a different default to the constructor.\n```java\nTableColumnDpWidthModel columnModel = new TableColumnDpWidthModel(context, 4, 200);\ncolumnModel.setColumnWidth(1, 300);\ncolumnModel.setColumnWidth(2, 250);\ntableView.setColumnModel(columnModel);\n```\n\n**TableColumnPxWidthModel**  \nThis model defines the column widths in a absolute manner. You can define a width in pixels for each column index.\nThe default column width is 200px. You can pass a different default to the constructor.\n```java\nTableColumnPxWidthModel columnModel = new TableColumnPxWidthModel(4, 350);\ncolumnModel.setColumnWidth(1, 500);\ncolumnModel.setColumnWidth(2, 600);\ntableView.setColumnModel(columnModel);\n```\n\n### Showing Data\n#### Simple Data\nFor displaying simple data like a 2D-String-Array you can use the `SimpleTableDataAdapter`. The `SimpleTableDataAdapter` will turn the given Strings to [TextViews](http://developer.android.com/reference/android/widget/TextView.html) and display them inside the TableView at the same position as previous in the 2D-String-Array.\n```java\npublic class MainActivity extends AppCompatActivity {\n    \n    private static final String[][] DATA_TO_SHOW = { { \"This\", \"is\", \"a\", \"test\" }, \n                                                     { \"and\", \"a\", \"second\", \"test\" } };\n        \n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        TableView\u003cString[]\u003e tableView = (TableView\u003cString[]\u003e) findViewById(R.id.tableView);\n        tableView.setDataAdapter(new SimpleTableDataAdapter(this, DATA_TO_SHOW));\n    }\n}        \n```\n\n#### Custom Data\nFor 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](http://developer.android.com/reference/android/view/View.html) that shall be displayed in the cell with the given *rowIndex* and *columnIndex*. Here is an example of an TableDataAdapter for a **Car** object.\n```java\npublic class CarTableDataAdapter extends TableDataAdapter\u003cCar\u003e {\n\n    public CarTableDataAdapter(Context context, List\u003cCar\u003e data) {\n        super(context, data);\n    }\n\n    @Override\n    public View getCellView(int rowIndex, int columnIndex, ViewGroup parentView) {\n        Car car = getRowData(rowIndex);\n        View renderedView = null;\n\n        switch (columnIndex) {\n            case 0:\n                renderedView = renderProducerLogo(car);\n                break;\n            case 1:\n                renderedView = renderCatName(car);\n                break;\n            case 2:\n                renderedView = renderPower(car);\n                break;\n            case 3:\n                renderedView = renderPrice(car);\n                break;\n        }\n\n        return renderedView;\n    }\n    \n}\n```\nThe `TableDataAdapter` provides several easy access methods you need to render your cell views like:\n- `getRowData()`\n- `getContext()`\n- `getLayoutInflater()`\n- `getResources()`\n\n#### Sortable Data\nIf 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](http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html) and set it to the specific column.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n    // ...\n    sortableTableView.setColumnComparator(0, new CarProducerComparator());\n}\n\nprivate static class CarProducerComparator implements Comparator\u003cCar\u003e {\n    @Override\n    public int compare(Car car1, Car car2) {\n        return car1.getProducer().getName().compareTo(car2.getProducer().getName());\n    }\n}\n```\nBy 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.\n\n#### Empty Data Indicator\nIf 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`.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n    // ...\n    tableView.setEmptyDataIndicatorView(findViewById(R.id.empty_data_indicator));\n}\n```\nThis view is automatically shown if no data is available and hidden if there is some data to show.\n\n#### Header Data\nSetting 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`.  \nIf all you want to display in the header is the column title as String (like in most cases) the `SimpleTableHeaderAdapter` will fulfil your needs.\nTo show simple Strings inside your table header, use the following code:\n```java\npublic class MainActivity extends AppCompatActivity {\n    \n    private static final String[] TABLE_HEADERS = { \"This\", \"is\", \"a\", \"test\" };\n        \n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        // ...\n        tableView.setHeaderAdapter(new SimpleTableHeaderAdapter(this, TABLE_HEADERS));\n    }\n}  \n```\nTo show Strings from resources inside your table header, use the following code:\n```java\npublic class MainActivity extends AppCompatActivity {\n    \n    private static final int[] TABLE_HEADERS = { R.string.header_col1, R.string.header_col2, R.string.header_col3 };\n        \n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        // ...\n        tableView.setHeaderAdapter(new SimpleTableHeaderAdapter(this, TABLE_HEADERS));\n    }\n}  \n```\n\n### Interaction Listening\n#### Data Click Listening\nTo listen for clicks on data items you can register a `TableDataClickListener`. The`TableView` provides a method called `addDataClickListener()` to register this listeners.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n\tsuper.onCreate(savedInstanceState);\n\tsetContentView(R.layout.activity_main);\n    // ...\n    tableView.addDataClickListener(new CarClickListener());\n}\n\nprivate class CarClickListener implements TableDataClickListener\u003cCar\u003e {\n    @Override\n    public void onDataClicked(int rowIndex, Car clickedCar) {\n        String clickedCarString = clickedCar.getProducer().getName() + \" \" + clickedCar.getName();\n        Toast.makeText(getContext(), clickedCarString, Toast.LENGTH_SHORT).show();\n    }\n}\n```\n\n#### Long Data Click Listening\nTo listen for clicks on data items you can register a `TableDataLongClickListener`. The`TableView` provides a method called `addDataLongClickListener()` to register this columns.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n\tsuper.onCreate(savedInstanceState);\n\tsetContentView(R.layout.activity_main);\n    // ...\n    tableView.addDataLongClickListener(new CarLongClickListener());\n}\n\nprivate class CarLongClickListener implements TableDataLongClickListener\u003cCar\u003e {\n    @Override\n    public boolean onDataLongClicked(int rowIndex, Car clickedCar) {\n        String clickedCarString = clickedCar.getProducer().getName() + \" \" + clickedCar.getName();\n        Toast.makeText(getContext(), clickedCarString, Toast.LENGTH_SHORT).show();\n        return true;\n    }\n}\n```\nThe 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.\n\n#### Header Click Listening\nTo listen for clicks on headers you can register a `TableHeaderClickListner`. The `TableView` provides a method called `addHeaderClickListener()` to do so.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n\tsuper.onCreate(savedInstanceState);\n\tsetContentView(R.layout.activity_main);\n    // ...\n    tableView.addHeaderClickListener(new MyHeaderClickListener());\n}\n\nprivate class MyHeaderClickListener implements TableHeaderClickListener {\n    @Override\n    public void onHeaderClicked(int columnIndex) {\n        String notifyText = \"clicked column \" + (columnIndex+1);\n        Toast.makeText(getContext(), notifyText, Toast.LENGTH_SHORT).show();\n    }\n}\n```\n\n#### On Scroll Listening\nTo listen for scroll or scroll state changes you can register a `OnScrollListener`. The `TableView` provides a method called `addOnScrollListener()` to do so.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n\tsuper.onCreate(savedInstanceState);\n\tsetContentView(R.layout.activity_main);\n    // ...\n    tableView.addOnScrollListener(new MyOnScrollListener());\n}\n\nprivate class MyOnScrollListener implements OnScrollListener {\n    @Override\n    public void onScroll(final ListView tableDataView, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) {\n        // listen for scroll changes\n    }\n        \n    @Override\n    public void onScrollStateChanged(final ListView tableDateView, final ScrollState scrollState) {\n        // listen for scroll state changes\n    }\n}\n```\nIn addition this library provides an `EndlessOnScrollListener` which allows the loading of further data when the user scrolls to the\nend of the table. Therefore you can give an row threshold which defines when the data shall be reloaded. A threshold of 3\nwould mean, that the loading shall be triggered when the user reaches the 3rd last row. The default threshold is 5.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n\tsuper.onCreate(savedInstanceState);\n\tsetContentView(R.layout.activity_main);\n    // ...\n    tableView.addOnScrollListener(new MyEndlessOnScrollListener());\n}\n\nprivate class MyEndlessOnScrollListener extends EndlessOnScrollListener {\n    \n    @Override\n    public void onReloadingTriggered(final int firstRowItem, final int visibleRowCount, final int totalRowCount) {\n        // show a loading view to the user\n        // reload some data\n        // add the loaded data to the adapter\n        // hide the loading view\n    }\n}\n```\n\n### Styling\n#### Header Styling\nThe 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.\n```xml\n\u003cde.codecrafters.tableview.TableView\n    xmlns:table=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/tableView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    table:tableView_headerColor=\"@color/primary\" /\u003e\n```\n```java\ntableView.setHeaderBackgroundColor(getResources().getColor(R.color.primary));\n```\nFor more complex header styles you can also set a **drawable** as header background using the following method.\n```java\ntableView.setHeaderBackground(R.drawable.linear_gradient);\n```\nIn 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. \n```xml\n\u003cde.codecrafters.tableview.TableView\n    xmlns:table=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/tableView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    table:tableView_headerElevation=\"10\" /\u003e\n```\n```java\ntableView.setHeaderElevation(10);\n```\n**NOTE:** *This elevation is realized with the app-compat version of elevation. So it is also applicable on pre-lollipop devices*\n  \nFor 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`.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n\tsuper.onCreate(savedInstanceState);\n\tsetContentView(R.layout.activity_main);\n    // ...\n    sortableTableView.setHeaderSortStateViewProvider(new MySortStateViewProvider());\n}\n\nprivate static class MySortStateViewProvider implements SortStateViewProvider {\n\n    private static final int NO_IMAGE_RES = -1;\n\n    @Override\n    public int getSortStateViewResource(SortState state) {\n        switch (state) {\n            case SORTABLE:\n                return R.mipmap.ic_sortable;\n            case SORTED_ASC:\n                return R.mipmap.ic_sorted_asc;\n            case SORTED_DESC:\n                return R.mipmap.ic_sorted_desc;\n            default:\n                return NO_IMAGE_RES;\n        }\n    }\n}\n```\nThere is also a factory class existing called `SortStateViewProviders` where you can get some predefined implementations of the `SortStateViewProvider`.\n\n#### Data Row Styling\nIn 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`.  \nThis Factory contains for example an alternating-table-data-row-row provider that will color rows with even index different from rows with odd index.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n    // ...\n    int colorEvenRows = getResources().getColor(R.color.white);\n    int colorOddRows = getResources().getColor(R.color.gray);\n    tableView.setDataRowBackgroundProvider(TableDataRowBackgroundProviders.alternatingRowColors(colorEvenRows, colorOddRows));\n}\n```\nIf 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.\n```java\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n    // ...\n    tableView.setDataRowBackgroundProvider(new CarPriceRowColorProvider());\n}\n    \nprivate static class CarPriceRowColorProvider implements TableDataRowBackgroundProviders\u003cCar\u003e {\n    @Override\n    public Drawable getRowBackground(final int rowIndex, final Car car) {\n        int rowColor = getResources(R.color.white);\n            \n        if(car.getPrice() \u003c 50000) {\n            rowColor = getResources(R.color.light_green);\n        } else if(car.getPrice() \u003e 100000) {\n            rowColor = getResources(R.color.light_red);\n        }\n                \n        return new ColorDrawable(rowColor);\n    }\n}\n```\nThis 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.\n  \n#### Seperator Styling  \nIf 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`.\n```java\n\u003cde.codecrafters.tableview.TableView\n    android:id=\"@+id/tableView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:divider=\"@color/black\"\n    android:dividerHeight=\"1dip\"\n    ...  /\u003e \n```\nAs for the `ListView` you can specify `divider` as a drawable and `dividerHeight` as the vertical size of the divider.  \n  \n### Swipe to Refresh\nThe TableView has a build in SwipeToRefresh action. By default this is disabled, but you can easily enable it using the follwing line.\n```java\ntableView.setSwipeToRefreshEnabled( true );\n```\nThis 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.\n```java\ncarTableView.setSwipeToRefreshListener(new SwipeToRefreshListener() {\n    @Override\n    public void onRefresh(final RefreshIndicator refreshIndicator) {\n        // your async refresh action goes here\n    }\n});\n```\nThe 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()`.\n  \n### Hide Table Header\nTo 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.\nTo make the header visible again just call `setHeaderVisible( true )` or `setHeaderVisible( true, 1000 )`.\n\n#### Hide/Show Table Header on Scroll\nTo hide an show the table header when the user is scrolling, just use the `TableHeaderCollapseOnScrollListener`.\n```java\ncarTableView.setOnScrollListener(new TableHeaderCollapseOnScrollListener( carTableView ));\n```\nBy 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.\nTo change this you can call `TableHeaderCollapseOnScrollListener#setRowOffset( int )` with your preferred offset.\nTo enable animation you can call `TableHeaderCollapseOnScrollListener#setAnimationDuration( int )` with your preferred animation duration.\n  \n### State Persistence\nThe 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.\n```java\ntableView.setSaveEnabled( false );\n```  \n  \n## License\n*Copyright 2015 Ingo Schwarz*  \n  \nLicensed 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\n\n```\nhttp://www.apache.org/licenses/LICENSE-2.0\n```\n\nUnless 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.\n","funding_links":["https://www.paypal.me/ISchwarz23/5USD","https://www.paypal.me/ISchwarz23/5EUR","https://www.paypal.me/ISchwarz23/10USD","https://www.paypal.me/ISchwarz23/10EUR","https://www.paypal.me/ISchwarz23/15USD","https://www.paypal.me/ISchwarz23/15EUR","https://www.paypal.me/ISchwarz23/25USD","https://www.paypal.me/ISchwarz23/25EUR","https://www.paypal.me/ISchwarz23/50USD","https://www.paypal.me/ISchwarz23/50EUR","https://www.paypal.me/ISchwarz23/100USD","https://www.paypal.me/ISchwarz23/100EUR"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fischwarz23%2Fsortabletableview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fischwarz23%2Fsortabletableview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fischwarz23%2Fsortabletableview/lists"}