recycleview 指示器

This commit is contained in:
yangyakun
2022-06-23 20:51:50 +08:00
parent f1489b6f4d
commit 55f6979911
29 changed files with 1304 additions and 129 deletions

View File

@@ -118,7 +118,6 @@ object OverlayLeftViewUtils {
if(taxiPassengerMogoConsultView?.get() != null){
OverlayViewUtils.showOverlayView(context,taxiPassengerMogoConsultView?.get())
}else{
ToastUtils.showLong("已经回收")
taxiPassengerMogoConsultView =
WeakReference<TaxiPassengerMogoConsultView>(TaxiPassengerMogoConsultView(context))
OverlayViewUtils.showOverlayView(context,taxiPassengerMogoConsultView?.get())
@@ -135,7 +134,6 @@ object OverlayLeftViewUtils {
if(taxiPassengerMogoMoviesView?.get() != null){
OverlayViewUtils.showOverlayView(context,taxiPassengerMogoMoviesView?.get())
}else{
ToastUtils.showLong("已经回收")
taxiPassengerMogoMoviesView =
WeakReference<TaxiPassengerMogoMoviesView>(TaxiPassengerMogoMoviesView(context))
OverlayViewUtils.showOverlayView(context,taxiPassengerMogoMoviesView?.get())

View File

@@ -2,10 +2,10 @@ package com.mogo.och.taxi.passenger.ui.video
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.RelativeLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
@@ -20,12 +20,16 @@ import com.mogo.och.taxi.passenger.bean.TaxiPassengerVideoPlay
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CarouselLayoutManager
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CarouselZoomPostLayoutListener
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CenterScrollListener
import com.mogo.och.taxi.passenger.widget.ConsultVideoPlayer
import com.mogo.och.taxi.passenger.utils.blur.GlideBlurTransform
import com.mogo.och.taxi.passenger.widget.ConsultVideoPlayer
import com.mogo.och.taxi.passenger.widget.indicator.IndicatorView
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import io.reactivex.disposables.Disposable
import java.util.*
import kotlin.math.floor
/**
@@ -45,33 +49,38 @@ class TaxiPassengerMogoConsultView :RelativeLayout {
private lateinit var rvVideoPlaylist: RecyclerView
private lateinit var indicatorView: IndicatorView
private lateinit var clContain: ConstraintLayout
private fun initView(context: Context) {
d(SceneConstant.M_TAXI_P + "pageStopCenterScrollListener", "initView:$visibility")
d(SceneConstant.M_TAXI_P + TAG, "initView")
LayoutInflater.from(context).inflate(R.layout.taxi_p_arrived_mogo_consult, this, true)
rvVideoPlaylist = findViewById(R.id.rv_video_playlist)
indicatorView = findViewById(R.id.indicatorView)
clContain = findViewById(R.id.cl_contain)
val arrayListOf = ArrayList<TaxiPassengerVideoPlay>()
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708409810/20210610重新排版3屏.m4v","https://gohome-1253308323.cos.ap-beijing.myqcloud.com/McTk51586843620689.png","重新排版"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708499497/大运会合作解说版.m4v","https://gohome-1253308323.cos.ap-beijing.myqcloud.com/12111.jpg","大运会合作解说"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708554279/红旗车队.m4v","https://gohome-1253308323.cos.ap-beijing.myqcloud.com/McTk51586843620689.png","红旗车队"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708596763/全车型混剪增加红旗车队.m4v","https://gohome-1253308323.cos.ap-beijing.myqcloud.com/12111.jpg","全车型混剪增加红旗车队"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708499497/大运会合作解说版.m4v","https://gohome-1253308323.cos.ap-beijing.myqcloud.com/12111.jpg","大运会合作解说"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708596763/全车型混剪增加红旗车队.m4v","https://gohome-1253308323.cos.ap-beijing.myqcloud.com/12111.jpg","全车型混剪增加红旗车队"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708409810/20210610重新排版3屏.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969579713/三屏.png","重新排版"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708499497/大运会合作解说版.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969536177/大运会.png","大运会"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708554279/红旗车队.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969553174/红旗重新排版.png","红旗车队"))
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708596763/全车型混剪增加红旗车队.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969511280/车队.png","全车型混剪增加红旗车队"))
val recyclerVideoAdapter = RecyclerVideoAdapter(context, arrayListOf)
val carouselLayoutManager = CarouselLayoutManager(CarouselLayoutManager.HORIZONTAL, true)
carouselLayoutManager.setPostLayoutListener(CarouselZoomPostLayoutListener ())
carouselLayoutManager.maxVisibleItems = 1
indicatorView.notifyDataChanged(arrayListOf.size)
indicatorView.setSlideMode(IndicatorSlideMode.SCALE)
indicatorView.setOrientation(IndicatorOrientation.INDICATOR_HORIZONTAL)
indicatorView.setIndicatorStyle(IndicatorStyle.ROUND_RECT)
indicatorView.setSliderColor(Color.parseColor("#80FFFFFF"), Color.parseColor("#2972FF"))
indicatorView.setSliderWidth(14f, 90f)
indicatorView.setSliderHeight(14f)
rvVideoPlaylist.addOnScrollListener(object: CenterScrollListener() {
var prePlayerPosition = 0
override fun pageSelect(recyclerView: RecyclerView?, newState: Int) {
//播放视频
val centerItemPosition: Int = carouselLayoutManager.centerItemPosition
System.err.println("CarouselZoomPostLayoutListener---centerItemPosition:"+centerItemPosition+"----prePlayerPosition:"+prePlayerPosition);
val player = carouselLayoutManager.findViewByPosition(centerItemPosition)
indicatorView.onPageSelected(centerItemPosition)
if(player is ConsultVideoPlayer){
if(prePlayerPosition!=centerItemPosition) {
if(player.currentState==GSYVideoView.CURRENT_STATE_PAUSE){
@@ -98,6 +107,18 @@ class TaxiPassengerMogoConsultView :RelativeLayout {
}
})
carouselLayoutManager.addOnDargAutoDiffListener { adapterPosition, currentPosition ->
val fl = adapterPosition - floor(adapterPosition)
var currentIndex = currentPosition
if(fl>0.5){
if(currentPosition==0){
currentIndex = rvVideoPlaylist.adapter!!.itemCount
}else {
currentIndex -= 1
}
}
indicatorView.onPageScrolled(currentIndex, fl, 0)
}
rvVideoPlaylist.layoutManager = carouselLayoutManager
rvVideoPlaylist.setHasFixedSize(true)
rvVideoPlaylist.adapter = recyclerVideoAdapter
@@ -128,20 +149,21 @@ class TaxiPassengerMogoConsultView :RelativeLayout {
clContain.background = BitmapDrawable(context.resources, resource)
}
})
player.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onAutoComplete(url: String?, vararg objects: Any?) {
player.onVideoReset()
val itemCount = rvVideoPlaylist.adapter?.itemCount
itemCount?.let {
if (centerItemPosition == itemCount - 1) {
rvVideoPlaylist.smoothScrollToPosition(0)
} else {
rvVideoPlaylist.smoothScrollToPosition(centerItemPosition + 1)
if(player.getVideoAllCallBack()==null) {
player.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onAutoComplete(url: String?, vararg objects: Any?) {
player.onVideoReset()
val itemCount = rvVideoPlaylist.adapter?.itemCount
itemCount?.let {
if (centerItemPosition == itemCount - 1) {
rvVideoPlaylist.smoothScrollToPosition(0)
} else {
rvVideoPlaylist.smoothScrollToPosition(centerItemPosition + 1)
}
}
}
}
})
})
}
}
@@ -195,10 +217,9 @@ class TaxiPassengerMogoConsultView :RelativeLayout {
val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager
val centerItemPosition: Int = carouselLayoutManager.centerItemPosition
val player = carouselLayoutManager.findViewByPosition(centerItemPosition)
d(SceneConstant.M_TAXI_P + "pageStopCenterScrollListener", "onDetachedFromWindow:$visibility---$player---${centerItemPosition}")
player?.let {
if(player is ConsultVideoPlayer){
player.onVideoReset()
player.release()
}
}
}

View File

@@ -1,49 +0,0 @@
package com.mogo.och.taxi.passenger.ui.video.layoutmanage;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public abstract class CarouselChildSelectionListener {
@NonNull
private final RecyclerView mRecyclerView;
@NonNull
private final CarouselLayoutManager mCarouselLayoutManager;
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(final View v) {
final RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
final int position = holder.getAdapterPosition();
if (position == mCarouselLayoutManager.getCenterItemPosition()) {
onCenterItemClicked(mRecyclerView, mCarouselLayoutManager, v);
} else {
onBackItemClicked(mRecyclerView, mCarouselLayoutManager, v);
}
}
};
protected CarouselChildSelectionListener(@NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager) {
mRecyclerView = recyclerView;
mCarouselLayoutManager = carouselLayoutManager;
mRecyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(@NonNull final View view) {
view.setOnClickListener(mOnClickListener);
}
@Override
public void onChildViewDetachedFromWindow(@NonNull final View view) {
view.setOnClickListener(null);
}
});
}
protected abstract void onCenterItemClicked(@NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager, @NonNull final View v);
protected abstract void onBackItemClicked(@NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager, @NonNull final View v);
}

View File

@@ -63,6 +63,7 @@ public class CarouselLayoutManager extends RecyclerView.LayoutManager implements
private PostLayoutListener mViewPostLayout;
private final List<OnCenterItemSelectionListener> mOnCenterItemSelectionListeners = new ArrayList<>();
private final List<OnDargAutoDiffListener> onDargAutoDiffListeners = new ArrayList<>();
private int mCenterItemPosition = INVALID_POSITION;
private int mItemsCount;
@@ -188,6 +189,14 @@ public class CarouselLayoutManager extends RecyclerView.LayoutManager implements
mOnCenterItemSelectionListeners.remove(onCenterItemSelectionListener);
}
public void addOnDargAutoDiffListener(@NonNull final OnDargAutoDiffListener onDargAutoDiffListener) {
onDargAutoDiffListeners.add(onDargAutoDiffListener);
}
public void removeOnDargAutoDiffListener(@NonNull final OnDargAutoDiffListener onDargAutoDiffListener) {
onDargAutoDiffListeners.remove(onDargAutoDiffListener);
}
@SuppressWarnings("RefusedBequest")
@Override
public void scrollToPosition(final int position) {
@@ -439,7 +448,9 @@ public class CarouselLayoutManager extends RecyclerView.LayoutManager implements
private void detectOnItemSelectionChanged(final float currentScrollPosition, final RecyclerView.State state) {
final float absCurrentScrollPosition = makeScrollPositionInRange0ToCount(currentScrollPosition, state.getItemCount());
final int centerItem = Math.round(absCurrentScrollPosition);
if(currentScrollPosition-centerItem!=0){
new Handler(Looper.getMainLooper()).post(() -> dragDxDiff(currentScrollPosition,mCenterItemPosition));
}
if (mCenterItemPosition != centerItem) {
mCenterItemPosition = centerItem;
new Handler(Looper.getMainLooper()).post(new Runnable() {
@@ -456,6 +467,11 @@ public class CarouselLayoutManager extends RecyclerView.LayoutManager implements
onCenterItemSelectionListener.onCenterItemChanged(centerItem);
}
}
private void dragDxDiff(final float centerItem,final int currentPosition) {
for (final OnDargAutoDiffListener onDargAutoDiffListener : onDargAutoDiffListeners) {
onDargAutoDiffListener.onDxChanged(centerItem,currentPosition);
}
}
private void fillDataVertical(final RecyclerView.Recycler recycler, final int width, final int height) {
final int start = (width - mDecoratedChildWidth) / 2;
@@ -781,6 +797,10 @@ public class CarouselLayoutManager extends RecyclerView.LayoutManager implements
void onCenterItemChanged(final int adapterPosition);
}
public interface OnDargAutoDiffListener {
void onDxChanged(final float adapterPosition,final int currentPosition);
}
/**
* Helper class that holds currently visible items.
* Generally this class fills this list. <br />

View File

@@ -26,16 +26,6 @@ public class CarouselZoomPostLayoutListener extends CarouselLayoutManager.PostLa
@Override
public ItemTransformation transformChild(@NonNull final View child, final float itemPositionToCenterDiff, final int orientation) {
float scale = 1.0f - mScaleMultiplier * Math.abs(itemPositionToCenterDiff);
// float scale;
// if(itemPositionToCenterDiff==1||itemPositionToCenterDiff==-1){
// scale = 0.79f;
// }else {
// scale = 1.0f - mScaleMultiplier * Math.abs(itemPositionToCenterDiff);
// if(scale<0.79){
// scale = 0.79f;
// }
// }
// because scaling will make view smaller in its center, then we should move this item to the top or bottom to make it visible
final float translateY;
final float translateX;
if (CarouselLayoutManager.VERTICAL == orientation) {

View File

@@ -1,37 +0,0 @@
package com.mogo.och.taxi.passenger.ui.video.layoutmanage;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class DefaultChildSelectionListener extends CarouselChildSelectionListener {
@NonNull
private final OnCenterItemClickListener mOnCenterItemClickListener;
protected DefaultChildSelectionListener(@NonNull final OnCenterItemClickListener onCenterItemClickListener, @NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager) {
super(recyclerView, carouselLayoutManager);
mOnCenterItemClickListener = onCenterItemClickListener;
}
@Override
protected void onCenterItemClicked(@NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager, @NonNull final View v) {
mOnCenterItemClickListener.onCenterItemClicked(recyclerView, carouselLayoutManager, v);
}
@Override
protected void onBackItemClicked(@NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager, @NonNull final View v) {
recyclerView.smoothScrollToPosition(carouselLayoutManager.getPosition(v));
}
public static DefaultChildSelectionListener initCenterItemListener(@NonNull final OnCenterItemClickListener onCenterItemClickListener, @NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager) {
return new DefaultChildSelectionListener(onCenterItemClickListener, recyclerView, carouselLayoutManager);
}
public interface OnCenterItemClickListener {
void onCenterItemClicked(@NonNull final RecyclerView recyclerView, @NonNull final CarouselLayoutManager carouselLayoutManager, @NonNull final View v);
}
}

View File

@@ -13,6 +13,7 @@ import com.mogo.eagle.core.utilcode.util.TimeTransformUtils
import com.mogo.eagle.core.widget.media.video.TextureVideoViewOutlineProvider
import com.mogo.och.taxi.passenger.R
import com.mogo.och.taxi.passenger.ui.video.FullVideoUtils
import com.shuyu.gsyvideoplayer.listener.VideoAllCallBack
import com.shuyu.gsyvideoplayer.utils.Debuger
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
@@ -118,11 +119,12 @@ class ConsultVideoPlayer : StandardGSYVideoPlayer {
fullVideoPlayer?.let {
clearFullscreenLayout(it)
}
onVideoReset()
fullVideoPlayer?.onVideoReset()
if (thumbImageView is ImageView) {
(thumbImageView as ImageView).setImageResource(R.drawable.taxi_p_video_holder)
}
}else{
onVideoReset()
}
}
@@ -282,16 +284,16 @@ class ConsultVideoPlayer : StandardGSYVideoPlayer {
width, height
)
frameLayout.addView(gsyVideoPlayer, lp)
FullVideoUtils.showOverlayView(context as Activity,frameLayout)
FullVideoUtils.showOverlayView(context as Activity,frameLayout,R.style.och_window_anim_alpha)
gsyVideoPlayer.visibility = INVISIBLE
frameLayout.visibility = INVISIBLE
resolveFullVideoShow(context, gsyVideoPlayer, frameLayout)
gsyVideoPlayer.addTextureView()
gsyVideoPlayer.startProgressTimer()
gsyVideoManager.setLastListener(this)
gsyVideoManager.setListener(gsyVideoPlayer)
checkoutState()
thumbImageViewLayout.visibility = View.VISIBLE
return gsyVideoPlayer
} catch (e: java.lang.Exception) {
e.printStackTrace()
@@ -365,5 +367,9 @@ class ConsultVideoPlayer : StandardGSYVideoPlayer {
}
this.fullVideoPlayer = null
}
fun getVideoAllCallBack(): VideoAllCallBack? {
return mVideoAllCallBack
}
}

View File

@@ -0,0 +1,68 @@
package com.mogo.och.taxi.passenger.widget.indicator
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorOrientation
import com.zhpan.indicator.base.BaseIndicatorView
import com.mogo.och.taxi.passenger.widget.indicator.drawer.DrawerProxy
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
import com.mogo.och.taxi.passenger.widget.indicator.option.AttrsController
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
class IndicatorView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : BaseIndicatorView(context, attrs, defStyleAttr) {
private var mDrawerProxy: DrawerProxy
init {
AttrsController.initAttrs(context, attrs, mIndicatorOptions)
mDrawerProxy = DrawerProxy(mIndicatorOptions)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
mDrawerProxy.onLayout(changed, left, top, right, bottom)
}
override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val measureResult = mDrawerProxy.onMeasure(widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(measureResult.measureWidth, measureResult.measureHeight)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
rotateCanvas(canvas)
mDrawerProxy.onDraw(canvas)
}
override fun setIndicatorOptions(options: IndicatorOptions) {
super.setIndicatorOptions(options)
mDrawerProxy.setIndicatorOptions(options)
}
override fun notifyDataChanged(itemCount:Int) {
mDrawerProxy = DrawerProxy(mIndicatorOptions)
super.notifyDataChanged(itemCount)
}
private fun rotateCanvas(canvas: Canvas) {
if (mIndicatorOptions.orientation == IndicatorOrientation.INDICATOR_VERTICAL) {
canvas.rotate(90f, width / 2f, width / 2f)
} else if (mIndicatorOptions.orientation == IndicatorOrientation.INDICATOR_RTL) {
canvas.rotate(180f, width / 2f, height / 2f)
}
}
fun setOrientation(@AIndicatorOrientation orientation: Int) {
mIndicatorOptions.orientation = orientation;
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.och.taxi.passenger.widget.indicator.annotation
import androidx.annotation.IntDef
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
/**
*
* @author zhangpan
* @date 2021/1/21
*/
@IntDef(
IndicatorOrientation.INDICATOR_HORIZONTAL, IndicatorOrientation.INDICATOR_VERTICAL,
IndicatorOrientation.INDICATOR_RTL
)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
annotation class AIndicatorOrientation()

View File

@@ -0,0 +1,19 @@
package com.mogo.och.taxi.passenger.widget.indicator.annotation
import androidx.annotation.IntDef
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.COLOR
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.NORMAL
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.SCALE
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.SMOOTH
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.WORM
/**
* <pre>
* Created by zhangpan on 2019-10-18.
* Description:
</pre> *
*/
@IntDef(NORMAL, SMOOTH, WORM, COLOR, SCALE)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
annotation class AIndicatorSlideMode

View File

@@ -0,0 +1,15 @@
package com.mogo.och.taxi.passenger.widget.indicator.annotation
import androidx.annotation.IntDef
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle
/**
* <pre>
* Created by zhangpan on 2019-10-18.
* Description:
</pre> *
*/
@IntDef(IndicatorStyle.CIRCLE, IndicatorStyle.DASH, IndicatorStyle.ROUND_RECT)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD)
annotation class AIndicatorStyle

View File

@@ -0,0 +1,207 @@
package com.zhpan.indicator.base
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.annotation.ColorInt
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2
import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorStyle
import com.mogo.och.taxi.passenger.widget.indicator.base.IIndicator
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhangpan on 2019-09-04.
* Description:IndicatorView基类处理了页面滑动。
* </pre>
*/
@Suppress("UNUSED")
open class BaseIndicatorView constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int
) : View(context, attrs, defStyleAttr), IIndicator {
var mIndicatorOptions: IndicatorOptions
private var recyclerView: RecyclerView? = null
init {
mIndicatorOptions = IndicatorOptions()
}
fun setPageSize(pageSize: Int): BaseIndicatorView {
mIndicatorOptions.pageSize = pageSize
return this
}
// 页面选定
fun onPageSelected(position: Int) {
System.err.println("BaseIndicatorView---onPageSelected:" + position)
if (getSlideMode() == IndicatorSlideMode.NORMAL) {
setCurrentPosition(position)
setSlideProgress(0f)
invalidate()
}
}
// 滚动距离
fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
if (getSlideMode() != IndicatorSlideMode.NORMAL && getPageSize() > 1) {
scrollSlider(position, positionOffset)
invalidate()
}
}
private fun scrollSlider(position: Int, positionOffset: Float) {
if (mIndicatorOptions.slideMode == IndicatorSlideMode.SCALE
|| mIndicatorOptions.slideMode == IndicatorSlideMode.COLOR) {
setCurrentPosition(position)
setSlideProgress(positionOffset)
} else {
if (position % getPageSize() == getPageSize() - 1) { // 最后一个页面与第一个页面
if (positionOffset < 0.5) {
setCurrentPosition(position)
setSlideProgress(0f)
} else {
setCurrentPosition(0)
setSlideProgress(0f)
}
} else { // 中间页面
setCurrentPosition(position)
setSlideProgress(positionOffset)
}
}
}
override fun notifyDataChanged(itemCount: Int) {
setPageSize(itemCount)
requestLayout()
invalidate()
}
private fun setupViewPager() {
}
fun getNormalSlideWidth(): Float {
return mIndicatorOptions.normalSliderWidth
}
fun setNormalSlideWidth(normalSliderWidth: Float) {
mIndicatorOptions.normalSliderWidth = normalSliderWidth
}
fun getCheckedSlideWidth(): Float {
return mIndicatorOptions.checkedSliderWidth
}
fun setCheckedSlideWidth(checkedSliderWidth: Float) {
mIndicatorOptions.checkedSliderWidth = checkedSliderWidth
}
val checkedSliderWidth: Float
get() = mIndicatorOptions.checkedSliderWidth
fun setCurrentPosition(currentPosition: Int) {
mIndicatorOptions.currentPosition = currentPosition
}
fun getCurrentPosition(): Int {
return mIndicatorOptions.currentPosition
}
fun getIndicatorGap(indicatorGap: Float) {
mIndicatorOptions.sliderGap = indicatorGap
}
fun setIndicatorGap(indicatorGap: Float) {
mIndicatorOptions.sliderGap = indicatorGap
}
fun setCheckedColor(@ColorInt normalColor: Int) {
mIndicatorOptions.checkedSliderColor = normalColor
}
fun getCheckedColor(): Int {
return mIndicatorOptions.checkedSliderColor
}
fun setNormalColor(@ColorInt normalColor: Int) {
mIndicatorOptions.normalSliderColor = normalColor
}
fun getSlideProgress(): Float {
return mIndicatorOptions.slideProgress
}
fun setSlideProgress(slideProgress: Float) {
mIndicatorOptions.slideProgress = slideProgress
}
fun getPageSize(): Int {
return mIndicatorOptions.pageSize
}
fun setSliderColor(
@ColorInt normalColor: Int,
@ColorInt selectedColor: Int
): BaseIndicatorView {
mIndicatorOptions.setSliderColor(normalColor, selectedColor)
return this
}
fun setSliderWidth(sliderWidth: Float): BaseIndicatorView {
mIndicatorOptions.setSliderWidth(sliderWidth)
return this
}
fun setSliderWidth(
normalSliderWidth: Float,
selectedSliderWidth: Float
): BaseIndicatorView {
mIndicatorOptions.setSliderWidth(normalSliderWidth, selectedSliderWidth)
return this
}
fun setSliderGap(sliderGap: Float): BaseIndicatorView {
mIndicatorOptions.sliderGap = sliderGap
return this
}
fun getSlideMode(): Int {
return mIndicatorOptions.slideMode
}
fun setSlideMode(@AIndicatorSlideMode slideMode: Int): BaseIndicatorView {
mIndicatorOptions.slideMode = slideMode
return this
}
fun setIndicatorStyle(@AIndicatorStyle indicatorStyle: Int): BaseIndicatorView {
mIndicatorOptions.indicatorStyle = indicatorStyle
return this
}
fun setSliderHeight(sliderHeight: Float): BaseIndicatorView {
mIndicatorOptions.sliderHeight = sliderHeight
return this
}
fun showIndicatorWhenOneItem(showIndicatorWhenOneItem: Boolean) {
mIndicatorOptions.showIndicatorOneItem = showIndicatorWhenOneItem
}
fun onPageScrollStateChanged(state: Int) {
}
override fun setIndicatorOptions(options: IndicatorOptions) {
mIndicatorOptions = options
}
}

View File

@@ -0,0 +1,18 @@
package com.mogo.och.taxi.passenger.widget.indicator.base
import androidx.viewpager.widget.ViewPager
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhangpan on 2019-09-02.
* Description:
</pre> *
*/
interface IIndicator {
fun notifyDataChanged(itemCount:Int)
fun setIndicatorOptions(options: IndicatorOptions)
}

View File

@@ -0,0 +1,94 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.animation.ArgbEvaluator
import android.graphics.Paint
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhpan on 2019/11/23.
* Description:
</pre> *
*/
abstract class BaseDrawer internal constructor(internal var mIndicatorOptions: IndicatorOptions) :
IDrawer {
private val mMeasureResult: MeasureResult
internal var maxWidth: Float = 0.toFloat()
internal var minWidth: Float = 0.toFloat()
internal var mPaint: Paint = Paint()
internal var argbEvaluator: ArgbEvaluator? = null
companion object {
const val INDICATOR_PADDING_ADDITION = 6
const val INDICATOR_PADDING = 3
}
protected val isWidthEquals: Boolean
get() = mIndicatorOptions.normalSliderWidth == mIndicatorOptions.checkedSliderWidth
init {
mPaint.isAntiAlias = true
mMeasureResult = MeasureResult()
if (mIndicatorOptions.slideMode == IndicatorSlideMode.SCALE
|| mIndicatorOptions.slideMode == IndicatorSlideMode.COLOR
) {
argbEvaluator = ArgbEvaluator()
}
}
override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
): MeasureResult {
maxWidth =
mIndicatorOptions.normalSliderWidth.coerceAtLeast(mIndicatorOptions.checkedSliderWidth)
minWidth =
mIndicatorOptions.normalSliderWidth.coerceAtMost(mIndicatorOptions.checkedSliderWidth)
if (mIndicatorOptions.orientation == IndicatorOrientation.INDICATOR_VERTICAL) {
mMeasureResult.setMeasureResult(measureHeight(), measureWidth())
} else {
mMeasureResult.setMeasureResult(measureWidth(), measureHeight())
}
return mMeasureResult
}
protected open fun measureHeight(): Int {
return mIndicatorOptions.sliderHeight.toInt() + INDICATOR_PADDING
}
private fun measureWidth(): Int {
val pageSize = mIndicatorOptions.pageSize
val indicatorGap = mIndicatorOptions.sliderGap
return ((pageSize - 1) * indicatorGap + maxWidth + (pageSize - 1) * minWidth).toInt() + INDICATOR_PADDING_ADDITION
}
override fun onLayout(
changed: Boolean,
left: Int,
top: Int,
right: Int,
bottom: Int
) {
}
inner class MeasureResult {
var measureWidth: Int = 0
internal set
var measureHeight: Int = 0
internal set
internal fun setMeasureResult(
measureWidth: Int,
measureHeight: Int
) {
this.measureWidth = measureWidth
this.measureHeight = measureHeight
}
}
}

