11package com.mindorks.editdrawabletext
22
33import android.content.Context
4+ import android.content.res.TypedArray
45import android.graphics.Rect
56import android.graphics.drawable.Drawable
7+ import android.text.Editable
8+ import android.text.TextWatcher
69import android.util.AttributeSet
710import android.view.MotionEvent
811import android.widget.EditText
912import kotlin.math.abs
1013
11- class EditDrawableText : EditText {
14+ class EditDrawableText ( context : Context , attrs : AttributeSet ) : EditText(context, attrs) {
1215
1316 private var drawableRight: Drawable ? = null
1417 private var drawableLeft: Drawable ? = null
1518 private var drawableTop: Drawable ? = null
1619 private var drawableBottom: Drawable ? = null
1720 private var positionX: Int = 0
1821 private var positionY: Int = 0
19-
22+ private var isDrawableShownWhenTextIsEmpty = true
2023 private var onDrawableClickListener: OnDrawableClickListener ? = null
2124
22- constructor (context: Context , attrs: AttributeSet ) : super (context, attrs)
2325
24- constructor (context: Context , attrs: AttributeSet , defStyle: Int ) : super (context, attrs, defStyle)
26+ init {
27+ parseAttributes(
28+ context.obtainStyledAttributes(
29+ attrs,
30+ R .styleable.EditDrawableText
31+ )
32+ )
33+ }
34+
35+ private fun parseAttributes (obtainStyledAttributes : TypedArray ) {
36+ isDrawableShownWhenTextIsEmpty = obtainStyledAttributes.getBoolean(R .styleable.EditDrawableText_isDrawableShownWhenTextIsEmpty , isDrawableShownWhenTextIsEmpty);
37+ obtainStyledAttributes.recycle()
38+ hasDrawable(isDrawableShownWhenTextIsEmpty)
39+ }
40+
41+ fun hasDrawable (value : Boolean ) {
42+ isDrawableShownWhenTextIsEmpty = value
43+ if (! isDrawableShownWhenTextIsEmpty) this .setCompoundDrawablesWithIntrinsicBounds(0 , 0 , 0 , 0 )
44+ invalidate()
45+ }
2546
2647 override fun setCompoundDrawables (leftDrawable : Drawable ? ,
2748 topDrawable : Drawable ? ,
@@ -33,106 +54,129 @@ class EditDrawableText : EditText {
3354 if (bottomDrawable != null ) drawableBottom = bottomDrawable
3455 super .setCompoundDrawables(leftDrawable, topDrawable, rightDrawable, bottomDrawable)
3556 }
36-
57+
3758 override fun onTouchEvent (event : MotionEvent ): Boolean {
3859 var bounds: Rect ?
39- if (event.action == MotionEvent .ACTION_DOWN ) {
40- positionX = event.x.toInt()
41- positionY = event.y.toInt()
42-
43-
44- // this works for left since container shares 0,0 origin with bounds
45- if (drawableLeft != null ) {
46- bounds = drawableLeft!! .bounds
60+ val editText = this
61+ this .addTextChangedListener(object : TextWatcher {
62+ override fun afterTextChanged (p0 : Editable ? ) {
4763
48- var xClickPosition: Int
49- var yClickPosition: Int
50- /*
51- * @return pixels into dp
52- */
53- val extraClickArea = (13 * resources.displayMetrics.density + 0.5 ).toInt()
54-
55- xClickPosition = positionX
56- yClickPosition = positionY
64+ }
5765
58- if (! bounds!! .contains(positionX, positionY)) {
59- /* * Gives some extra space for tapping. */
60- xClickPosition = positionX - extraClickArea
61- yClickPosition = positionY - extraClickArea
66+ override fun beforeTextChanged (p0 : CharSequence? , p1 : Int , p2 : Int , p3 : Int ) {
67+ }
6268
63- if (xClickPosition <= 0 ) xClickPosition = positionX
64- if (yClickPosition <= 0 ) yClickPosition = positionY
69+ override fun onTextChanged (char : CharSequence , p1 : Int , p2 : Int , p3 : Int ) {
70+ if (char.isEmpty()) {
71+ if (! isDrawableShownWhenTextIsEmpty) editText.setCompoundDrawablesWithIntrinsicBounds(0 , 0 , 0 , 0 )
72+ } else editText.setCompoundDrawables(drawableLeft, drawableTop, drawableRight, drawableBottom)
73+ }
6574
66- /* * Creates square from the smallest value from x or y*/
67- if (xClickPosition < yClickPosition) yClickPosition = xClickPosition
68- }
6975
70- if (bounds.contains(xClickPosition, yClickPosition) && onDrawableClickListener != null ) {
71- onDrawableClickListener !! .onClick( DrawablePosition . LEFT )
72- event.action = MotionEvent . ACTION_CANCEL
73- return false
76+ })
77+ if (event.action == MotionEvent . ACTION_DOWN ) {
78+ positionX = event.x.toInt()
79+ positionY = event.y.toInt()
7480
75- }
81+ // this works for left since container shares 0,0 origin with bounds
82+ if (drawableLeft != null ) {
83+ bounds = drawableLeft?.bounds
84+ setupDrawableLeftClick(bounds, event)
7685 }
77-
86+
7887 if (drawableRight != null ) {
79- bounds = drawableRight!! .bounds
80- var xClickPosition: Int
81- var yClickPosition: Int
82- val extraClickingArea = 13
83-
84- xClickPosition = positionX + extraClickingArea
85- yClickPosition = positionY - extraClickingArea
86-
87- /* *
88- * It right drawable -> subtract the value of x from the width of view. so that width - tapped area * will result in x co-ordinate in drawable bound.
89- */
90- xClickPosition = width - xClickPosition
91- if (xClickPosition <= 0 ) xClickPosition + = extraClickingArea
92-
93- /* If after calculating for extra clickable area is negative.
94- * assign the original value so that after subtracting
95- * extra clicking area value doesn't go into negative value.
96- */
97-
98- if (yClickPosition <= 0 ) yClickPosition = positionY
99-
100- /* *If drawable bounds contains the x and y points then move ahead. */
101- if (bounds!! .contains(xClickPosition, yClickPosition) && onDrawableClickListener != null ) {
102- onDrawableClickListener!! .onClick(DrawablePosition .RIGHT )
103- event.action = MotionEvent .ACTION_CANCEL
104- return false
105- }
106- return super .onTouchEvent(event)
88+ bounds = drawableRight?.bounds
89+ setupDrawableRightClick(bounds, event)
10790 }
10891
10992 if (drawableTop != null ) {
110- bounds = drawableTop!! .bounds
111- val extraClickingArea = 13
112- if (abs((width - paddingLeft - paddingRight) / 2 + paddingLeft - positionX) <= bounds.width() / 2 + extraClickingArea) {
113- onDrawableClickListener!! .onClick(DrawablePosition .TOP )
114- event.action = MotionEvent .ACTION_CANCEL
115- return false
116- }
93+ bounds = drawableTop?.bounds
94+ setupDrawableTopClick(bounds, event)
11795 }
11896
119- if (drawableBottom!= null )
120- {
121- bounds = drawableBottom!! .bounds
122- val extraClickingArea = 13
123-
124- if (abs((width - paddingLeft - paddingRight) / 2 + paddingLeft - positionX) <= bounds.width() / 2 + extraClickingArea) {
125- onDrawableClickListener!! .onClick(DrawablePosition .BOTTOM )
126- event.action = MotionEvent .ACTION_CANCEL
127- return false
128- }
97+ if (drawableBottom != null ) {
98+ bounds = drawableBottom?.bounds
99+ setupDrawableBottomClick(bounds, event)
129100 }
130101
131102
132103 }
133104 return super .onTouchEvent(event)
134105 }
135106
107+ private fun setupDrawableBottomClick (bounds : Rect ? , event : MotionEvent ) {
108+ val extraClickingArea = 13
109+ if (abs((width - paddingLeft - paddingRight) / 2 + paddingLeft - positionX) <= bounds!! .width() / 2 + extraClickingArea) {
110+ onDrawableClickListener?.onClick(DrawablePosition .BOTTOM )
111+ event.action = MotionEvent .ACTION_CANCEL
112+ }
113+ }
114+
115+ private fun setupDrawableTopClick (bounds : Rect ? , event : MotionEvent ) {
116+ val extraClickingArea = 13
117+ if (abs((width - paddingLeft - paddingRight) / 2 + paddingLeft - positionX) <= bounds!! .width() / 2 + extraClickingArea) {
118+ onDrawableClickListener?.onClick(DrawablePosition .TOP )
119+ event.action = MotionEvent .ACTION_CANCEL
120+ }
121+ }
122+
123+ private fun setupDrawableLeftClick (bounds : Rect ? , event : MotionEvent ) {
124+ var xClickPosition: Int
125+ var yClickPosition: Int
126+ /*
127+ * @return pixels into dp
128+ */
129+ val extraClickArea = (13 * resources.displayMetrics.density + 0.5 ).toInt()
130+
131+ xClickPosition = positionX
132+ yClickPosition = positionY
133+
134+ if (! bounds!! .contains(positionX, positionY)) {
135+ /* * Gives some extra space for tapping. */
136+ xClickPosition = positionX - extraClickArea
137+ yClickPosition = positionY - extraClickArea
138+
139+ if (xClickPosition <= 0 ) xClickPosition = positionX
140+ if (yClickPosition <= 0 ) yClickPosition = positionY
141+
142+ /* * Creates square from the smallest value from x or y*/
143+ if (xClickPosition < yClickPosition) yClickPosition = xClickPosition
144+ }
145+
146+ if (bounds.contains(xClickPosition, yClickPosition) && onDrawableClickListener != null ) {
147+ onDrawableClickListener?.onClick(DrawablePosition .LEFT )
148+ event.action = MotionEvent .ACTION_CANCEL
149+
150+ }
151+ }
152+
153+ private fun setupDrawableRightClick (bounds : Rect ? , event : MotionEvent ) {
154+ var xClickPosition: Int
155+ var yClickPosition: Int
156+ val extraClickingArea = 13
157+
158+ xClickPosition = positionX + extraClickingArea
159+ yClickPosition = positionY - extraClickingArea
160+
161+ /* *
162+ * It right drawable -> subtract the value of x from the width of view. so that width - tapped area * will result in x co-ordinate in drawable bound.
163+ */
164+ xClickPosition = width - xClickPosition
165+ if (xClickPosition <= 0 ) xClickPosition + = extraClickingArea
166+
167+ /* If after calculating for extra clickable area is negative.
168+ * assign the original value so that after subtracting
169+ * extra clicking area value doesn't go into negative value.
170+ */
171+
172+ if (yClickPosition <= 0 ) yClickPosition = positionY
173+
174+ /* *If drawable bounds contains the x and y points then move ahead. */
175+ if (bounds!! .contains(xClickPosition, yClickPosition) && onDrawableClickListener != null ) {
176+ onDrawableClickListener?.onClick(DrawablePosition .RIGHT )
177+ event.action = MotionEvent .ACTION_CANCEL
178+ }
179+ }
136180
137181 fun setDrawableClickListener (OnDrawableClickListener : OnDrawableClickListener ) {
138182 this .onDrawableClickListener = OnDrawableClickListener
0 commit comments