├── res
├── drawable
│ ├── icon.png
│ └── accessory_disclosure.xml
├── drawable-hdpi
│ ├── accessory_disclosure_white.png
│ └── accessory_disclosure_default.png
├── drawable-ldpi
│ ├── accessory_disclosure_white.png
│ └── accessory_disclosure_default.png
├── drawable-mdpi
│ ├── accessory_disclosure_white.png
│ └── accessory_disclosure_default.png
├── values
│ ├── strings.xml
│ ├── styles.xml
│ └── colors.xml
├── color
│ └── text_color_selector.xml
└── layout
│ ├── table_header.xml
│ └── table_cell.xml
├── src
└── fr
│ └── days
│ └── android
│ └── uitableview
│ ├── model
│ ├── AccessoryType.java
│ ├── UITableItem.java
│ ├── UITableHeaderItem.java
│ ├── UITableCellItem.java
│ └── IndexPath.java
│ ├── listener
│ ├── OnCellClickListener.java
│ ├── OnHeaderClickListener.java
│ ├── OnCellLongClickListener.java
│ ├── OnHeaderLongClickListener.java
│ └── OnCellAccessoryClickListener.java
│ ├── adapter
│ ├── UITableViewInternalAccessoryListener.java
│ ├── UITableViewAdapter.java
│ └── UITableViewAdapterInternal.java
│ ├── view
│ ├── UITableItemView.java
│ ├── UITableHeaderView.java
│ ├── UITableView.java
│ └── UITableCellView.java
│ └── drawable
│ └── UITableCellDrawable.java
├── .gitignore
├── AndroidManifest.xml
├── project.properties
├── proguard-project.txt
├── pom.xml
└── README.md
/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable/icon.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/accessory_disclosure_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable-hdpi/accessory_disclosure_white.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/accessory_disclosure_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable-ldpi/accessory_disclosure_white.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/accessory_disclosure_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable-mdpi/accessory_disclosure_white.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/accessory_disclosure_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable-hdpi/accessory_disclosure_default.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/accessory_disclosure_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable-ldpi/accessory_disclosure_default.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/accessory_disclosure_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DayS/uitableview4android/HEAD/res/drawable-mdpi/accessory_disclosure_default.png
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/model/AccessoryType.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.model;
2 |
3 | public enum AccessoryType {
4 | NONE, DISCLOSURE
5 | // , DETAIL, CHECKMARK
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS junk files
2 | .DS_Store
3 | [Tt]humbs.db
4 |
5 | # Temp files
6 | *~
7 |
8 | # Project files
9 | .class
10 | .classpath
11 | .project
12 | .settings/
13 | target/
14 | bin/
15 | gen/
16 |
17 | .springBeans
18 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Android-uitableview
4 | Hello world!
5 | Settings
6 | MainActivity
7 |
8 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/listener/OnCellClickListener.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.listener;
2 |
3 | import fr.days.android.uitableview.model.IndexPath;
4 |
5 | public interface OnCellClickListener {
6 |
7 | void onCellClick(IndexPath indexPath);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/listener/OnHeaderClickListener.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.listener;
2 |
3 | import fr.days.android.uitableview.model.IndexPath;
4 |
5 | public interface OnHeaderClickListener {
6 |
7 | void onHeaderClick(IndexPath indexPath);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/model/UITableItem.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.model;
2 |
3 |
4 | public abstract class UITableItem {
5 |
6 | public String title;
7 |
8 | public UITableItem(String title) {
9 | super();
10 | this.title = title;
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/listener/OnCellLongClickListener.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.listener;
2 |
3 | import fr.days.android.uitableview.model.IndexPath;
4 |
5 | public interface OnCellLongClickListener {
6 |
7 | boolean onCellLongClick(IndexPath indexPath);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/listener/OnHeaderLongClickListener.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.listener;
2 |
3 | import fr.days.android.uitableview.model.IndexPath;
4 |
5 | public interface OnHeaderLongClickListener {
6 |
7 | boolean onHeaderLongClick(IndexPath indexPath);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/listener/OnCellAccessoryClickListener.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.listener;
2 |
3 | import fr.days.android.uitableview.model.IndexPath;
4 |
5 | public interface OnCellAccessoryClickListener {
6 |
7 | void onCellAccessoryClick(IndexPath indexPath);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/model/UITableHeaderItem.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.model;
2 |
3 | public class UITableHeaderItem extends UITableItem {
4 |
5 | public UITableHeaderItem() {
6 | super(null);
7 | }
8 |
9 | public UITableHeaderItem(String title) {
10 | super(title);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/res/color/text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/drawable/accessory_disclosure.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/adapter/UITableViewInternalAccessoryListener.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.adapter;
2 |
3 | import fr.days.android.uitableview.model.IndexPath;
4 |
5 | /**
6 | * This listener is used to notify the {@link UITableViewAdapterInternal} that user clicked on an accessory and then notify the application
7 | *
8 | * @author dvilleneuve
9 | *
10 | */
11 | public interface UITableViewInternalAccessoryListener {
12 |
13 | void onCellAccessoryClick(IndexPath indexPath);
14 |
15 | boolean onCellAccessoryLongClick(IndexPath indexPath);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-10
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/model/UITableCellItem.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.model;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.drawable.Drawable;
5 |
6 | public class UITableCellItem extends UITableItem {
7 |
8 | public String subtitle;
9 |
10 | public int imageInt;
11 | public Drawable imageDrawable;
12 | public Bitmap imageBitmap;
13 |
14 | public AccessoryType accessory = AccessoryType.NONE;
15 | public Drawable accessoryDrawable;
16 |
17 | public UITableCellItem() {
18 | super(null);
19 | }
20 |
21 | public UITableCellItem(String title, String subtitle) {
22 | super(title);
23 | this.subtitle = subtitle;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/view/UITableItemView.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.view;
2 |
3 | import android.content.Context;
4 | import android.widget.LinearLayout;
5 | import fr.days.android.uitableview.model.IndexPath;
6 |
7 | public class UITableItemView extends LinearLayout {
8 |
9 | protected IndexPath indexPath;
10 |
11 | public UITableItemView(Context context, IndexPath indexPath) {
12 | super(context);
13 | this.indexPath = indexPath;
14 | }
15 |
16 | /**
17 | * Reset the {@link IndexPath} of this cell and so his background according to his position.
18 | *
19 | * @param indexPath
20 | */
21 | public void setIndexPath(IndexPath indexPath) {
22 | this.indexPath = indexPath;
23 | }
24 |
25 | public IndexPath getIndexPath() {
26 | return indexPath;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #FFD3D3D3
6 |
7 |
8 | #FFFFFFFF
9 | #FFFFFFFF
10 |
11 |
12 | #FF3590C4
13 | #FF2570BA
14 |
15 |
16 | #000000
17 | #FFFFFF
18 |
19 |
20 | #4C566C
21 |
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/res/layout/table_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
24 |
25 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/adapter/UITableViewAdapter.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.adapter;
2 |
3 | import android.content.Context;
4 | import fr.days.android.uitableview.model.IndexPath;
5 | import fr.days.android.uitableview.model.UITableCellItem;
6 | import fr.days.android.uitableview.model.UITableHeaderItem;
7 | import fr.days.android.uitableview.view.UITableCellView;
8 | import fr.days.android.uitableview.view.UITableHeaderView;
9 |
10 | public abstract class UITableViewAdapter {
11 |
12 | public int numberOfGroups() {
13 | return 1;
14 | }
15 |
16 | public int numberOfRows(int group) {
17 | return 0;
18 | }
19 |
20 | public abstract UITableHeaderItem headerItemForGroup(Context context, IndexPath indexPath);
21 |
22 | public abstract UITableCellItem cellItemForRow(Context context, IndexPath indexPath);
23 |
24 | public abstract UITableHeaderView headerViewForGroup(Context context, IndexPath indexPath, UITableHeaderItem cellItem, UITableHeaderView convertView);
25 |
26 | public abstract UITableCellView cellViewForRow(Context context, IndexPath indexPath, UITableCellItem cellItem, UITableCellView convertView);
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/view/UITableHeaderView.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.view;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.widget.TextView;
6 | import fr.days.android.uitableview.R;
7 | import fr.days.android.uitableview.model.IndexPath;
8 |
9 | public class UITableHeaderView extends UITableItemView {
10 |
11 | private TextView titleView;
12 |
13 | public UITableHeaderView(Context context, IndexPath indexPath) {
14 | super(context, indexPath);
15 |
16 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
17 | if (inflater != null) {
18 | inflater.inflate(R.layout.table_header, this);
19 | }
20 |
21 | titleView = (TextView) findViewById(R.id.title);
22 | }
23 |
24 | public UITableHeaderView(Context context, IndexPath indexPath, String title) {
25 | this(context, indexPath);
26 | setTitle(title);
27 | }
28 |
29 | public TextView getTitleView() {
30 | return titleView;
31 | }
32 |
33 | public String getTitle() {
34 | return titleView.getText().toString();
35 | }
36 |
37 | public void setTitle(String title) {
38 | if (title == null) {
39 | titleView.setVisibility(GONE);
40 | } else {
41 | titleView.setVisibility(VISIBLE);
42 | }
43 | titleView.setText(title);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/drawable/UITableCellDrawable.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.drawable;
2 |
3 | import android.graphics.drawable.GradientDrawable;
4 | import android.graphics.drawable.GradientDrawable.Orientation;
5 | import android.graphics.drawable.StateListDrawable;
6 |
7 | /**
8 | * This class will ceate a the cell style at runtime. It's necessary to allow multiple background color in cells
9 | *
10 | * @author dvilleneuve
11 | *
12 | */
13 | public class UITableCellDrawable extends StateListDrawable {
14 |
15 | public UITableCellDrawable(float topRadius, float bottomRadius, int[] colorDefault, int[] colorPressed, int borderColor) {
16 | addState(new int[] { -android.R.attr.state_pressed }, createGradientDrawable(topRadius, bottomRadius, colorDefault, borderColor));
17 | addState(new int[] { android.R.attr.state_pressed }, createGradientDrawable(topRadius, bottomRadius, colorPressed, borderColor));
18 | }
19 |
20 | private GradientDrawable createGradientDrawable(float topRadius, float bottomRadius, int[] color, int borderColor) {
21 | GradientDrawable gradientDrawable = new GradientDrawable(Orientation.TOP_BOTTOM, color);
22 | gradientDrawable.setShape(GradientDrawable.RECTANGLE);
23 | gradientDrawable.setGradientRadius(270.0f);
24 | gradientDrawable.setStroke(1, borderColor);
25 | gradientDrawable.setCornerRadii(getRadii(topRadius, bottomRadius));
26 |
27 | return gradientDrawable;
28 | }
29 |
30 | private float[] getRadii(float top, float bottom) {
31 | return new float[] { top, top, //
32 | top, top, //
33 | bottom, bottom, //
34 | bottom, bottom //
35 | };
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/model/IndexPath.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.model;
2 |
3 | /**
4 | * This class represent an item by the group to which it belongs and his position in this group.
5 | */
6 | public class IndexPath {
7 | private final int position;
8 | private final int group;
9 | private final int row;
10 | private final int groupsCount;
11 | private final int rowsCount;
12 |
13 | public IndexPath(int position, int group, int groupCount) {
14 | this(position, group, -1, groupCount, 0);
15 | }
16 |
17 | public IndexPath(int position, int group, int row, int groupsCount, int rowsCount) {
18 | this.position = position;
19 | this.group = group;
20 | this.row = row;
21 | this.groupsCount = groupsCount;
22 | this.rowsCount = rowsCount;
23 | }
24 |
25 | public int getPosition() {
26 | return position;
27 | }
28 |
29 | public int getGroup() {
30 | return group;
31 | }
32 |
33 | public int getRow() {
34 | return row;
35 | }
36 |
37 | public int getGroupsCount() {
38 | return groupsCount;
39 | }
40 |
41 | public int getRowsCount() {
42 | return rowsCount;
43 | }
44 |
45 | public boolean isHeader() {
46 | return row == -1;
47 | }
48 |
49 | public boolean isFirstGroup() {
50 | return group == 0;
51 | }
52 |
53 | public boolean isLastGroup() {
54 | return group == groupsCount - 1;
55 | }
56 |
57 | public boolean isFirstCellOfGroup() {
58 | return row == 0;
59 | }
60 |
61 | public boolean isLastCellOfGroup() {
62 | return row == rowsCount - 1;
63 | }
64 |
65 | public boolean isLastCell() {
66 | return isLastGroup() && isLastCellOfGroup();
67 | }
68 |
69 | public boolean isStateEquals(IndexPath indexPath) {
70 | if (indexPath == null)
71 | return false;
72 | if (indexPath == this)
73 | return true;
74 |
75 | if (isFirstCellOfGroup() && !indexPath.isFirstCellOfGroup())
76 | return false;
77 | else if (isLastCellOfGroup() && !indexPath.isLastCellOfGroup())
78 | return false;
79 | else {
80 | if (indexPath.isFirstCellOfGroup() || indexPath.isLastCellOfGroup())
81 | return false;
82 | }
83 | return true;
84 | }
85 |
86 | @Override
87 | public String toString() {
88 | return "IndexPath [position=" + position + ", group=" + group + "/" + groupsCount + ", row=" + row + "/" + rowsCount + "]";
89 | }
90 | }
--------------------------------------------------------------------------------
/res/layout/table_cell.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
27 |
28 |
37 |
38 |
48 |
49 |
50 |
59 |
60 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | fr.days.android
5 | uitableview4android
6 | 1.1-SNAPSHOT
7 | apklib
8 |
9 |
10 | scm:git|ssh://git@github.com/DayS/uitableview4android.git
11 | HEAD
12 |
13 |
14 |
15 | UTF-8
16 | 1.6
17 |
18 | 2.3.2
19 | 2.3.2
20 | 3.3.0
21 |
22 | 2.3.3
23 | 10
24 |
25 |
26 |
27 |
28 |
29 | com.google.android
30 | android
31 | ${android.sdk.version}
32 | provided
33 |
34 |
35 |
36 |
37 | src
38 |
39 |
40 | maven-compiler-plugin
41 | ${maven.compiler.plugin.version}
42 |
43 | ${java.version}
44 | ${java.version}
45 |
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-release-plugin
50 | ${maven-release-plugin.version}
51 |
52 | v@{project.version}
53 |
54 |
55 |
56 | com.jayway.maven.plugins.android.generation2
57 | android-maven-plugin
58 | ${android.maven.plugin.version}
59 | true
60 |
61 | true
62 |
63 | ${env.ANDROID_HOME}
64 | ${android.sdk.level}
65 |
66 | false
67 |
68 |
69 | -Xmx512m
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/view/UITableView.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.graphics.drawable.ColorDrawable;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.widget.AdapterView;
9 | import android.widget.ListView;
10 | import fr.days.android.uitableview.adapter.UITableViewAdapter;
11 | import fr.days.android.uitableview.adapter.UITableViewAdapterInternal;
12 | import fr.days.android.uitableview.adapter.UITableViewInternalAccessoryListener;
13 | import fr.days.android.uitableview.listener.OnCellAccessoryClickListener;
14 | import fr.days.android.uitableview.listener.OnCellClickListener;
15 | import fr.days.android.uitableview.listener.OnCellLongClickListener;
16 | import fr.days.android.uitableview.listener.OnHeaderClickListener;
17 | import fr.days.android.uitableview.listener.OnHeaderLongClickListener;
18 | import fr.days.android.uitableview.model.IndexPath;
19 |
20 | public class UITableView extends ListView implements android.widget.AdapterView.OnItemClickListener, android.widget.AdapterView.OnItemLongClickListener, UITableViewInternalAccessoryListener {
21 |
22 | private UITableViewAdapterInternal tableViewAdapterInternal;
23 | private OnCellClickListener onCellClickListener;
24 | private OnCellLongClickListener onCellLongClickListener;
25 | private OnCellAccessoryClickListener onCellAccessoryClickListener;
26 | private OnHeaderClickListener onHeaderClickListener;
27 | private OnHeaderLongClickListener onHeaderLongClickListener;
28 |
29 | public UITableView(Context context) {
30 | super(context);
31 | init();
32 | }
33 |
34 | public UITableView(Context context, AttributeSet attrs, int defStyle) {
35 | super(context, attrs, defStyle);
36 | init();
37 | }
38 |
39 | public UITableView(Context context, AttributeSet attrs) {
40 | super(context, attrs);
41 | init();
42 | }
43 |
44 | private void init() {
45 | setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
46 | setBackgroundColor(Color.parseColor("#f1f6f9"));
47 | setDivider(new ColorDrawable(Color.TRANSPARENT));
48 | setSelector(new ColorDrawable(Color.TRANSPARENT));
49 |
50 | // Init internal listeners
51 | setOnItemClickListener(this);
52 | setOnItemLongClickListener(this);
53 | }
54 |
55 | public void setAdapter(UITableViewAdapter tableViewAdapter) {
56 | tableViewAdapterInternal = new UITableViewAdapterInternal(getContext(), tableViewAdapter);
57 | tableViewAdapterInternal.setInternalAccessoryListener(this);
58 | super.setAdapter(tableViewAdapterInternal);
59 | }
60 |
61 | public void setOnCellClickListener(OnCellClickListener tableCellListener) {
62 | this.onCellClickListener = tableCellListener;
63 | }
64 |
65 | public void setOnCellLongClickListener(OnCellLongClickListener onCellLongClickListener) {
66 | this.onCellLongClickListener = onCellLongClickListener;
67 | }
68 |
69 | public void setOnCellAccessoryClickListener(OnCellAccessoryClickListener onCellAccessoryClickListener) {
70 | this.onCellAccessoryClickListener = onCellAccessoryClickListener;
71 | }
72 |
73 | public void setOnHeaderClickListener(OnHeaderClickListener onHeaderClickListener) {
74 | this.onHeaderClickListener = onHeaderClickListener;
75 | }
76 |
77 | public void setOnHeaderLongClickListener(OnHeaderLongClickListener onHeaderLongClickListener) {
78 | this.onHeaderLongClickListener = onHeaderLongClickListener;
79 | }
80 |
81 | @Override
82 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
83 | IndexPath indexPath = tableViewAdapterInternal.retrieveIndexPathByPosition(position);
84 | if (indexPath != null) {
85 | if (indexPath.isHeader()) {
86 | if (onHeaderClickListener != null) {
87 | onHeaderClickListener.onHeaderClick(indexPath);
88 | }
89 | } else {
90 | if (onCellClickListener != null) {
91 | onCellClickListener.onCellClick(indexPath);
92 | }
93 | }
94 | }
95 | }
96 |
97 | @Override
98 | public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
99 | IndexPath indexPath = tableViewAdapterInternal.retrieveIndexPathByPosition(position);
100 | if (indexPath != null) {
101 | if (indexPath.isHeader()) {
102 | if (onHeaderLongClickListener != null) {
103 | return onHeaderLongClickListener.onHeaderLongClick(indexPath);
104 | }
105 | } else {
106 | if (onCellLongClickListener != null) {
107 | return onCellLongClickListener.onCellLongClick(indexPath);
108 | }
109 | }
110 | }
111 | return false;
112 | }
113 |
114 | @Override
115 | public void onCellAccessoryClick(IndexPath indexPath) {
116 | if (indexPath != null && !indexPath.isHeader()) {
117 | // Trigger the accessory listener if set, else tigger the cell listener
118 | if (onCellAccessoryClickListener != null) {
119 | onCellAccessoryClickListener.onCellAccessoryClick(indexPath);
120 | } else if (onCellClickListener != null) {
121 | onCellClickListener.onCellClick(indexPath);
122 | }
123 | }
124 | }
125 |
126 | @Override
127 | public boolean onCellAccessoryLongClick(IndexPath indexPath) {
128 | if (indexPath != null && !indexPath.isHeader()) {
129 | if (onCellLongClickListener != null) {
130 | return onCellLongClickListener.onCellLongClick(indexPath);
131 | }
132 | }
133 | return false;
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # What is UITableView4Android ?
2 |
3 | UITableView4Android is an Android library providing a customized ListView with the look & field and behavior of UITableView on iOS.
4 |
5 | **Note: This is not a recommended Android UI pattern! This repo is only here in case your client insist to do this.**
6 |
7 | # Motivation
8 |
9 | Some companies are asking for mobile applications that must have the same appearance both on Android and iOS. And of course, iOS is almost always the version to fit...
10 | List views are one the most difficult component to adapt on Android because of corners and borders to set correctly.
11 |
12 | # Usage example
13 |
14 | ## 1. Declare layout
15 |
16 | Add the UITableView in your layout :
17 | ```xml
18 |
24 |
25 | ```
26 |
27 | ## 2. Implement the adapter
28 |
29 | This `UITableView` is a sub-class of Android ListView and need an implementation of `UITableViewAdapter`.
30 |
31 | ```java
32 | class SimpleUITableViewAdapter extends UITableViewAdapter {
33 |
34 | private int[] color_line1_default;
35 | private int[] color_line2_default;
36 | private int[] color_line1_pressed;
37 | private int[] color_line2_pressed;
38 |
39 | public SimpleUITableViewAdapter() {
40 | // Prepare two sets of colors for odd and even lines
41 | color_line1_default = new int[] { getResources().getColor(R.color.base_start_color_line1_default), getResources().getColor(R.color.base_end_color_line1_default) };
42 | color_line2_default = new int[] { getResources().getColor(R.color.base_start_color_line2_default), getResources().getColor(R.color.base_end_color_line2_default) };
43 | color_line1_pressed = new int[] { getResources().getColor(R.color.base_start_color_line1_pressed), getResources().getColor(R.color.base_end_color_line1_pressed) };
44 | color_line2_pressed = new int[] { getResources().getColor(R.color.base_start_color_line2_pressed), getResources().getColor(R.color.base_end_color_line2_pressed) };
45 | }
46 |
47 | @Override
48 | public int numberOfGroups() {
49 | return 4;
50 | }
51 |
52 | @Override
53 | public int numberOfRows(int group) {
54 | return (group + 1) * 2;
55 | }
56 |
57 | @Override
58 | public UITableHeaderItem headerItemForGroup(Context context, IndexPath indexPath) {
59 | return new UITableHeaderItem("Group " + indexPath.getGroup());
60 | }
61 |
62 | @Override
63 | public UITableCellItem cellItemForRow(Context context, IndexPath indexPath) {
64 | String title = "Cell number " + indexPath.getRow() + " in group " + indexPath.getGroup();
65 | String subtitle = (indexPath.getRow() % 2 == 0) ? "Subtitle " + indexPath.getRow() : null;
66 | return new UITableCellItem(title, subtitle);
67 | }
68 |
69 | @Override
70 | public UITableHeaderView headerViewForGroup(Context context, IndexPath indexPath, UITableHeaderItem headerItem, UITableHeaderView convertView) {
71 | UITableHeaderView headerView;
72 | if (convertView == null) {
73 | // If the recycled view is null, we just creating one
74 | headerView = new UITableHeaderView(context, indexPath);
75 | } else {
76 | headerView = (UITableHeaderView) convertView;
77 | }
78 |
79 | headerView.setTitle(headerItem.title);
80 |
81 | return headerView;
82 | }
83 |
84 | @Override
85 | public UITableCellView cellViewForRow(Context context, IndexPath indexPath, UITableCellItem cellItem, UITableCellView convertView) {
86 | UITableCellView cellView;
87 | if (convertView == null) {
88 | // If the recycled view is null, we just creating one with cell's commons parameters
89 | cellView = new UITableCellView(context, indexPath);
90 | cellView.setMinimumHeight(80);
91 | cellView.setAccessory(AccessoryType.DISCLOSURE);
92 | } else {
93 | cellView = (UITableCellView) convertView;
94 | }
95 |
96 | cellView.setTitle(cellItem.title);
97 | cellView.setSubtitle(cellItem.subtitle);
98 |
99 | // Set alternated background color
100 | if (indexPath.getRow() % 2 == 0) {
101 | cellView.setBackgroundColor(color_line1_default, color_line1_pressed);
102 | } else {
103 | cellView.setBackgroundColor(color_line2_default, color_line2_pressed);
104 | }
105 |
106 | return cellView;
107 | }
108 | }
109 | ```
110 |
111 | ## 3. Add listeners
112 |
113 | Some listeners are avaible to handle click and long click on cells, headers and accessory's cells. Let's implement them all on our `SimpleUITableViewAdapter`.
114 |
115 | ```java
116 | @Override
117 | public void onCellClick(IndexPath indexPath) {
118 | Toast.makeText(getApplicationContext(), "Cell clicked : " + indexPath, 1000).show();
119 | }
120 |
121 | @Override
122 | public boolean onCellLongClick(IndexPath indexPath) {
123 | Toast.makeText(getApplication(), "Cell long clicked : " + indexPath, 1000).show();
124 | return indexPath.getRow() % 2 == 0; // Consume the long click one row out of two
125 | }
126 |
127 | @Override
128 | public void onCellAccessoryClick(IndexPath indexPath) {
129 | Toast.makeText(getApplication(), "Cell accessory clicked : " + indexPath, 1000).show();
130 | }
131 |
132 | @Override
133 | public void onHeaderClick(IndexPath indexPath) {
134 | Toast.makeText(getApplicationContext(), "Header clicked : " + indexPath, 1000).show();
135 | }
136 |
137 | @Override
138 | public boolean onHeaderLongClick(IndexPath indexPath) {
139 | Toast.makeText(getApplicationContext(), "Header long clicked : " + indexPath, 1000).show();
140 | return indexPath.getGroup() % 2 == 0; // Consume the long click one row out of two
141 | }
142 | ```
143 |
144 | ## 4. Configure UITableView
145 |
146 | Now, we have an implementation of `UITableViewAdapter` with all listeners added. It only remains to configure the `UITableView`.
147 |
148 | ```java
149 | SimpleUITableViewAdapter tableViewAdapter = new SimpleUITableViewAdapter();
150 | tableView = (UITableView) findViewById(R.id.listView);
151 | tableView.setAdapter(tableViewAdapter);
152 | tableView.setOnCellClickListener(tableViewAdapter);
153 | tableView.setOnCellLongClickListener(tableViewAdapter);
154 | tableView.setOnCellAccessoryClickListener(tableViewAdapter);
155 | tableView.setOnHeaderClickListener(tableViewAdapter);
156 | tableView.setOnHeaderLongClickListener(tableViewAdapter);
157 | ```
158 |
159 | # Result
160 |
161 | And here is the result.
162 |
163 | 
164 |
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/adapter/UITableViewAdapterInternal.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.adapter;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import android.content.Context;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import fr.days.android.uitableview.model.IndexPath;
11 | import fr.days.android.uitableview.model.UITableCellItem;
12 | import fr.days.android.uitableview.model.UITableHeaderItem;
13 | import fr.days.android.uitableview.view.UITableCellView;
14 | import fr.days.android.uitableview.view.UITableHeaderView;
15 |
16 | /**
17 | * Internal adapter used by Android ListView.
18 | *
19 | * @author dvilleneuve
20 | *
21 | */
22 | public class UITableViewAdapterInternal extends BaseAdapter {
23 |
24 | private static final int VIEW_TYPE_HEADER = 0;
25 | private static final int VIEW_TYPE_CELL = 1;
26 |
27 | private final Context context;
28 | private final UITableViewAdapter tableViewAdapter;
29 |
30 | private UITableViewInternalAccessoryListener internalAccessoryListener;
31 | private Map indexPaths = new HashMap();
32 |
33 | /**
34 | * @param uiTableViewAdapter
35 | */
36 | public UITableViewAdapterInternal(Context context, UITableViewAdapter uiTableViewAdapter) {
37 | this.context = context;
38 | this.tableViewAdapter = uiTableViewAdapter;
39 | }
40 |
41 | @Override
42 | public int getViewTypeCount() {
43 | return 2;
44 | }
45 |
46 | @Override
47 | public int getItemViewType(int position) {
48 | IndexPath indexPath = retrieveIndexPathByPosition(position);
49 | if (indexPath == null)
50 | return IGNORE_ITEM_VIEW_TYPE;
51 | else if (indexPath.isHeader())
52 | return VIEW_TYPE_HEADER;
53 | else
54 | return VIEW_TYPE_CELL;
55 | }
56 |
57 | @Override
58 | public int getCount() {
59 | int numberOfGroups = tableViewAdapter.numberOfGroups();
60 | int countItems = numberOfGroups;
61 | for (int group = 0; group < numberOfGroups; group++) {
62 | countItems += tableViewAdapter.numberOfRows(group);
63 | }
64 | return countItems;
65 | }
66 |
67 | @Override
68 | public Object getItem(int position) {
69 | IndexPath indexPath = retrieveIndexPathByPosition(position);
70 | if (indexPath == null) {
71 | throw new NullPointerException("Unable to retrieve index path for position " + position);
72 | } else if (indexPath.isHeader()) {
73 | return getHeaderItem(indexPath);
74 | } else {
75 | return tableViewAdapter.cellItemForRow(context, indexPath);
76 | }
77 | }
78 |
79 | public UITableHeaderItem getHeaderItem(IndexPath indexPath) {
80 | UITableHeaderItem headerItem = tableViewAdapter.headerItemForGroup(context, indexPath);
81 | return headerItem != null ? headerItem : new UITableHeaderItem();
82 | }
83 |
84 | @Override
85 | public long getItemId(int position) {
86 | return position;
87 | }
88 |
89 | @Override
90 | public View getView(int position, View convertView, ViewGroup parent) {
91 | IndexPath indexPath = retrieveIndexPathByPosition(position);
92 |
93 | if (indexPath == null) {
94 | throw new NullPointerException("Unable to retrieve index path for position " + position);
95 | } else if (indexPath.isHeader()) {
96 | if (!(convertView instanceof UITableHeaderView)) {
97 | convertView = null;
98 | }
99 | if (convertView != null) {
100 | UITableHeaderView tableHeaderView = (UITableHeaderView) convertView;
101 | tableHeaderView.setIndexPath(indexPath);
102 | }
103 | UITableHeaderItem headerItem = getHeaderItem(indexPath);
104 | UITableHeaderView headerView = tableViewAdapter.headerViewForGroup(context, indexPath, headerItem, (UITableHeaderView) convertView);
105 | return headerView;
106 | } else {
107 | if (!(convertView instanceof UITableCellView)) {
108 | convertView = null;
109 | }
110 | if (convertView != null) {
111 | // Configure the recycling view by reseting his indexpath and background
112 | UITableCellView tableCellView = (UITableCellView) convertView;
113 | tableCellView.setIndexPath(indexPath);
114 | if (!tableCellView.getIndexPath().isStateEquals(indexPath)) {
115 | tableCellView.setDefaultBackgroundColor();
116 | }
117 | }
118 | UITableCellItem cellItem = tableViewAdapter.cellItemForRow(context, indexPath);
119 | UITableCellView cellView = tableViewAdapter.cellViewForRow(context, indexPath, cellItem, (UITableCellView) convertView);
120 | cellView.setInternalAccessoryListener(internalAccessoryListener);
121 | return cellView;
122 | }
123 | }
124 |
125 | /**
126 | * Retrieve an {@link IndexPath} according to a ListView's item position.
127 | *
128 | * @param position
129 | * @return An {@link IndexPath} if position is valid, null else
130 | */
131 | public IndexPath retrieveIndexPathByPosition(final int position) {
132 | IndexPath indexPath = indexPaths.get(position);
133 | if (indexPath == null) {
134 | int numberOfGroups = tableViewAdapter.numberOfGroups();
135 |
136 | if (position == 0) { // Shortcut for the first item
137 | indexPath = new IndexPath(0, 0, numberOfGroups);
138 |
139 | } else {
140 | int numberOfRowsBefore = 0;
141 | for (int group = 0; group < numberOfGroups; group++) {
142 | int numberOfRows = tableViewAdapter.numberOfRows(group);
143 |
144 | // Header
145 | if (position == numberOfRowsBefore) {
146 | indexPath = new IndexPath(position, group, numberOfGroups);
147 | break;
148 | }
149 | // Cell
150 | if (position <= numberOfRowsBefore + numberOfRows) {
151 | indexPath = new IndexPath(position, group, position - numberOfRowsBefore - 1, numberOfGroups, numberOfRows);
152 | break;
153 | }
154 |
155 | // This position doesn't fit to this group, see the next one
156 | numberOfRowsBefore += numberOfRows + 1; // rows + header
157 | }
158 | }
159 |
160 | indexPaths.put(position, indexPath);
161 | }
162 | return indexPath;
163 | }
164 |
165 | @Override
166 | public void notifyDataSetChanged() {
167 | indexPaths.clear();
168 | super.notifyDataSetChanged();
169 | }
170 |
171 | @Override
172 | public void notifyDataSetInvalidated() {
173 | indexPaths.clear();
174 | super.notifyDataSetInvalidated();
175 | }
176 |
177 | public UITableViewInternalAccessoryListener getInternalAccessoryListener() {
178 | return internalAccessoryListener;
179 | }
180 |
181 | public void setInternalAccessoryListener(UITableViewInternalAccessoryListener internalAccessoryListener) {
182 | this.internalAccessoryListener = internalAccessoryListener;
183 | }
184 |
185 | }
--------------------------------------------------------------------------------
/src/fr/days/android/uitableview/view/UITableCellView.java:
--------------------------------------------------------------------------------
1 | package fr.days.android.uitableview.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Rect;
6 | import android.graphics.drawable.Drawable;
7 | import android.graphics.drawable.InsetDrawable;
8 | import android.text.TextUtils;
9 | import android.view.LayoutInflater;
10 | import android.view.TouchDelegate;
11 | import android.view.View;
12 | import android.widget.ImageView;
13 | import android.widget.TextView;
14 | import fr.days.android.uitableview.R;
15 | import fr.days.android.uitableview.adapter.UITableViewInternalAccessoryListener;
16 | import fr.days.android.uitableview.drawable.UITableCellDrawable;
17 | import fr.days.android.uitableview.model.AccessoryType;
18 | import fr.days.android.uitableview.model.IndexPath;
19 |
20 | public class UITableCellView extends UITableItemView {
21 |
22 | private static final int INSET = 10;
23 |
24 | private static int[] colorLineDefault;
25 | private static int[] colorLinePressed;
26 | private static int borderColor = Integer.MIN_VALUE;
27 |
28 | private ImageView imageView;
29 | private TextView titleView;
30 | private TextView subtitleView;
31 | private ImageView accessoryView;
32 | private UITableViewInternalAccessoryListener internalAccessoryListener;
33 |
34 | public UITableCellView(Context context, IndexPath indexPath) {
35 | super(context, indexPath);
36 |
37 | if (borderColor == Integer.MIN_VALUE) {
38 | borderColor = getColor(R.color.cell_border);
39 | colorLineDefault = new int[] { getResources().getColor(R.color.base_start_color_line_default), getResources().getColor(R.color.base_end_color_line_default) };
40 | colorLinePressed = new int[] { getResources().getColor(R.color.base_start_color_line_pressed), getResources().getColor(R.color.base_end_color_line_pressed) };
41 | }
42 |
43 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
44 | if (inflater != null) {
45 | inflater.inflate(R.layout.table_cell, this);
46 | }
47 |
48 | imageView = (ImageView) findViewById(R.id.image);
49 | titleView = (TextView) findViewById(R.id.title);
50 | subtitleView = (TextView) findViewById(R.id.subtitle);
51 | accessoryView = (ImageView) findViewById(R.id.accessory);
52 |
53 | // Set default color
54 | setDefaultBackgroundColor();
55 |
56 | // Increase the touchable area for accessoryView
57 | post(getTouchDelegateAction(this, accessoryView, 30, 30, 30, 30));
58 | }
59 |
60 | public UITableCellView(Context context, IndexPath indexPath, String title, String subtitle) {
61 | this(context, indexPath);
62 | setTitle(title);
63 | setSubtitle(subtitle);
64 | }
65 |
66 | private int getColor(int colorId) {
67 | return getResources().getColor(colorId);
68 | }
69 |
70 | public ImageView getImageView() {
71 | return imageView;
72 | }
73 |
74 | public void setImage(Integer imageResource) {
75 | if (imageResource == null) {
76 | imageView.setVisibility(View.GONE);
77 | } else {
78 | imageView.setVisibility(View.VISIBLE);
79 | imageView.setImageResource(imageResource);
80 | }
81 | }
82 |
83 | public void setImage(Drawable drawable) {
84 | if (drawable == null) {
85 | imageView.setVisibility(View.GONE);
86 | } else {
87 | imageView.setVisibility(View.VISIBLE);
88 | imageView.setImageDrawable(drawable);
89 | }
90 | }
91 |
92 | public void setImageBitmap(Bitmap bitmap) {
93 | if (bitmap == null) {
94 | imageView.setVisibility(View.GONE);
95 | } else {
96 | imageView.setVisibility(View.VISIBLE);
97 | imageView.setImageBitmap(bitmap);
98 | }
99 | }
100 |
101 | public TextView getTitleView() {
102 | return titleView;
103 | }
104 |
105 | public String getTitle() {
106 | return titleView.getText().toString();
107 | }
108 |
109 | public void setTitle(String title) {
110 | this.titleView.setText(title);
111 | }
112 |
113 | public TextView getSubtitleView() {
114 | return subtitleView;
115 | }
116 |
117 | public String getSubtitle() {
118 | return subtitleView.getText().toString();
119 | }
120 |
121 | public void setSubtitle(String subtitle) {
122 | if (TextUtils.isEmpty(subtitle)) {
123 | subtitleView.setVisibility(View.GONE);
124 | } else {
125 | subtitleView.setVisibility(View.VISIBLE);
126 | subtitleView.setText(subtitle);
127 | }
128 | }
129 |
130 | public ImageView getAccessoryView() {
131 | return accessoryView;
132 | }
133 |
134 | public void setAccessory(AccessoryType accessoryType) {
135 | if (accessoryType == AccessoryType.NONE) {
136 | accessoryView.setVisibility(View.GONE);
137 | } else {
138 | accessoryView.setVisibility(View.VISIBLE);
139 |
140 | switch (accessoryType) {
141 | case DISCLOSURE:
142 | accessoryView.setImageResource(R.drawable.accessory_disclosure);
143 | break;
144 | }
145 | }
146 | }
147 |
148 | public void setAccessory(Drawable drawable) {
149 | if (drawable == null) {
150 | accessoryView.setVisibility(View.GONE);
151 | } else {
152 | accessoryView.setVisibility(View.VISIBLE);
153 | accessoryView.setImageDrawable(drawable);
154 | }
155 | }
156 |
157 | public void setDefaultBackgroundColor() {
158 | setBackgroundColor(colorLineDefault, colorLinePressed);
159 | }
160 |
161 | public void setBackgroundColor(int[] colorDefault, int[] colorPressed) {
162 | // Assign the right backgroundDrawable according to the cell's position in the group
163 | Drawable backgroundDrawable;
164 | if (indexPath.getRowsCount() == 1) {
165 | backgroundDrawable = new UITableCellDrawable(10.0f, 10.0f, colorDefault, colorPressed, borderColor);
166 | } else {
167 | if (indexPath.isFirstCellOfGroup()) {
168 | backgroundDrawable = new UITableCellDrawable(10.0f, 0, colorDefault, colorPressed, borderColor);
169 | } else if (indexPath.isLastCellOfGroup()) {
170 | backgroundDrawable = new UITableCellDrawable(0, 10.0f, colorDefault, colorPressed, borderColor);
171 | } else {
172 | backgroundDrawable = new UITableCellDrawable(0, 0, colorDefault, colorPressed, borderColor);
173 | }
174 | }
175 |
176 | // Add extra space if this cell is the last one
177 | int bottomInset = 0;
178 | if (indexPath.isLastCell()) {
179 | bottomInset = INSET;
180 | }
181 | setBackgroundDrawable(new InsetDrawable(backgroundDrawable, INSET, 0, INSET, bottomInset));
182 | }
183 |
184 | public UITableViewInternalAccessoryListener getInternalAccessoryListener() {
185 | return internalAccessoryListener;
186 | }
187 |
188 | public void setInternalAccessoryListener(final UITableViewInternalAccessoryListener internalAccessoryListener) {
189 | if (internalAccessoryListener != null) {
190 | accessoryView.setOnClickListener(new OnClickListener() {
191 | @Override
192 | public void onClick(View v) {
193 | internalAccessoryListener.onCellAccessoryClick(UITableCellView.this.indexPath);
194 | }
195 | });
196 | accessoryView.setOnLongClickListener(new OnLongClickListener() {
197 | @Override
198 | public boolean onLongClick(View v) {
199 | return internalAccessoryListener.onCellAccessoryLongClick(UITableCellView.this.indexPath);
200 | }
201 | });
202 | }
203 |
204 | this.internalAccessoryListener = internalAccessoryListener;
205 | }
206 |
207 | @Override
208 | public void setIndexPath(IndexPath indexPath) {
209 | super.setIndexPath(indexPath);
210 | setBackgroundColor(colorLineDefault, colorLinePressed);
211 | }
212 |
213 | /**
214 | * Adds a touchable padding around a View by constructing a TouchDelegate and adding it to parent View.
215 | *
216 | * @param parent
217 | * The "outer" parent View
218 | * @param delegate
219 | * The delegate that handles the TouchEvents
220 | * @param topPadding
221 | * Additional touch area in pixels above View
222 | * @param bootomPadding
223 | * Additional touch area in pixels below View
224 | * @param topPadding
225 | * Additional touch area in pixels left to View
226 | * @param topPadding
227 | * Additional touch area in pixels right to View
228 | * @return A runnable that you can post as action to a Views event queue
229 | */
230 | private static Runnable getTouchDelegateAction(final View parent, final View delegate, final int topPadding, final int bottomPadding, final int leftPadding, final int rightPadding) {
231 | return new Runnable() {
232 | @Override
233 | public void run() {
234 |
235 | // Construct a new Rectangle and let the Delegate set its values
236 | Rect touchRect = new Rect();
237 | delegate.getHitRect(touchRect);
238 |
239 | // Modify the dimensions of the Rectangle
240 | // Padding values below zero are replaced by zeros
241 | touchRect.top -= Math.max(0, topPadding);
242 | touchRect.bottom += Math.max(0, bottomPadding);
243 | touchRect.left -= Math.max(0, leftPadding);
244 | touchRect.right += Math.max(0, rightPadding);
245 |
246 | // Now we are going to construct the TouchDelegate
247 | TouchDelegate touchDelegate = new TouchDelegate(touchRect, delegate);
248 |
249 | // And set it on the parent
250 | parent.setTouchDelegate(touchDelegate);
251 |
252 | }
253 | };
254 | }
255 |
256 | }
257 |
--------------------------------------------------------------------------------