View File

@@ -0,0 +1,157 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.graphics.Canvas
import android.graphics.RectF
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils
/**
* <pre>
* Created by zhpan on 2019/11/23.
* Description: Circle Indicator drawer.
</pre> *
*/
class CircleDrawer internal constructor(indicatorOptions: IndicatorOptions) : BaseDrawer(
indicatorOptions
) {
private val rectF = RectF()
override fun measureHeight(): Int {
return maxWidth.toInt() + INDICATOR_PADDING_ADDITION
}
override fun onDraw(canvas: Canvas) {
val pageSize = mIndicatorOptions.pageSize
if (pageSize > 1 || mIndicatorOptions.showIndicatorOneItem && pageSize == 1) {
drawNormal(canvas)
drawSlider(canvas)
}
}
private fun drawNormal(canvas: Canvas) {
val normalIndicatorWidth = mIndicatorOptions.normalSliderWidth
mPaint.color = mIndicatorOptions.normalSliderColor
for (i in 0 until mIndicatorOptions.pageSize) {
val coordinateX = IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, i)
val coordinateY = IndicatorUtils.getCoordinateY(maxWidth)
drawCircle(canvas, coordinateX, coordinateY, normalIndicatorWidth / 2)
}
}
private fun drawSlider(canvas: Canvas) {
mPaint.color = mIndicatorOptions.checkedSliderColor
when (mIndicatorOptions.slideMode) {
IndicatorSlideMode.NORMAL, IndicatorSlideMode.SMOOTH -> drawCircleSlider(canvas)
IndicatorSlideMode.WORM -> drawWormSlider(canvas)
IndicatorSlideMode.SCALE -> drawScaleSlider(canvas)
IndicatorSlideMode.COLOR -> drawColor(canvas)
}
}
private fun drawColor(canvas: Canvas) {
val currentPosition = mIndicatorOptions.currentPosition
val slideProgress = mIndicatorOptions.slideProgress
val coordinateX = IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition)
val coordinateY = IndicatorUtils.getCoordinateY(maxWidth)
var evaluate = argbEvaluator?.evaluate(
slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = (evaluate as Int)
drawCircle(canvas, coordinateX, coordinateY, mIndicatorOptions.normalSliderWidth / 2)
// 绘制可循环的ViewPager指示器渐变
evaluate = argbEvaluator?.evaluate(
1 - slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = evaluate as Int
val nextCoordinateX = if (currentPosition == mIndicatorOptions.pageSize - 1) {
IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, 0)
} else {
coordinateX + mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth
}
drawCircle(canvas, nextCoordinateX, coordinateY, mIndicatorOptions.checkedSliderWidth / 2)
}
private fun drawScaleSlider(canvas: Canvas) {
val currentPosition = mIndicatorOptions.currentPosition
val slideProgress = mIndicatorOptions.slideProgress
val coordinateX = IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition)
val coordinateY = IndicatorUtils.getCoordinateY(maxWidth)
if (slideProgress < 1) {
val evaluate = argbEvaluator?.evaluate(
slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = (evaluate as Int)
val radius =
mIndicatorOptions.checkedSliderWidth / 2 - (mIndicatorOptions.checkedSliderWidth / 2 - mIndicatorOptions.normalSliderWidth / 2) * slideProgress
drawCircle(canvas, coordinateX, coordinateY, radius)
}
if (currentPosition == mIndicatorOptions.pageSize - 1) {
val evaluate = argbEvaluator?.evaluate(
slideProgress, mIndicatorOptions.normalSliderColor, mIndicatorOptions.checkedSliderColor
)
mPaint.color = evaluate as Int
val nextCoordinateX = maxWidth / 2
val nextRadius = minWidth / 2 + (maxWidth / 2 - minWidth / 2) * (slideProgress)
drawCircle(canvas, nextCoordinateX, coordinateY, nextRadius)
} else {
if (slideProgress > 0) {
val evaluate = argbEvaluator?.evaluate(
slideProgress, mIndicatorOptions.normalSliderColor, mIndicatorOptions.checkedSliderColor
)
mPaint.color = evaluate as Int
val nextCoordinateX =
coordinateX + mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth
val nextRadius =
mIndicatorOptions.normalSliderWidth / 2 + (mIndicatorOptions.checkedSliderWidth / 2 - mIndicatorOptions.normalSliderWidth / 2) * slideProgress
drawCircle(canvas, nextCoordinateX, coordinateY, nextRadius)
}
}
}
private fun drawCircleSlider(canvas: Canvas) {
val currentPosition = mIndicatorOptions.currentPosition
val startCoordinateX =
IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition)
val endCoordinateX = IndicatorUtils.getCoordinateX(
mIndicatorOptions, maxWidth, (currentPosition + 1) % mIndicatorOptions.pageSize
)
val coordinateX =
startCoordinateX + (endCoordinateX - startCoordinateX) * mIndicatorOptions.slideProgress
val coordinateY = IndicatorUtils.getCoordinateY(maxWidth)
val radius = mIndicatorOptions.checkedSliderWidth / 2
drawCircle(canvas, coordinateX, coordinateY, radius)
}
private fun drawWormSlider(canvas: Canvas) {
val sliderHeight = mIndicatorOptions.normalSliderWidth
val slideProgress = mIndicatorOptions.slideProgress
val currentPosition = mIndicatorOptions.currentPosition
val distance = mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth
val startCoordinateX =
IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition)
val left = startCoordinateX + (distance * (slideProgress - 0.5f) * 2.0f).coerceAtLeast(
0f
) - mIndicatorOptions.normalSliderWidth / 2 + INDICATOR_PADDING
val right = startCoordinateX + (distance * slideProgress * 2f).coerceAtMost(
distance
) + mIndicatorOptions.normalSliderWidth / 2 + INDICATOR_PADDING
rectF.set(left, INDICATOR_PADDING.toFloat(), right, sliderHeight + INDICATOR_PADDING)
canvas.drawRoundRect(rectF, sliderHeight, sliderHeight, mPaint)
}
private fun drawCircle(
canvas: Canvas,
coordinateX: Float,
coordinateY: Float,
radius: Float
) {
canvas.drawCircle(
coordinateX + INDICATOR_PADDING, coordinateY + INDICATOR_PADDING, radius, mPaint
)
}
}

