Skip to content

Commit 4040912

Browse files
authored
Merge pull request #125 from Trendyol/fit-option-message-view-rtl-support
FitOptionMessageView RTL Support
2 parents 15424b2 + 43edbb8 commit 4040912

File tree

4 files changed

+102
-59
lines changed

4 files changed

+102
-59
lines changed

libraries/fit-option-message-view/src/main/java/com/trendyol/fitoptionmessageview/FitOptionMessageView.kt

Lines changed: 91 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ import androidx.core.view.doOnNextLayout
1818

1919
class FitOptionMessageView : LinearLayout {
2020

21-
private val imageView by lazy { children.first { it is ImageView } as ImageView }
22-
private val textView by lazy { children.first { it is TextView } as TextView }
23-
private val initialXPositionOfTextView by lazy { textView.x }
24-
private val initialLeftPaddingOfTextView by lazy { textView.paddingLeft }
25-
2621
constructor(context: Context) : super(context) {
2722
initialize()
2823
}
@@ -39,18 +34,34 @@ class FitOptionMessageView : LinearLayout {
3934
initialize(attrs)
4035
}
4136

42-
constructor(
43-
context: Context,
44-
attrs: AttributeSet?,
45-
defStyleAttr: Int,
46-
defStyleRes: Int
47-
) : super(context, attrs, defStyleAttr, defStyleRes) {
48-
initialize(attrs)
49-
}
50-
37+
private val imageView by lazy { children.first { it is ImageView } as ImageView }
38+
private val textView by lazy { children.first { it is TextView } as TextView }
39+
private val initialXPositionOfTextView by lazy { textView.x }
40+
private val initialLeftPaddingOfTextView by lazy { textView.paddingStart }
5141
private var cradleMargin: Float = 0f
5242
private var playRevealAnimation: Boolean = false
5343
private var revealAnimationDuration: Long = 0
44+
private var revealAnimationProvider: (ImageView, TextView) -> Unit = { imageView, _ ->
45+
val (centerX, centerY) = imageView.x + imageView.measuredWidth / 2.0 to imageView.y + imageView.measuredWidth / 2.0
46+
val finalRadius = measuredWidth.toFloat()
47+
ViewAnimationUtils
48+
.createCircularReveal(
49+
this@FitOptionMessageView,
50+
centerX.toInt(),
51+
centerY.toInt(),
52+
/*startRadius: */0f,
53+
finalRadius
54+
)
55+
.setDuration(revealAnimationDuration)
56+
.start()
57+
}
58+
private val maskPath = Path()
59+
private val clipPath = Path()
60+
private val drawPath = Path()
61+
private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
62+
color = ContextCompat.getColor(context, android.R.color.white)
63+
xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
64+
}
5465

5566
private fun initialize(attrs: AttributeSet? = null) {
5667
initializeLinearLayout()
@@ -80,87 +91,112 @@ class FitOptionMessageView : LinearLayout {
8091
}
8192
}
8293

83-
var revealAnimationProvider: (ImageView, TextView) -> Unit = { imageView, _ ->
84-
val (centerX, centerY) = imageView.x + imageView.measuredWidth / 2.0 to imageView.y + imageView.measuredWidth / 2.0
85-
val finalRadius = measuredWidth.toFloat()
86-
ViewAnimationUtils
87-
.createCircularReveal(
88-
this@FitOptionMessageView,
89-
centerX.toInt(),
90-
centerY.toInt(),
91-
/*startRadius: */0f,
92-
finalRadius)
93-
.setDuration(revealAnimationDuration)
94-
.start()
95-
}
96-
9794
private fun startRevealAnimation() {
9895
revealAnimationProvider.invoke(imageView, textView)
9996
}
10097

10198
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
10299
super.onLayout(changed, l, t, r, b)
103-
val radius = imageView.measuredHeight / 2f
104-
textView.x = initialXPositionOfTextView - radius
105-
imageView.y = if (isHeightDeterminedByImage()) 0f else (textView.measuredHeight / 2f) - radius
100+
textView.x = getTextViewInitialX()
101+
imageView.y = getImageViewInitialY()
106102
imageView.elevation = textView.elevation + 0.01f
103+
if (layoutDirection == LAYOUT_DIRECTION_RTL) {
104+
imageView.x = measuredWidth - 2 * getRadius()
105+
}
107106
}
108107

108+
private fun getTextViewInitialX(): Float {
109+
return if (layoutDirection == LAYOUT_DIRECTION_LTR) {
110+
initialXPositionOfTextView - getRadius()
111+
} else {
112+
initialXPositionOfTextView
113+
}
114+
}
115+
116+
private fun getImageViewInitialY(): Float {
117+
return if (isHeightDeterminedByImage()) {
118+
0f
119+
} else {
120+
(textView.measuredHeight / 2f) - getRadius()
121+
}
122+
}
109123

110124
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
111125
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
112-
val radius = imageView.measuredHeight / 2f
113126
adjustMeasureSpec(heightMeasureSpec)
114127
textView.setPadding(
115-
initialLeftPaddingOfTextView + cradleMargin.toInt() + radius.toInt(),
128+
getTextViewLeftPadding(),
116129
textView.paddingTop,
117-
textView.paddingRight,
130+
getTextViewRightPadding(),
118131
textView.paddingBottom
119132
)
120133
}
121134

