From 68f6a1f8cce70b54d2081f5f50ed6e07564a80cc Mon Sep 17 00:00:00 2001 From: antoxa2584x Date: Tue, 8 Oct 2019 17:15:26 +0300 Subject: [PATCH] Provided rtl support --- .idea/codeStyles/Project.xml | 109 +++++++++++++++++ .../stepperdemo/frags/FragmentA.kt | 2 + .../stepperdemo/frags/FragmentB.kt | 4 + .../stepperdemo/frags/FragmentC.kt | 4 + .../stepperdemo/frags/FragmentD.kt | 4 + .../stepperdemo/frags/FragmentE.kt | 17 ++- app/src/main/res/layout/activity_main.xml | 59 +++++++-- .../java/com/tayfuncesur/stepper/Stepper.kt | 115 ++++++++++++------ lib/src/main/res/values-ldrtl/direction.xml | 4 + lib/src/main/res/values/attrs.xml | 5 + lib/src/main/res/values/direction.xml | 4 + 11 files changed, 277 insertions(+), 50 deletions(-) create mode 100644 lib/src/main/res/values-ldrtl/direction.xml create mode 100644 lib/src/main/res/values/direction.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1bec35e..ce889bd 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -3,6 +3,115 @@ + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
diff --git a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentA.kt b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentA.kt index 02334e9..f934edb 100644 --- a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentA.kt +++ b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentA.kt @@ -25,6 +25,8 @@ class FragmentA : Fragment() { PushDownAnim.setPushDownAnimTo(nextToB).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().navigate(R.id.fragmentAtoB) activity?.findViewById(R.id.Stepper)?.forward() + activity?.findViewById(R.id.StepperRtl)?.forward() + activity?.findViewById(R.id.StepperAuto)?.forward() } } } diff --git a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentB.kt b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentB.kt index 67a4012..e557151 100644 --- a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentB.kt +++ b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentB.kt @@ -26,11 +26,15 @@ class FragmentB : Fragment() { PushDownAnim.setPushDownAnimTo(nextToC).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().navigate(R.id.fragmentBtoC) activity?.findViewById(R.id.Stepper)?.forward() + activity?.findViewById(R.id.StepperRtl)?.forward() + activity?.findViewById(R.id.StepperAuto)?.forward() } PushDownAnim.setPushDownAnimTo(backArrow).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().popBackStack() activity?.findViewById(R.id.Stepper)?.back() + activity?.findViewById(R.id.StepperRtl)?.back() + activity?.findViewById(R.id.StepperAuto)?.back() } } } diff --git a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentC.kt b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentC.kt index b01cc66..ab0f940 100644 --- a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentC.kt +++ b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentC.kt @@ -25,11 +25,15 @@ class FragmentC : Fragment() { PushDownAnim.setPushDownAnimTo(nextToD).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().navigate(R.id.fragmentCtoD) activity?.findViewById(R.id.Stepper)?.forward() + activity?.findViewById(R.id.StepperRtl)?.forward() + activity?.findViewById(R.id.StepperAuto)?.forward() } PushDownAnim.setPushDownAnimTo(backArrow).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().popBackStack() activity?.findViewById(R.id.Stepper)?.back() + activity?.findViewById(R.id.StepperRtl)?.back() + activity?.findViewById(R.id.StepperAuto)?.back() } } } diff --git a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentD.kt b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentD.kt index de04ab0..1e9ee89 100644 --- a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentD.kt +++ b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentD.kt @@ -26,10 +26,14 @@ class FragmentD : Fragment() { PushDownAnim.setPushDownAnimTo(nextToE).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().navigate(R.id.fragmentDtoE) activity?.findViewById(R.id.Stepper)?.forward() + activity?.findViewById(R.id.StepperRtl)?.forward() + activity?.findViewById(R.id.StepperAuto)?.forward() } PushDownAnim.setPushDownAnimTo(backArrow).setScale(PushDownAnim.MODE_STATIC_DP,5F).setOnClickListener { view.findNavController().popBackStack() activity?.findViewById(R.id.Stepper)?.back() + activity?.findViewById(R.id.StepperRtl)?.back() + activity?.findViewById(R.id.StepperAuto)?.back() } } } diff --git a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentE.kt b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentE.kt index 0ef2c0f..100d90d 100644 --- a/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentE.kt +++ b/app/src/main/java/com/tayfuncesur/stepperdemo/frags/FragmentE.kt @@ -11,7 +11,6 @@ import com.tayfuncesur.stepper.Stepper import com.tayfuncesur.stepperdemo.R import com.thekhaeng.pushdownanim.PushDownAnim import kotlinx.android.synthetic.main.fragment_e.* -import kotlinx.android.synthetic.main.fragment_e.backArrow class FragmentE : Fragment() { @@ -29,6 +28,16 @@ class FragmentE : Fragment() { activity?.findViewById(R.id.StepperView)?.background = ContextCompat.getDrawable(context!!, R.drawable.success_gradient) } + + activity?.findViewById(R.id.StepperRtl)?.progress(3)?.addOnCompleteListener { + activity?.findViewById(R.id.StepperViewRtl)?.background = + ContextCompat.getDrawable(context!!, R.drawable.success_gradient) + } + + activity?.findViewById(R.id.StepperAuto)?.progress(3)?.addOnCompleteListener { + activity?.findViewById(R.id.StepperViewAuto)?.background = + ContextCompat.getDrawable(context!!, R.drawable.success_gradient) + } } @@ -37,9 +46,15 @@ class FragmentE : Fragment() { view.findNavController().popBackStack() activity?.findViewById(R.id.Stepper)?.stop() activity?.findViewById(R.id.Stepper)?.back() + activity?.findViewById(R.id.StepperRtl)?.stop() + activity?.findViewById(R.id.StepperRtl)?.back() + activity?.findViewById(R.id.StepperAuto)?.stop() + activity?.findViewById(R.id.StepperAuto)?.back() } PushDownAnim.setPushDownAnimTo(progressStop).setScale(PushDownAnim.MODE_STATIC_DP, 5F).setOnClickListener { activity?.findViewById(R.id.Stepper)?.stop() + activity?.findViewById(R.id.StepperRtl)?.stop() + activity?.findViewById(R.id.StepperAuto)?.stop() } } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index cdae859..5765d1f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,33 +1,66 @@ - + app:layout_constraintTop_toTopOf="parent"> - + + + + + + + + + + + + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/StepperAuto" + app:navGraph="@navigation/navigation_graph" /> \ No newline at end of file diff --git a/lib/src/main/java/com/tayfuncesur/stepper/Stepper.kt b/lib/src/main/java/com/tayfuncesur/stepper/Stepper.kt index bd0976a..63df817 100644 --- a/lib/src/main/java/com/tayfuncesur/stepper/Stepper.kt +++ b/lib/src/main/java/com/tayfuncesur/stepper/Stepper.kt @@ -1,22 +1,41 @@ +@file:Suppress("RedundantGetter") + package com.tayfuncesur.stepper import android.animation.Animator import android.animation.ValueAnimator import android.content.Context +import android.os.Build +import android.support.annotation.RequiresApi +import android.support.v4.text.TextUtilsCompat +import android.support.v4.view.ViewCompat import android.util.AttributeSet +import android.view.ViewGroup import android.view.animation.Animation import android.widget.RelativeLayout +import java.util.* +import kotlin.math.abs +@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) class Stepper @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : RelativeLayout(context, attrs, defStyleAttr) { - private var stepCount: Int = 5 + enum class Direction { + NO_RTL, AUTO, FORCE + } + + private var stepCount: Int private var currentStepCount: Int = 1 - private var defaultDuration: Long = 500 + private var defaultDuration: Long + + private var layoutDirection: Direction = Direction.NO_RTL + + val isLeftToRight = + TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_LTR private var screenWidth: Int = 0 @@ -30,21 +49,6 @@ class Stepper @JvmOverloads constructor( private lateinit var progressAnimationListener: Animator.AnimatorListener - fun getStepCount(): Int { - return stepCount - } - - fun setStepCount(stepCount: Int) { - this.stepCount = stepCount - } - - fun getDefaultDuration(): Long { - return defaultDuration - } - - fun setDefaultDuration(defaultDuration: Long) { - this.defaultDuration = defaultDuration - } fun addOnCompleteListener(addOnCompleteListener: () -> Unit) { this.completeListener = addOnCompleteListener @@ -80,40 +84,69 @@ class Stepper @JvmOverloads constructor( }) animator.duration = defaultDuration + return animator } init { + with(context.obtainStyledAttributes(attrs, R.styleable.Stepper, defStyleAttr, 0)) { + try { + stepCount = getInt(R.styleable.Stepper_stepCount, 5) + defaultDuration = getInt(R.styleable.Stepper_duration, 500).toLong() + layoutDirection = Direction.values()[getInt(R.styleable.Stepper_useRTL, 0)] + + + when (layoutDirection) { + Direction.FORCE -> rotate() + Direction.AUTO -> { + if (resources.getBoolean(R.bool.useRtl)) { + rotate() + } + } + } + } finally { + recycle() + } + + + post { + if (childCount != 1) throw IllegalStateException("Stepper must have only one child layout") + if (layoutParams.width != ViewGroup.LayoutParams.MATCH_PARENT) throw IllegalStateException( + "Stepper must have match_parent width for correct support of RTL/LTR" + ) + + val metrics = context.resources.displayMetrics + screenWidth = metrics.widthPixels - val attr = context.obtainStyledAttributes(attrs, R.styleable.Stepper, defStyleAttr, 0) - stepCount = attr.getInt(R.styleable.Stepper_stepCount, 5) - defaultDuration = attr.getInt(R.styleable.Stepper_duration, 500).toLong() - attr.recycle() - post { - if (childCount != 1) throw IllegalStateException("Stepper must have only one child layout") + getChildAt(0).layoutParams = (getChildAt(0).layoutParams as LayoutParams).apply { + width = (screenWidth / stepCount) - val metrics = context.resources.displayMetrics - screenWidth = metrics.widthPixels - getChildAt(0).layoutParams = LayoutParams((screenWidth / stepCount), getChildAt(0).height) + } + } } } + private fun rotate() { + this@Stepper.rotation = (180f) + } + fun forward() { if (inProgress) { stop() } + if (!isRunning) { currentStepCount++ getValueAnimator().start() } - } fun back() { if (inProgress) { stop() } + if (!isRunning) { currentStepCount-- getValueAnimator().start() @@ -128,7 +161,9 @@ class Stepper @JvmOverloads constructor( screenWidth ) ) + var leftOffset = 1 + progressValueAnimator.addUpdateListener { valueAnimator -> val currentVal = valueAnimator.animatedValue as Int val layoutParams = getChildAt(0).layoutParams as LayoutParams @@ -156,12 +191,13 @@ class Stepper @JvmOverloads constructor( override fun onAnimationStart(animation: Animator?) {} } - progressValueAnimator.addListener(progressAnimationListener) - + progressValueAnimator.apply { + addListener(progressAnimationListener) + repeatCount = if (loopSize == 0) Animation.INFINITE else loopSize - 1 + duration = 1000 + start() + } - progressValueAnimator.repeatCount = if (loopSize == 0) Animation.INFINITE else loopSize - 1 - progressValueAnimator.duration = 1000 - progressValueAnimator.start() inProgress = true } return this @@ -169,12 +205,19 @@ class Stepper @JvmOverloads constructor( fun stop() { if (::progressValueAnimator.isInitialized && inProgress) { - progressValueAnimator.removeAllListeners() - progressValueAnimator.end() - progressValueAnimator.cancel() + progressValueAnimator.apply { + removeAllListeners() + end() + cancel() + } + getChildAt(0).layoutParams = - LayoutParams(screenWidth - (screenWidth * Math.abs(currentStepCount - stepCount)), getChildAt(0).height) + LayoutParams( + screenWidth - (screenWidth * abs(currentStepCount - stepCount)), + getChildAt(0).height + ) } + isRunning = false inProgress = false diff --git a/lib/src/main/res/values-ldrtl/direction.xml b/lib/src/main/res/values-ldrtl/direction.xml new file mode 100644 index 0000000..08786a4 --- /dev/null +++ b/lib/src/main/res/values-ldrtl/direction.xml @@ -0,0 +1,4 @@ + + + true + \ No newline at end of file diff --git a/lib/src/main/res/values/attrs.xml b/lib/src/main/res/values/attrs.xml index 2a49e45..090ccbb 100644 --- a/lib/src/main/res/values/attrs.xml +++ b/lib/src/main/res/values/attrs.xml @@ -3,5 +3,10 @@ + + + + + \ No newline at end of file diff --git a/lib/src/main/res/values/direction.xml b/lib/src/main/res/values/direction.xml new file mode 100644 index 0000000..3d5cbfd --- /dev/null +++ b/lib/src/main/res/values/direction.xml @@ -0,0 +1,4 @@ + + + false + \ No newline at end of file