View File

@@ -0,0 +1,20 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.graphics.Canvas
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhpan on 2019/11/23.
* Description: Dash Indicator Drawer.
</pre> *
*/
class DashDrawer internal constructor(indicatorOptions: IndicatorOptions) : RectDrawer(
indicatorOptions
) {
override fun drawDash(canvas: Canvas) {
canvas.drawRect(mRectF, mPaint)
}
}

View File

@@ -0,0 +1,20 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhpan on 2019/11/24.
* Description: Indicator Drawer Factory.
</pre> *
*/
internal object DrawerFactory {
fun createDrawer(indicatorOptions: IndicatorOptions): IDrawer {
return when (indicatorOptions.indicatorStyle) {
IndicatorStyle.DASH -> DashDrawer(indicatorOptions)
IndicatorStyle.ROUND_RECT -> RoundRectDrawer(indicatorOptions)
else -> CircleDrawer(indicatorOptions)
}
}
}

View File

@@ -0,0 +1,48 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.graphics.Canvas
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhpan on 2019/11/23.
* Description: Indicator Drawer Proxy.
</pre> *
*/
class DrawerProxy(indicatorOptions: IndicatorOptions) : IDrawer {
private lateinit var mIDrawer: IDrawer
init {
init(indicatorOptions)
}
private fun init(indicatorOptions: IndicatorOptions) {
mIDrawer = DrawerFactory.createDrawer(indicatorOptions)
}
override fun onLayout(
changed: Boolean,
left: Int,
top: Int,
right: Int,
bottom: Int
) {
}
override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
): BaseDrawer.MeasureResult {
return mIDrawer.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
override fun onDraw(canvas: Canvas) {
mIDrawer.onDraw(canvas)
}
fun setIndicatorOptions(indicatorOptions: IndicatorOptions) {
init(indicatorOptions)
}
}

