From 06129d31d9e1c89866eee0430167ea3f4f400e3e Mon Sep 17 00:00:00 2001 From: zhpanvip Date: Thu, 28 Jan 2021 10:01:38 +0800 Subject: [PATCH] RTL mode supported. --- .../zhpan/banner/fragment/OthersFragment.java | 2 +- .../zhpan/banner/fragment/PageFragment.java | 1 - bannerview/build.gradle | 4 +- .../com/zhpan/bannerview/BannerViewPager.java | 13 +- .../bannerview/indicator/DrawableIndicator.kt | 172 ++++++++++++++++++ .../bannerview/manager/BannerOptions.java | 15 ++ 6 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 bannerview/src/main/java/com/zhpan/bannerview/indicator/DrawableIndicator.kt diff --git a/app/src/main/java/com/example/zhpan/banner/fragment/OthersFragment.java b/app/src/main/java/com/example/zhpan/banner/fragment/OthersFragment.java index 0a2b6b92..dae954ac 100644 --- a/app/src/main/java/com/example/zhpan/banner/fragment/OthersFragment.java +++ b/app/src/main/java/com/example/zhpan/banner/fragment/OthersFragment.java @@ -17,8 +17,8 @@ import com.scwang.smartrefresh.layout.SmartRefreshLayout; import com.zhpan.bannerview.BannerViewPager; import com.zhpan.bannerview.constants.IndicatorGravity; +import com.zhpan.bannerview.indicator.DrawableIndicator; import com.zhpan.bannerview.utils.BannerUtils; -import com.zhpan.indicator.DrawableIndicator; import com.zhpan.indicator.IndicatorView; import com.zhpan.indicator.base.IIndicator; import com.zhpan.indicator.enums.IndicatorSlideMode; diff --git a/app/src/main/java/com/example/zhpan/banner/fragment/PageFragment.java b/app/src/main/java/com/example/zhpan/banner/fragment/PageFragment.java index aef0df95..17dc38e5 100644 --- a/app/src/main/java/com/example/zhpan/banner/fragment/PageFragment.java +++ b/app/src/main/java/com/example/zhpan/banner/fragment/PageFragment.java @@ -43,7 +43,6 @@ protected void initView(Bundle savedInstanceState, View view) { .setIndicatorSlideMode(IndicatorSlideMode.SCALE) .setIndicatorSliderColor(getColor(R.color.red_normal_color), getColor(R.color.red_checked_color)) .setIndicatorSliderRadius(getResources().getDimensionPixelOffset(R.dimen.dp_4), getResources().getDimensionPixelOffset(R.dimen.dp_5)) - .setRTLMode(true) .setLifecycleRegistry(getLifecycle()) .setOnPageClickListener(this::pageClick) .setAdapter(new ViewBindingSampleAdapter(getResources().getDimensionPixelOffset(R.dimen.dp_8))) diff --git a/bannerview/build.gradle b/bannerview/build.gradle index 3c3381d0..f7eee7d5 100644 --- a/bannerview/build.gradle +++ b/bannerview/build.gradle @@ -6,7 +6,7 @@ android { compileSdkVersion 28 defaultConfig { - minSdkVersion 16 + minSdkVersion 19 } buildTypes { @@ -19,6 +19,6 @@ android { dependencies { implementation 'androidx.viewpager2:viewpager2:1.0.0' - api 'com.github.zhpanvip:viewpagerindicator:1.1.0' + api 'com.github.zhpanvip:viewpagerindicator:1.2.0' // api project(path: ':indicator') } diff --git a/bannerview/src/main/java/com/zhpan/bannerview/BannerViewPager.java b/bannerview/src/main/java/com/zhpan/bannerview/BannerViewPager.java index 90bcad87..0d1063ee 100644 --- a/bannerview/src/main/java/com/zhpan/bannerview/BannerViewPager.java +++ b/bannerview/src/main/java/com/zhpan/bannerview/BannerViewPager.java @@ -32,6 +32,7 @@ import com.zhpan.indicator.annotation.AIndicatorSlideMode; import com.zhpan.indicator.annotation.AIndicatorStyle; import com.zhpan.indicator.base.IIndicator; +import com.zhpan.indicator.enums.IndicatorOrientation; import com.zhpan.indicator.option.IndicatorOptions; import java.util.ArrayList; @@ -1037,11 +1038,15 @@ public BannerViewPager disallowParentInterceptDownEvent(boolean disallowParen return this; } + /** + * Set right to left mode. + * + * @param rtlMode true:right to left mode, + * false:right to left mode. + */ public BannerViewPager setRTLMode(boolean rtlMode) { - if (Build.VERSION.SDK_INT >= JELLY_BEAN_MR1) { - mViewPager.setLayoutDirection(rtlMode ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); - // TODO set indicator RTL mode. - } + mViewPager.setLayoutDirection(rtlMode ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); + mBannerManager.getBannerOptions().setRtl(rtlMode); return this; } diff --git a/bannerview/src/main/java/com/zhpan/bannerview/indicator/DrawableIndicator.kt b/bannerview/src/main/java/com/zhpan/bannerview/indicator/DrawableIndicator.kt new file mode 100644 index 00000000..b1d9a823 --- /dev/null +++ b/bannerview/src/main/java/com/zhpan/bannerview/indicator/DrawableIndicator.kt @@ -0,0 +1,172 @@ +package com.zhpan.bannerview.indicator + +import android.content.Context +import android.graphics.* +import android.os.Build +import android.util.AttributeSet +import androidx.annotation.DrawableRes +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat +import com.zhpan.indicator.base.BaseIndicatorView + +/** + * @ author : zhouweibin + * @ time: 2019/12/18 17:04. + * @ desc: 选中与未选中的图片长宽可能不一样 + */ +class DrawableIndicator @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : BaseIndicatorView(context!!, attrs, defStyleAttr) { + // 选中时的Bitmap + private var mCheckedBitmap: Bitmap? = null + + // 未选中时的Bitmap + private var mNormalBitmap: Bitmap? = null + + // 图片之间的间距 + private var mIndicatorPadding = 0 + + // 选中图片的宽度 + private var mCheckedBitmapWidth = 0 + + // 选中图片的高度 + private var mCheckedBitmapHeight = 0 + + //未选中图片的宽高 + private var mNormalBitmapWidth = 0 + private var mNormalBitmapHeight = 0 + private var mIndicatorSize: IndicatorSize? = null + private var normalCanResize = true + private var checkCanResize = true + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val maxHeight = mCheckedBitmapHeight.coerceAtLeast(mNormalBitmapHeight) + val realWidth = mCheckedBitmapWidth + (mNormalBitmapWidth + mIndicatorPadding) * (getPageSize() - 1) + setMeasuredDimension(realWidth, maxHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (getPageSize() > 1 && mCheckedBitmap != null && mNormalBitmap != null) { + for (i in 1 until getPageSize() + 1) { + var left: Int + var top: Int + var bitmap = mNormalBitmap + val index = i - 1 + when { + index < getCurrentPosition() -> { + left = (i - 1) * (mNormalBitmapWidth + mIndicatorPadding) + top = measuredHeight / 2 - mNormalBitmapHeight / 2 + } + index == getCurrentPosition() -> { + left = (i - 1) * (mNormalBitmapWidth + mIndicatorPadding) + top = measuredHeight / 2 - mCheckedBitmapHeight / 2 + bitmap = mCheckedBitmap + } + else -> { + left = (i - 1) * mIndicatorPadding + (i - 2) * mNormalBitmapWidth + mCheckedBitmapWidth + top = measuredHeight / 2 - mNormalBitmapHeight / 2 + } + } + drawIcon(canvas, left, top, bitmap) + } + } + } + + override fun rotateCanvas(canvas: Canvas) { + + } + + private fun drawIcon(canvas: Canvas, left: Int, top: Int, icon: Bitmap?) { + if (icon == null) { + return + } + canvas.drawBitmap(icon, left.toFloat(), top.toFloat(), null) + } + + private fun initIconSize() { + mCheckedBitmap?.let { + mIndicatorSize?.let { + if (mCheckedBitmap!!.isMutable && checkCanResize) { + mCheckedBitmap!!.width = mIndicatorSize!!.checkedWidth + mCheckedBitmap!!.height = mIndicatorSize!!.checkedHeight + } else { + val width = mCheckedBitmap!!.width + val height = mCheckedBitmap!!.height + val scaleWidth = mIndicatorSize!!.checkedWidth.toFloat() / width + val scaleHeight = mIndicatorSize!!.checkedHeight.toFloat() / height + val matrix = Matrix() + matrix.postScale(scaleWidth, scaleHeight) + mCheckedBitmap = Bitmap.createBitmap(mCheckedBitmap!!, 0, 0, width, height, matrix, true) + } + } + mCheckedBitmapWidth = mCheckedBitmap!!.width + mCheckedBitmapHeight = mCheckedBitmap!!.height + } + mNormalBitmap?.let { + mIndicatorSize?.let { + if (mNormalBitmap!!.isMutable && normalCanResize) { + mNormalBitmap!!.width = mIndicatorSize!!.normalWidth + mNormalBitmap!!.height = mIndicatorSize!!.normalHeight + } else { + val width = mNormalBitmap!!.width + val height = mNormalBitmap!!.height + val scaleWidth = mIndicatorSize!!.normalWidth.toFloat() / mNormalBitmap!!.width + val scaleHeight = mIndicatorSize!!.normalHeight.toFloat() / mNormalBitmap!!.height + val matrix = Matrix() + matrix.postScale(scaleWidth, scaleHeight) + mNormalBitmap = Bitmap.createBitmap(mNormalBitmap!!, 0, 0, width, height, matrix, true) + } + } + mNormalBitmapWidth = mNormalBitmap!!.width + mNormalBitmapHeight = mNormalBitmap!!.height + } + } + + fun setIndicatorDrawable(@DrawableRes normalDrawable: Int, @DrawableRes checkedDrawable: Int): DrawableIndicator { + mNormalBitmap = BitmapFactory.decodeResource(resources, normalDrawable) + mCheckedBitmap = BitmapFactory.decodeResource(resources, checkedDrawable) + if (mNormalBitmap == null) { + mNormalBitmap = getBitmapFromVectorDrawable(context, normalDrawable) + normalCanResize = false + } + if (mCheckedBitmap == null) { + mCheckedBitmap = getBitmapFromVectorDrawable(context, checkedDrawable) + checkCanResize = false + } + initIconSize() + postInvalidate() + return this + } + + fun setIndicatorSize(normalWidth: Int, normalHeight: Int, checkedWidth: Int, checkedHeight: Int): DrawableIndicator { + mIndicatorSize = IndicatorSize(normalWidth, normalHeight, checkedWidth, checkedHeight) + initIconSize() + postInvalidate() + return this + } + + fun setIndicatorGap(padding: Int): DrawableIndicator { + if (padding >= 0) { + mIndicatorPadding = padding + postInvalidate() + } + return this + } + + internal class IndicatorSize(var normalWidth: Int, var normalHeight: Int, var checkedWidth: Int, var checkedHeight: Int) + + private fun getBitmapFromVectorDrawable(context: Context, drawableId: Int): Bitmap? { + var drawable = ContextCompat.getDrawable(context, drawableId) + drawable?.let { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + drawable = DrawableCompat.wrap(drawable!!).mutate() + } + val bitmap = Bitmap.createBitmap(drawable!!.intrinsicWidth, + drawable!!.intrinsicHeight, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + drawable!!.setBounds(0, 0, canvas.width, canvas.height) + drawable!!.draw(canvas) + return bitmap + } + return null + } +} \ No newline at end of file diff --git a/bannerview/src/main/java/com/zhpan/bannerview/manager/BannerOptions.java b/bannerview/src/main/java/com/zhpan/bannerview/manager/BannerOptions.java index a54b98d7..41f03f29 100644 --- a/bannerview/src/main/java/com/zhpan/bannerview/manager/BannerOptions.java +++ b/bannerview/src/main/java/com/zhpan/bannerview/manager/BannerOptions.java @@ -6,6 +6,7 @@ import com.zhpan.bannerview.constants.PageStyle; import com.zhpan.bannerview.utils.BannerUtils; +import com.zhpan.indicator.enums.IndicatorOrientation; import com.zhpan.indicator.option.IndicatorOptions; import static com.zhpan.bannerview.transform.ScaleInTransformer.DEFAULT_MIN_SCALE; @@ -24,6 +25,7 @@ public BannerOptions() { pageMargin = BannerUtils.dp2px(20); rightRevealWidth = DEFAULT_REVEAL_WIDTH; leftRevealWidth = DEFAULT_REVEAL_WIDTH; + rtl = false; } public static final int DEFAULT_REVEAL_WIDTH = -1000; @@ -60,6 +62,8 @@ public BannerOptions() { private int orientation = ViewPager2.ORIENTATION_HORIZONTAL; + private boolean rtl; + private boolean disallowParentInterceptDownEvent; private final IndicatorOptions mIndicatorOptions; @@ -268,6 +272,17 @@ public void setOffScreenPageLimit(int offScreenPageLimit) { this.offScreenPageLimit = offScreenPageLimit; } + public boolean isRtl() { + return rtl; + } + + public void setRtl(boolean rtl) { + this.rtl = rtl; + if (rtl) { + mIndicatorOptions.setOrientation(IndicatorOrientation.INDICATOR_RTL); + } + } + public static class IndicatorMargin { private final int left, right, top, bottom;