观察者模式的一次实践

本文介绍了在Android直播端实现美颜与滤镜联动功能的技术方案,使用tablayout+viewpager布局,通过drawable自定义tab指示器。数据管理采用观察者模式,将美颜和滤镜数据存储在BeautyDataManager中,当数据变化时,通过Observer通知adapter更新。这种设计实现了美颜和滤镜选择的同步,并保持了代码的解耦。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 项目需求背景:

直播端有个美颜设置功能,如下:
在这里插入图片描述
在这里插入图片描述

2. 实现方式:

先说布局:
看完交互之后,决定采用tablayout+viewpager

  1. 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" />
  1. 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也会自然被选中。同理也是如此。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值