View File

@@ -0,0 +1,28 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.graphics.Canvas
import com.mogo.och.taxi.passenger.widget.indicator.drawer.BaseDrawer
/**
* <pre>
* Created by zhpan on 2019/11/23.
* Description:
</pre> *
*/
interface IDrawer {
fun onLayout(
changed: Boolean,
left: Int,
top: Int,
right: Int,
bottom: Int
)
fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
): BaseDrawer.MeasureResult
fun onDraw(canvas: Canvas)
}

View File

@@ -0,0 +1,219 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.graphics.*
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils
/**
* <pre>
* Created by zhpan on 2020/1/17.
* Description:
</pre> *
*/
open class RectDrawer internal constructor(indicatorOptions: IndicatorOptions) : BaseDrawer(
indicatorOptions
) {
internal var mRectF: RectF = RectF()
override fun onDraw(canvas: Canvas) {
val pageSize = mIndicatorOptions.pageSize
if (pageSize > 1 || mIndicatorOptions.showIndicatorOneItem && pageSize == 1) {
if (isWidthEquals && mIndicatorOptions.slideMode != IndicatorSlideMode.NORMAL) {
drawUncheckedSlider(canvas, pageSize)
drawCheckedSlider(canvas)
} else { // 单独处理normalWidth与checkedWidth不一致的情况
if (mIndicatorOptions.slideMode == IndicatorSlideMode.SCALE) {
for (i in 0 until pageSize) {
drawScaleSlider(canvas, i)
}
} else {
drawInequalitySlider(canvas, pageSize)
}
}
}
}
private fun drawScaleSlider(
canvas: Canvas,
i: Int
) {
val checkedColor = mIndicatorOptions.checkedSliderColor
val indicatorGap = mIndicatorOptions.sliderGap
val sliderHeight = mIndicatorOptions.sliderHeight
val currentPosition = mIndicatorOptions.currentPosition
val normalWidth = mIndicatorOptions.normalSliderWidth
val checkedWidth = mIndicatorOptions.checkedSliderWidth
when {
i < currentPosition -> {
mPaint.color = mIndicatorOptions.normalSliderColor
val left: Float = if (currentPosition == mIndicatorOptions.pageSize - 1) {
(i * normalWidth + i * indicatorGap) + (checkedWidth - normalWidth) * mIndicatorOptions.slideProgress
} else {
(i * normalWidth + i * indicatorGap)
}
mRectF.set(left, 0f, left + normalWidth, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
i == currentPosition -> {
mPaint.color = checkedColor
val slideProgress = mIndicatorOptions.slideProgress
if (currentPosition == mIndicatorOptions.pageSize - 1) {
val evaluate = argbEvaluator?.evaluate(
slideProgress, checkedColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = (evaluate as Int)
val right =
(mIndicatorOptions.pageSize - 1) * (normalWidth + mIndicatorOptions.sliderGap) + checkedWidth
val left = right - checkedWidth + (checkedWidth - normalWidth) * (slideProgress)
mRectF.set(left, 0f, right, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
} else {
if (slideProgress < 1) {
val evaluate = argbEvaluator?.evaluate(
slideProgress, checkedColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = (evaluate as Int)
val left = i * normalWidth + i * indicatorGap
val right = left + normalWidth + (checkedWidth - normalWidth) * (1 - slideProgress)
mRectF.set(left, 0f, right, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
}
if (currentPosition == mIndicatorOptions.pageSize - 1) {
if (slideProgress > 0) {
val evaluate = argbEvaluator?.evaluate(
1 - slideProgress, checkedColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = evaluate as Int
val left = 0f
val right = left + normalWidth + (checkedWidth - normalWidth) * slideProgress
mRectF.set(left, 0f, right, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
} else {
if (slideProgress > 0) {
val evaluate = argbEvaluator?.evaluate(
1 - slideProgress, checkedColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = evaluate as Int
val right =
i * normalWidth + i * indicatorGap + normalWidth + (indicatorGap + checkedWidth)
val left = right - (normalWidth) - (checkedWidth - normalWidth) * (slideProgress)
mRectF.set(left, 0f, right, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
}
}
else -> {
if ((currentPosition + 1 != i || mIndicatorOptions.slideProgress == 0f)) { // 避免多余绘制
mPaint.color = mIndicatorOptions.normalSliderColor
val left = i * minWidth + i * indicatorGap + (checkedWidth - minWidth)
mRectF.set(left, 0f, left + minWidth, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
}
}
}
private fun drawUncheckedSlider(
canvas: Canvas,
pageSize: Int
) {
for (i in 0 until pageSize) {
mPaint.color = mIndicatorOptions.normalSliderColor
val left = i * maxWidth + i * +mIndicatorOptions.sliderGap + (maxWidth - minWidth)
mRectF.set(left, 0f, left + minWidth, mIndicatorOptions.sliderHeight)
drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight)
}
}
private fun drawInequalitySlider(
canvas: Canvas,
pageSize: Int
) {
var left = 0f
for (i in 0 until pageSize) {
val sliderWidth = (if (i == mIndicatorOptions.currentPosition) maxWidth else minWidth)
mPaint.color =
if (i == mIndicatorOptions.currentPosition) mIndicatorOptions.checkedSliderColor else mIndicatorOptions.normalSliderColor
mRectF.set(left, 0f, left + sliderWidth, mIndicatorOptions.sliderHeight)
drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight)
left += sliderWidth + mIndicatorOptions.sliderGap
}
}
private fun drawCheckedSlider(canvas: Canvas) {
mPaint.color = mIndicatorOptions.checkedSliderColor
when (mIndicatorOptions.slideMode) {
IndicatorSlideMode.SMOOTH -> drawSmoothSlider(canvas)
IndicatorSlideMode.WORM -> drawWormSlider(canvas)
IndicatorSlideMode.COLOR -> drawColorSlider(canvas)
}
}
private fun drawColorSlider(canvas: Canvas) {
val currentPosition = mIndicatorOptions.currentPosition
val slideProgress = mIndicatorOptions.slideProgress
val left = currentPosition * minWidth + currentPosition * mIndicatorOptions.sliderGap
if (slideProgress < 0.99) {
val evaluate = argbEvaluator?.evaluate(
slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = (evaluate as Int)
mRectF.set(left, 0f, left + minWidth, mIndicatorOptions.sliderHeight)
drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight)
}
var nextSliderLeft = left + mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth
if (currentPosition == mIndicatorOptions.pageSize - 1) {
nextSliderLeft = 0f
}
val evaluate = argbEvaluator?.evaluate(
1 - slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor
)
mPaint.color = evaluate as Int
mRectF.set(nextSliderLeft, 0f, nextSliderLeft + minWidth, mIndicatorOptions.sliderHeight)
drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight)
}
private fun drawWormSlider(canvas: Canvas) {
val sliderHeight = mIndicatorOptions.sliderHeight
val slideProgress = mIndicatorOptions.slideProgress
val currentPosition = mIndicatorOptions.currentPosition
val distance = mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth
val startCoordinateX =
IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition)
val left = startCoordinateX + (distance * (slideProgress - 0.5f) * 2.0f).coerceAtLeast(
0f
) - mIndicatorOptions.normalSliderWidth / 2
val right = startCoordinateX + (distance * slideProgress * 2f).coerceAtMost(
distance
) + mIndicatorOptions.normalSliderWidth / 2
mRectF.set(left, 0f, right, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
private fun drawSmoothSlider(canvas: Canvas) {
val currentPosition = mIndicatorOptions.currentPosition
val indicatorGap = mIndicatorOptions.sliderGap
val sliderHeight = mIndicatorOptions.sliderHeight
val left =
currentPosition * maxWidth + currentPosition * +indicatorGap + (maxWidth + indicatorGap) * mIndicatorOptions.slideProgress
mRectF.set(left, 0f, left + maxWidth, sliderHeight)
drawRoundRect(canvas, sliderHeight, sliderHeight)
}
protected open fun drawRoundRect(
canvas: Canvas,
rx: Float,
ry: Float
) {
drawDash(canvas)
}
protected open fun drawDash(canvas: Canvas) {}
}

View File

@@ -0,0 +1,24 @@
package com.mogo.och.taxi.passenger.widget.indicator.drawer
import android.graphics.Canvas
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhpan on 2019/11/26.
* Description:
</pre> *
*/
class RoundRectDrawer internal constructor(indicatorOptions: IndicatorOptions) : RectDrawer(
indicatorOptions
) {
override fun drawRoundRect(
canvas: Canvas,
rx: Float,
ry: Float
) {
canvas.drawRoundRect(mRectF, rx, ry, mPaint)
}
}

View File

@@ -0,0 +1,16 @@
package com.mogo.och.taxi.passenger.widget.indicator.enums
import android.widget.LinearLayout
/**
*
* @author zhangpan
* @date 2021/1/21
*/
class IndicatorOrientation {
companion object {
const val INDICATOR_HORIZONTAL = LinearLayout.HORIZONTAL
const val INDICATOR_VERTICAL = LinearLayout.VERTICAL
const val INDICATOR_RTL = 3
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.och.taxi.passenger.widget.indicator.enums
/**
* <pre>
* Created by zhangpan on 2019-10-18.
* Description:
</pre> *
*/
interface IndicatorSlideMode {
companion object {
const val NORMAL = 0
const val SMOOTH = 2
const val WORM = 3
const val SCALE = 4
const val COLOR = 5
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.och.taxi.passenger.widget.indicator.enums
/**
* <pre>
* Created by zhangpan on 2019-10-18.
* Description:
</pre> *
*/
interface IndicatorStyle {
companion object {
const val CIRCLE = 0
const val DASH = 1 shl 1
const val ROUND_RECT = 1 shl 2
}
}

View File

@@ -0,0 +1,38 @@
package com.mogo.och.taxi.passenger.widget.indicator.option;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.mogo.och.taxi.passenger.R;
import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils;
public class AttrsController {
public static void initAttrs(@NonNull Context context, @Nullable AttributeSet attrs,
IndicatorOptions indicatorOptions) {
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView);
int indicatorSlideMode = typedArray.getInt(R.styleable.IndicatorView_vpi_slide_mode, 0);
int indicatorStyle = typedArray.getInt(R.styleable.IndicatorView_vpi_style, 0);
int checkedColor = typedArray.getColor(R.styleable.IndicatorView_vpi_slider_checked_color,
Color.parseColor("#6C6D72"));
int normalColor = typedArray.getColor(R.styleable.IndicatorView_vpi_slider_normal_color,
Color.parseColor("#8C18171C"));
int orientation = typedArray.getInt(R.styleable.IndicatorView_vpi_orientation, 0);
float radius = typedArray.getDimension(R.styleable.IndicatorView_vpi_slider_radius,
IndicatorUtils.dp2px(8));
indicatorOptions.setCheckedColor(checkedColor);
indicatorOptions.setNormalSliderColor(normalColor);
indicatorOptions.setOrientation(orientation);
indicatorOptions.setIndicatorStyle(indicatorStyle);
indicatorOptions.setSlideMode(indicatorSlideMode);
indicatorOptions.setSliderWidth(radius * 2, radius * 2);
typedArray.recycle();
}
}
}

View File

@@ -0,0 +1,108 @@
package com.mogo.och.taxi.passenger.widget.indicator.option
import android.graphics.Color
import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorOrientation
import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorStyle
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils
/**
* <pre>
* Created by zhpan on 2019/11/20.
* Description:Indicator的配置参数
</pre> *
*/
class IndicatorOptions {
@AIndicatorOrientation
var orientation = IndicatorOrientation.INDICATOR_HORIZONTAL
@AIndicatorStyle
var indicatorStyle: Int = 0
/**
* Indicator滑动模式目前仅支持两种
*
* @see IndicatorSlideMode.NORMAL
*
* @see IndicatorSlideMode.SMOOTH
*/
@AIndicatorSlideMode
var slideMode: Int = 0
/**
* 页面size
*/
var pageSize: Int = 0
/**
* 未选中时Indicator颜色
*/
var normalSliderColor: Int = 0
/**
* 选中时Indicator颜色
*/
var checkedSliderColor: Int = 0
/**
* Indicator间距
*/
var sliderGap: Float = 0f
var sliderHeight: Float = 0f
get() = if (field > 0) field else normalSliderWidth / 2
var normalSliderWidth: Float = 0f
var checkedSliderWidth: Float = 0f
/**
* 指示器当前位置
*/
var currentPosition: Int = 0
/**
* 从一个点滑动到另一个点的进度
*/
var slideProgress: Float = 0f
var showIndicatorOneItem: Boolean = false
init {
normalSliderWidth = IndicatorUtils.dp2px(8f)
.toFloat()
checkedSliderWidth = normalSliderWidth
sliderGap = normalSliderWidth
normalSliderColor = Color.parseColor("#8C18171C")
checkedSliderColor = Color.parseColor("#8C6C6D72")
slideMode = IndicatorSlideMode.NORMAL
}
fun setCheckedColor(checkedColor: Int) {
this.checkedSliderColor = checkedColor
}
fun setSliderWidth(
normalIndicatorWidth: Float,
checkedIndicatorWidth: Float
) {
this.normalSliderWidth = normalIndicatorWidth
this.checkedSliderWidth = checkedIndicatorWidth
}
fun setSliderWidth(sliderWidth: Float) {
setSliderWidth(sliderWidth, sliderWidth)
}
fun setSliderColor(
normalColor: Int,
checkedColor: Int
) {
this.normalSliderColor = normalColor
this.checkedSliderColor = checkedColor
}
}

View File

@@ -0,0 +1,32 @@
package com.mogo.och.taxi.passenger.widget.indicator.utils
import android.content.res.Resources
import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions
/**
* <pre>
* Created by zhangpan on 2020-01-20.
* Description:
</pre> *
*/
object IndicatorUtils {
@JvmStatic
fun dp2px(dpValue: Float): Int {
return (0.5f + dpValue * Resources.getSystem().displayMetrics.density).toInt()
}
fun getCoordinateX(
indicatorOptions: IndicatorOptions,
maxDiameter: Float,
index: Int
): Float {
val normalIndicatorWidth = indicatorOptions.normalSliderWidth
return maxDiameter / 2 + (normalIndicatorWidth + indicatorOptions.sliderGap) * index
}
fun getCoordinateY(maxDiameter: Float): Float {
return maxDiameter / 2
}
}

View File

@@ -42,6 +42,21 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_mogo_consult"/>
<com.mogo.och.taxi.passenger.widget.indicator.IndicatorView
android:id="@+id/indicatorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rv_video_playlist"
android:layout_marginTop="95px"
app:vpi_orientation="horizontal"
app:vpi_slide_mode="scale"
app:vpi_slider_checked_color="@color/taxi_p_traffic_light_red_color_up"
app:vpi_slider_normal_color="@color/taxi_p_check_keyboard_input_field"
app:vpi_slider_radius="@dimen/dp_20"
app:vpi_style="round_rect" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="IndicatorView">
<attr name="vpi_slider_checked_color" format="color" />
<attr name="vpi_slider_normal_color" format="color" />
<attr name="vpi_slider_radius" format="dimension" />
<attr name="vpi_rtl" format="boolean" />
<attr name="vpi_orientation" format="enum">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
<enum name="rtl" value="3"/>
</attr>
<attr name="vpi_slide_mode" format="enum">
<enum name="normal" value="0" />
<enum name="smooth" value="2" />
<enum name="worm" value="3" />
<enum name="scale" value="4" />
<enum name="color" value="5" />
</attr>
<attr name="vpi_style" format="enum">
<enum name="circle" value="0" />
<enum name="dash" value="2" />
<enum name="round_rect" value="4" />
</attr>
</declare-styleable>
</resources>