135+
private fun getTextViewLeftPadding(): Int {
136+
return if (layoutDirection == LAYOUT_DIRECTION_LTR) {
137+
initialLeftPaddingOfTextView + cradleMargin.toInt() + getRadius().toInt()
138+
} else {
139+
textView.paddingLeft
140+
}
141+
}
142+
143+
private fun getTextViewRightPadding(): Int {
144+
return if (layoutDirection == LAYOUT_DIRECTION_LTR) {
145+
textView.paddingRight
146+
} else {
147+
initialLeftPaddingOfTextView + cradleMargin.toInt() + getRadius().toInt()
148+
}
149+
}
150+
151+
override fun dispatchDraw(canvas: Canvas) {
152+
val saveCount = canvas.save()
153+
super.dispatchDraw(canvas)
154+
calculateMaskPath()
155+
canvas.drawPath(maskPath, maskPaint)
156+
canvas.restoreToCount(saveCount)
157+
}
158+
122159
private fun adjustMeasureSpec(heightMeasureSpec: Int) {
123160
val lp = textView.layoutParams as LayoutParams
124-
val radius = imageView.measuredHeight / 2
125161

126162
val childHeightMeasureSpec = getChildMeasureSpec(
127163
heightMeasureSpec,
128164
paddingTop + paddingBottom + lp.topMargin + lp.bottomMargin,
129165
lp.height
130166
)
131-
val childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(measuredWidth-radius, MeasureSpec.EXACTLY)
167+
val childWidthMeasureSpec =
168+
MeasureSpec.makeMeasureSpec(measuredWidth - getRadius().toInt(), MeasureSpec.EXACTLY)
132169
textView.measure(childWidthMeasureSpec, childHeightMeasureSpec)
133170
}
134171

135-
private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
136-
color = ContextCompat.getColor(context, android.R.color.white)
137-
xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
138-
}
139-
140-
private val maskPath = Path()
141-
private val clipPath = Path()
142-
private val drawPath = Path()
143-
144172
private fun calculateMaskPath() {
145173
clipPath.reset()
146174
drawPath.reset()
147-
val (centerX, centerY) = textView.x to if (isHeightDeterminedByImage()) imageView.measuredHeight / 2f else textView.measuredHeight / 2f
148-
val radius = imageView.measuredHeight / 2f
149-
clipPath.addCircle(centerX, centerY, radius + cradleMargin, Path.Direction.CCW)
150-
drawPath.addCircle(centerX, centerY, radius, Path.Direction.CCW)
175+
val (centerX, centerY) = getCenterX() to getCenterY()
176+
clipPath.addCircle(centerX, centerY, getRadius() + cradleMargin, Path.Direction.CCW)
177+
drawPath.addCircle(centerX, centerY, getRadius(), Path.Direction.CCW)
151178
clipPath.op(drawPath, Path.Op.DIFFERENCE)
152179
maskPath.set(clipPath)
153180
}
154181

155-
override fun dispatchDraw(canvas: Canvas) {
156-
val saveCount = canvas.save()
157-
super.dispatchDraw(canvas)
158-
calculateMaskPath()
159-
canvas.drawPath(maskPath, maskPaint)
160-
canvas.restoreToCount(saveCount)
182+
private fun getCenterX(): Float {
183+
return if (layoutDirection == LAYOUT_DIRECTION_LTR) {
184+
textView.x
185+
} else {
186+
textView.x + textView.measuredWidth
187+
}
188+
}
189+
190+
private fun getCenterY(): Float {
191+
return if (isHeightDeterminedByImage()) {
192+
getRadius()
193+
} else {
194+
textView.measuredHeight / 2f
195+
}
161196
}
162197

163198
private fun isHeightDeterminedByImage(): Boolean =
164199
imageView.measuredHeight > textView.measuredHeight
165200

201+
private fun getRadius(): Float = imageView.measuredHeight / 2f
166202
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@
4242
android:layout_gravity="center"
4343
android:background="@drawable/rounded_corner"
4444
android:fontFamily="sans-serif-medium"
45+
android:layoutDirection="locale"
4546
android:paddingHorizontal="12dp"
4647
android:paddingVertical="16dp"
47-
android:text="Test test, test test! Test"
48+
android:text="@string/fit_option_message_view_test_message"
4849
android:textColor="#333333"
4950
android:textSize="12sp"
5051
android:textStyle="normal" />
@@ -72,9 +73,10 @@
7273
android:layout_gravity="center"
7374
android:background="@drawable/rounded_corner"
7475
android:fontFamily="sans-serif-medium"
76+
android:layoutDirection="locale"
7577
android:paddingHorizontal="2dp"
7678
android:paddingVertical="16dp"
77-
android:text="Test test, test test! Test"
79+
android:text="@string/fit_option_message_view_test_message"
7880
android:textColor="#333333"
7981
android:textSize="12sp"
8082
android:textStyle="normal" />
@@ -100,9 +102,10 @@
100102
android:layout_gravity="center"
101103
android:background="@drawable/rounded_corner"
102104
android:fontFamily="sans-serif-medium"
105+
android:layoutDirection="locale"
103106
android:paddingHorizontal="12dp"
104107
android:paddingVertical="16dp"
105-
android:text="Test test, test test! Test"
108+
android:text="@string/fit_option_message_view_test_message"
106109
android:textColor="#333333"
107110
android:textSize="12sp"
108111
android:textStyle="normal" />
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<resources>
2+
<string name="fit_option_message_view_test_message">يوصي معظم المستخدمين بشراء المنتج بحجمك الخاص.</string>
3+
</resources>
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
<resources>
2-
<string name="app_name">UI Components</string>
2+
<string name="app_name" translatable="false">UI Components</string>
3+
<string name="fit_option_message_view_test_message">Most users recommend buying the product in your own size.</string>
34
</resources>

0 commit comments

Comments
 (0)