Skip to content

Commit 3f2dedb

Browse files
committed
Refactoring, comments, updated sample
1 parent 3a2f67e commit 3f2dedb

File tree

7 files changed

+118
-68
lines changed

7 files changed

+118
-68
lines changed

.idea/modules.xml

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

checkboxtextviews/src/main/java/uk/co/onemandan/checkboxtextviews/CheckBoxTextViews.kt

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,33 @@ import android.graphics.PorterDuff
1313
import android.graphics.PorterDuffColorFilter
1414
import android.support.v4.content.ContextCompat
1515
import android.util.DisplayMetrics
16-
16+
import android.view.LayoutInflater
17+
18+
/*
19+
* Converts a String array via an @array resource into selectable/deselectable views that act as a
20+
* CheckBox. Selected views are returned via a String ArrayList, either via the listener or public
21+
* function.
22+
* @param Context
23+
* @param AttributeSet
24+
*/
1725
class CheckBoxTextViews(context: Context, attrs: AttributeSet): LinearLayout(context, attrs),
1826
View.OnClickListener {
1927

2028
init {
21-
init(context, attrs)
29+
init(attrs)
2230
}
2331

24-
private var _flexbox: FlexboxLayout? = null
32+
private var _flexbox: FlexboxLayout? = null //CheckBox item host layout. Flexbox is set up
33+
//so that items flow to next line and are
34+
//centered
2535

26-
private var _defaultBackgroundColour = 0
27-
private var _defaultTextColour = 0
28-
private var _selectedBackgroundColour = 0
29-
private var _selectedTextColour = 0
36+
private var _defaultBackgroundColour = 0 //Deselected CheckBox item background colour
37+
private var _defaultTextColour = 0 //Deselected CheckBox item text colour
38+
private var _selectedBackgroundColour = 0 //Selected CheckBox item background colour
39+
private var _selectedTextColour = 0 //Selected CheckBox item text clour
3040

31-
private var _defaultSelected = false
41+
private var _defaultSelected = false //Whether or not the CheckBox items are
42+
//initially selected
3243

3344
private var _selectedItems: ArrayList<String>? = null
3445
private var _selectedItemListener: CheckBoxTextViewsListener? = null
@@ -37,17 +48,26 @@ class CheckBoxTextViews(context: Context, attrs: AttributeSet): LinearLayout(con
3748
selectView(v)
3849
}
3950

40-
private fun init(context: Context, attrs: AttributeSet){
41-
val root = inflate(context, R.layout.checkbox_item_host, this)
42-
_flexbox = root.rootFlexboxLayout
51+
/*
52+
* Inflate and retrieve the CheckBox item host layout. Handle attribute resources.
53+
* @param AttributeSet passed to HandleAttributes
54+
*/
55+
private fun init(attrs: AttributeSet){
56+
val root = LayoutInflater.from(context).inflate(R.layout.checkbox_item_host,
57+
this, true)
4358

44-
_selectedItems = ArrayList()
59+
_flexbox = root.rootFlexboxLayout
60+
_selectedItems = ArrayList()
4561

46-
handleDefaultAttributes(context)
47-
handleAttributes(context, attrs)
62+
handleDefaultAttributes()
63+
handleAttributes(attrs)
4864
}
4965

50-
private fun handleDefaultAttributes(context: Context){
66+
/*
67+
* Set attributes to initial default values. These are the values that are used if none are
68+
* supplied via the View.
69+
*/
70+
private fun handleDefaultAttributes(){
5171
val themeAttrs = intArrayOf(R.attr.colorAccent)
5272
val ta = context.theme.obtainStyledAttributes(themeAttrs)
5373

@@ -59,7 +79,13 @@ class CheckBoxTextViews(context: Context, attrs: AttributeSet): LinearLayout(con
5979
ta.recycle()
6080
}
6181

62-
private fun handleAttributes(context: Context, attrs: AttributeSet){
82+
/*
83+
* Attempt to obtain the supplied resources via the View. The resources that the user can
84+
* provide are the CheckBox items deselected/selected background colour and text colour, whether
85+
* the items are initially selected and the String array to create the CheckBox items from.
86+
* @param AttributeSet used to obtain the styleable attributes from the View
87+
*/
88+
private fun handleAttributes(attrs: AttributeSet){
6389
val ta = context.theme.obtainStyledAttributes(attrs, R.styleable.CheckBoxTextViews,
6490
0, 0)
6591

@@ -74,6 +100,7 @@ class CheckBoxTextViews(context: Context, attrs: AttributeSet): LinearLayout(con
74100
_defaultSelected = ta.getBoolean(
75101
R.styleable.CheckBoxTextViews_cbtv_selected, false)
76102

103+
//Retrieve the items via the provided String array and create the CheckBox items
77104
val itemsId = ta.getResourceId(R.styleable.CheckBoxTextViews_cbtv_items, 0)
78105
if(itemsId != 0){
79106
val items: Array<String> = resources.getStringArray(itemsId)
@@ -83,46 +110,54 @@ class CheckBoxTextViews(context: Context, attrs: AttributeSet): LinearLayout(con
83110
}
84111
}
85112

113+
/*
114+
* A CheckBox item is a rounded rectangle view with centered text, that is selectable. Inflate
115+
* the CheckBox item layout and set the title and and root Views corresponding to the String and
116+
* attribute resources.
117+
* @param String the CheckBox item text
118+
*/
86119
private fun createCheckBoxItem(item: String){
87-
val checkBoxItem: View = inflate(context, R.layout.checkbox_item, null)
120+
val checkBoxItem: View = LayoutInflater.from(context).inflate(R.layout.checkbox_item,
121+
_flexbox, false)
122+
88123
val root: ClipView = checkBoxItem.rootClipView
89124
val title: TextView = checkBoxItem.itemTextView
90125

91126
title.text = item
92127
title.setTextColor(_defaultTextColour)
93128

94129
setBackgroundColour(root, _defaultBackgroundColour)
95-
96-
val layoutParams = FlexboxLayout.LayoutParams(FlexboxLayout.LayoutParams.WRAP_CONTENT,
97-
FlexboxLayout.LayoutParams.WRAP_CONTENT)
98-
99-
layoutParams.setMargins(dpToPx(8f), dpToPx(8f), dpToPx(8f), 0)
100-
checkBoxItem.layoutParams = layoutParams
101130
checkBoxItem.setOnClickListener(this)
102131

132+
//During inflation, 'attachToRoot' can be specified, however, Views need to be added to the
133+
//FlexBox individually so that the specified rules are used (flex to new line, centered)
103134
_flexbox!!.addView(checkBoxItem)
104135

136+
//Users can specify whether or not the CheckBox items should initially be selected
105137
if(_defaultSelected){
106138
selectView(checkBoxItem)
107139
}
108140
}
109141

110-
private fun setBackgroundColour(view: View, colour: Int){
111-
view.background.colorFilter = PorterDuffColorFilter(colour,
112-
PorterDuff.Mode.SRC_IN)
113-
}
114-
142+
/*
143+
* Sets the CheckBox items tag to reflect whether or not it has been selected. Set the CheckBox
144+
* items background colour and text colour corresponding to its selection status.
145+
* @param View? the CheckBox items root layout
146+
*/
115147
private fun selectView(v: View?){
116148
//Update whether or not the item has been selected via the tag
117149
if(v!!.tag == null){
150+
//If first time setting the tag, it must have been selected, so it must be true
118151
v.tag = true
119152
} else {
120153
v.tag = !(v.tag as Boolean)
121154
}
122155

123-
val title = v.itemTextView
124-
val root = v.rootClipView
156+
val title = v.itemTextView //Used to change text colour
157+
val root = v.rootClipView //Used to change background colour
125158

159+
//Update text and background colour of the CheckBox item depending on whether or not it has
160+
//been selected
126161
if(v.tag as Boolean){
127162
title.setTextColor(_selectedTextColour)
128163
setBackgroundColour(root, _selectedBackgroundColour)
@@ -135,18 +170,30 @@ class CheckBoxTextViews(context: Context, attrs: AttributeSet): LinearLayout(con
135170
_selectedItems!!.remove(title.text.toString())
136171
}
137172

173+
//Call the listener
138174
_selectedItemListener?.onItemSelected(_selectedItems!!)
139175
}
140176

177+
//HELPERS
178+
////////////////////////////////////////////////////////////////////////////////////////////////
179+
180+
private fun setBackgroundColour(view: View, colour: Int){
181+
view.background.colorFilter = PorterDuffColorFilter(colour,
182+
PorterDuff.Mode.SRC_IN)
183+
}
184+
185+
private fun dpToPx(dp: Float): Int {
186+
return Math.round(dp * (Resources.getSystem().displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
187+
}
188+
189+
//ACCESSORS
190+
////////////////////////////////////////////////////////////////////////////////////////////////
191+
141192
fun getSelectedItems(): ArrayList<String> {
142193
return _selectedItems!!
143194
}
144195

145196
fun setSelectedItemListener(listener: CheckBoxTextViewsListener){
146197
_selectedItemListener = listener
147198
}
148-
149-
private fun dpToPx(dp: Float): Int {
150-
return Math.round(dp * (Resources.getSystem().displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
151-
}
152199
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package uk.co.onemandan.checkboxtextviews
22

33
interface CheckBoxTextViewsListener {
4+
5+
// Called every time a CheckBox item is selected or deselected
46
fun onItemSelected(items: List<String>)
57
}

checkboxtextviews/src/main/java/uk/co/onemandan/checkboxtextviews/ClipView.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import android.util.AttributeSet
99
import android.view.View
1010
import android.widget.FrameLayout
1111

12+
/*
13+
* When setting the background of a drawable with rounded corners in conjunction of setting the
14+
* foreground to make use of '?selectableItemBackground', the ripple will extend further than the
15+
* rounded corners. Instead, a 'ClipView' is used, so that the ripple is only rendered on the
16+
* rounded rectangle.
17+
*/
1218
class ClipView : FrameLayout {
1319

1420
private var _context : Context? = null

sample/src/main/java/uk/co/onemandan/sample/MainActivity.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,5 @@ class MainActivity : AppCompatActivity() {
1010
override fun onCreate(savedInstanceState: Bundle?) {
1111
super.onCreate(savedInstanceState)
1212
setContentView(R.layout.activity_main)
13-
14-
itemsCheckBoxTextViews.setSelectedItemListener(object: CheckBoxTextViewsListener{
15-
override fun onItemSelected(items: List<String>) {
16-
selectedItemsTextView.text = items.joinToString(", ")
17-
}
18-
})
1913
}
2014
}

sample/src/main/res/layout/activity_main.xml

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,6 @@
1111
android:id="@+id/itemsCheckBoxTextViews"
1212
android:layout_width="match_parent"
1313
android:layout_height="wrap_content"
14-
app:cbtv_items="@array/TestArray"
15-
app:cbtv_selected="true"/>
16-
17-
<TextView
18-
android:id="@+id/selectedItemTextView"
19-
android:layout_width="wrap_content"
20-
android:layout_height="wrap_content"
21-
android:layout_marginTop="16dp"
22-
android:layout_marginStart="16dp"
23-
android:layout_marginLeft="16dp"
24-
android:layout_below="@id/itemsCheckBoxTextViews"
25-
android:text="@string/title_selected_items"/>
26-
27-
<TextView
28-
android:id="@+id/selectedItemsTextView"
29-
android:layout_width="match_parent"
30-
android:layout_height="wrap_content"
31-
android:layout_marginTop="16dp"
32-
android:layout_marginStart="16dp"
33-
android:layout_marginEnd="16dp"
34-
android:layout_below="@id/selectedItemTextView"/>
14+
app:cbtv_items="@array/LoremIpsum" />
3515

3616
</RelativeLayout>

sample/src/main/res/values/arrays.xml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
33

4-
<array name="TestArray">
5-
<item>@string/test_1</item>
6-
<item>@string/test_2</item>
7-
<item>@string/test_3</item>
8-
<item>@string/test_4</item>
9-
<item>@string/test_5</item>
4+
<array name="LoremIpsum">
5+
<item>lorem</item>
6+
<item>ipsum</item>
7+
<item>dolor</item>
8+
<item>sit</item>
9+
<item>consectetur</item>
10+
<item>adipiscing</item>
11+
<item>elit</item>
12+
<item>sed</item>
13+
<item>do</item>
14+
<item>eiusmod</item>
15+
<item>tempor</item>
16+
<item>incididunt</item>
17+
<item>ut</item>
18+
<item>labore</item>
19+
<item>et</item>
20+
<item>dolore</item>
21+
<item>magna</item>
22+
<item>aliqua</item>
23+
<item>ut</item>
24+
<item>enim</item>
25+
<item>ad</item>
26+
<item>minim</item>
27+
<item>veniam</item>
28+
<item>quis</item>
29+
<item>nostrud</item>
1030
</array>
1131

1232
</resources>

0 commit comments

Comments
 (0)