├── .gitignore
├── AndroidManifest.xml
├── README
├── build.xml
├── local.properties
├── proguard-project.txt
├── project.properties
├── res
├── drawable-mdpi
│ ├── message_read_status_read.png
│ └── message_read_status_unread.png
├── drawable
│ ├── message_list_item_background.xml
│ └── message_read_status.xml
├── layout
│ └── message_list_item.xml
└── values
│ ├── attrs.xml
│ └── colors.xml
└── src
└── com
└── charlesharley
└── example
└── android
└── customdrawablestates
├── HomeActivity.java
└── MessageListItemView.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ IDEA project files
2 | *.iml
3 | .idea
4 |
5 | # Build directories
6 | gen
7 | out
8 | bin
9 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Example Android application demonstrating how to use custom drawable states to enhance your Android application with minimal effort.
2 |
3 | See this tutorial for further details:
4 |
5 | Icons used are from the FatCow icon set, http://www.fatcow.com/free-icons
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
29 |
30 |
31 |
40 |
41 |
42 |
43 |
47 |
48 |
60 |
61 |
62 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/local.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 *NOT* be checked into Version Control Systems,
5 | # as it contains information specific to your local configuration.
6 |
7 | # location of the SDK. This is only used by Ant
8 | # For customization when using a Version Control System, please read the
9 | # header note.
10 | sdk.dir=/Applications/AndroidSDK
11 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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-15
15 |
--------------------------------------------------------------------------------
/res/drawable-mdpi/message_read_status_read.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CharlesHarley/Example-Android-CustomDrawableStates/a8b9ed7d1fc2bced6b98e1c399416ce4f56b1243/res/drawable-mdpi/message_read_status_read.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/message_read_status_unread.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CharlesHarley/Example-Android-CustomDrawableStates/a8b9ed7d1fc2bced6b98e1c399416ce4f56b1243/res/drawable-mdpi/message_read_status_unread.png
--------------------------------------------------------------------------------
/res/drawable/message_list_item_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
13 |
14 |
17 |
18 |
21 |
22 |
--------------------------------------------------------------------------------
/res/drawable/message_read_status.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/layout/message_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 |
27 |
28 |
--------------------------------------------------------------------------------
/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #ff274172
5 |
6 |
--------------------------------------------------------------------------------
/src/com/charlesharley/example/android/customdrawablestates/HomeActivity.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Charles Harley
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.charlesharley.example.android.customdrawablestates;
16 |
17 | import android.app.ListActivity;
18 | import android.os.Bundle;
19 | import android.view.View;
20 | import android.view.ViewGroup;
21 | import android.widget.BaseAdapter;
22 |
23 | public class HomeActivity extends ListActivity {
24 |
25 | @Override
26 | public void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 |
29 | setListAdapter(new ExampleListAdapter());
30 | }
31 |
32 | private static class ExampleListAdapter extends BaseAdapter {
33 |
34 | private Message[] messages;
35 |
36 | private ExampleListAdapter() {
37 | messages = new Message[] {
38 | new Message("Gas bill overdue", true),
39 | new Message("Congratulations, you've won!", true),
40 | new Message("I love you!", false),
41 | new Message("Please reply!", false),
42 | new Message("You ignoring me?", false),
43 | new Message("Not heard from you", false),
44 | new Message("Electricity bill", true),
45 | new Message("Gas bill", true),
46 | new Message("Holiday plans", false),
47 | new Message("Marketing stuff", false),
48 | };
49 | }
50 |
51 | @Override
52 | public int getCount() {
53 | return messages.length;
54 | }
55 |
56 | @Override
57 | public Object getItem(int position) {
58 | return messages[position];
59 | }
60 |
61 | @Override
62 | public long getItemId(int position) {
63 | return position;
64 | }
65 |
66 | @Override
67 | public View getView(int position, View convertView, ViewGroup viewGroup) {
68 | MessageListItemView messageListItemView = (MessageListItemView) convertView;
69 |
70 | if (messageListItemView == null) {
71 | messageListItemView = new MessageListItemView(viewGroup.getContext());
72 | }
73 |
74 | Message message = (Message) getItem(position);
75 | messageListItemView.setMessageSubject(message.subject);
76 | messageListItemView.setMessageUnread(message.unread);
77 |
78 | return messageListItemView;
79 | }
80 |
81 | }
82 |
83 | private static class Message {
84 |
85 | private String subject;
86 | private boolean unread;
87 |
88 | private Message(String subject, boolean unread) {
89 | this.subject = subject;
90 | this.unread = unread;
91 | }
92 |
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/com/charlesharley/example/android/customdrawablestates/MessageListItemView.java:
--------------------------------------------------------------------------------
1 | /* Copyright 2012 Charles Harley
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.charlesharley.example.android.customdrawablestates;
16 |
17 | import android.content.Context;
18 | import android.util.AttributeSet;
19 | import android.util.DisplayMetrics;
20 | import android.util.TypedValue;
21 | import android.view.LayoutInflater;
22 | import android.view.ViewGroup;
23 | import android.widget.AbsListView;
24 | import android.widget.RelativeLayout;
25 | import android.widget.TextView;
26 |
27 | public class MessageListItemView extends RelativeLayout {
28 |
29 | /**
30 | * Custom message unread state variable for use with a {@link android.graphics.drawable.StateListDrawable}.
31 | */
32 | private static final int[] STATE_MESSAGE_UNREAD = {R.attr.state_message_unread};
33 |
34 | private TextView messageSubject;
35 | private boolean messageUnread;
36 |
37 | public MessageListItemView(Context context) {
38 | this(context, null);
39 | }
40 |
41 | public MessageListItemView(Context context, AttributeSet attributeSet) {
42 | super(context, attributeSet);
43 |
44 | loadViews();
45 | }
46 |
47 | public MessageListItemView(Context context, AttributeSet attributeSet, int defStyle) {
48 | super(context, attributeSet, defStyle);
49 |
50 | loadViews();
51 | }
52 |
53 | private void loadViews() {
54 | LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
55 | layoutInflater.inflate(R.layout.message_list_item, this, true);
56 |
57 | int fiveDPInPixels = convertDIPToPixels(5);
58 | int fiftyDPInPixels = convertDIPToPixels(50);
59 |
60 | setPadding(fiveDPInPixels, fiveDPInPixels, fiveDPInPixels, fiveDPInPixels);
61 | setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, fiftyDPInPixels));
62 | setBackgroundResource(R.drawable.message_list_item_background);
63 |
64 | messageSubject = (TextView) findViewById(R.id.message_subject);
65 | }
66 |
67 | public int convertDIPToPixels(int dip) {
68 | // In production code this method would exist in a utility library.
69 | // e.g see my ScreenUtils class: https://gist.github.com/2504204
70 | DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
71 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
72 | }
73 |
74 | @Override
75 | protected int[] onCreateDrawableState(int extraSpace) {
76 | // If the message is unread then we merge our custom message unread state into
77 | // the existing drawable state before returning it.
78 | if (messageUnread) {
79 | // We are going to add 1 extra state.
80 | final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
81 |
82 | mergeDrawableStates(drawableState, STATE_MESSAGE_UNREAD);
83 |
84 | return drawableState;
85 | } else {
86 | return super.onCreateDrawableState(extraSpace);
87 | }
88 | }
89 |
90 | public void setMessageSubject(String subject) {
91 | messageSubject.setText(subject);
92 | }
93 |
94 | public void setMessageUnread(boolean messageUnread) {
95 | // Performance optimisation: only update the state if it has changed.
96 | if (this.messageUnread != messageUnread) {
97 | this.messageUnread = messageUnread;
98 |
99 | // Refresh the drawable state so that it includes the message unread state if required.
100 | refreshDrawableState();
101 | }
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------