1. 项目需求背景:
直播端有个美颜设置功能,如下:
2. 实现方式:
先说布局:
看完交互之后,决定采用tablayout+viewpager
- tablayout指示器长度的改变:
网上有采用反射或是第三方控件来改变indicator长度,这里我们直接用drawable方式
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="20dp"
android:gravity="center">
<shape>
<corners android:radius="90dp" />
<size android:height="3dp" />
<solid android:color="#ff445e" />
</shape>
</item>
</layer-list>
//布局中引入:
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="0dp"
android:layout_height="@dimen/dp_36"
app:layout_constraintLeft_toRightOf="@id/tvReset"
app:layout_constraintRight_toLeftOf="@id/ivClose"
app:layout_constraintTop_toTopOf="parent"
app:tabIndicator="@drawable/layer_tab_indicator"
app:tabMode="auto"
app:tabSelectedTextColor="@color/colorFF445E"
app:tabTextColor="@color/color3C3C3C" />
- viewpager放置美颜和滤镜:
有个交互细节:当选中某个美颜item的时候,滤镜对应位置的item也要被选中,同理,选中某个滤镜item,对应位置的美颜item也要被选中。
总体设计是这样的:viewpager里面放adapter(这个是放美颜/滤镜面板),adapter里面再放adapter(这个是美颜/滤镜 item)。
因为美颜/滤镜布局是一样的,只是数据不同,所以我采用了同一个adapter. 数据变动之后(比如用户选中美颜item2, 要通知滤镜在item2位置也是要被选中的,同理也是如此,写着写着发现这就类似一个套餐),因为数据变动要互相通知,这里采用了观察者模式。
设计如下:
① 美颜数据和滤镜数据放在一个单独的data manager中
data bean 设计如下:
data class BeautyData(
var icon: Int,//图标
var name: String,//名称
var postion: Int,//位置
var isChecked: Boolean = false,//是否别选中
var progress: Int = 0// 美颜级别/滤镜级别
)
data manager设计如下,继承Observable
object BeautyDataManager : Observable() {
var mBeautyDataList: MutableList<BeautyData> = mutableListOf()//美颜数据
var mFilterDataList: MutableList<BeautyData> = mutableListOf() // 滤镜数据
init {
initBeautyData()
initFilterData()
}
}
②data manage 中暴露对美颜/滤镜的操作,示例如下:对数据操作会后,要调用 setChanged和notifyObservers
fun setBeautyChanged(position: Int) {
/*******
*******距离逻辑实现部分,可以不看*/
val beautyChecked = isBeautyChecked(mBeautyDataList)
val filterChecked = isFilterChecked(mFilterDataList)
if (!beautyChecked && !filterChecked) {
if (whoFirst != 1) {
whoFirst = 2//说明filter先点击
}
}
val beautyLastPosition = getBeautyLastPosition()
val filterLastPosition = getFilterLastPosition()
resetFilerData()
for (i in mFilterDataList.indices) {
if (i == position) {
mFilterDataList[i].isChecked = true
break
}
}
if (!beautyChecked && !filterChecked) {
for (i in mBeautyDataList.indices) {
if (i == position) {
mBeautyDataList[i].isChecked = true
break
}
}
} else {//有一个已经是选中状态了
if (whoFirst == 2) {
if (beautyLastPosition == filterLastPosition) {
for (i in mBeautyDataList.indices) {
if (i == position) {
resetBeautyData()
mBeautyDataList[i].isChecked = true
break
}
}
}
}
}
/***重要的是这一行**/
setChanged()
notifyObservers()// 通知观察者
}
③adapter注册Observable并实现Observer
class BeautyAdapter :
BaseQuickAdapter<BeautyData, BaseDataBindingHolder<ItemLiveBeautyBinding>>(R.layout.item_live_beauty),
Observer {
/***
**注册事件源
*/
fun registerObserver(observable: Observable) {
observable.addObserver(this)
}
/***
**反注册
*/
fun unregisterObserver(observable: Observable) {
observable.deleteObserver(this)
}
/**
**数据源 datamanger中有数据更新的时候,回调通知此方法
*/
override fun update(o: Observable?, arg: Any?) {
if (o is BeautyDataManager) {
Timber.d("data is update")
notifyDataSetChanged()
}
}
}
采用观察者模式,数据单独放在一个data manager中,所有对数据的操作都是在data manger中进行,再由manager通知观察者,数据做了变更。这样做的最大好处是解耦。布局仅仅是展示作用。
3. 实际效果:
当点击美颜中第二个item的时候,滤镜中的第二个item也会自然被选中。同理也是如此。