feat : 重写 装扮商城 , 我的装扮 , 装扮赠送 页面

This commit is contained in:
eggmanQQQ
2024-11-20 15:06:13 +08:00
parent a48f768434
commit e0b348f92a
98 changed files with 6761 additions and 347 deletions

View File

@@ -314,6 +314,12 @@
<activity
android:name=".ui.user.activity.UserCpListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".decoration.ui.activity.DressUpTabActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.search.SearchUserActivity"
android:screenOrientation="portrait" />
<activity
android:name=".audio.AudioRecordActivity"
android:label="@string/main_androidmanifest_017"

View File

@@ -5,8 +5,8 @@ import android.graphics.Bitmap
import android.view.LayoutInflater
import com.chwl.app.databinding.RoomNotifyCpBindBinding
import com.chwl.app.ui.utils.CpUtils
import com.chwl.app.ui.utils.isDestroyed
import com.chwl.core.gift.bean.CpMsgBean
import com.chwl.core.utils.LogUtils
import com.tencent.qgame.animplayer.inter.IFetchResource
import com.tencent.qgame.animplayer.mix.Resource
import com.tencent.qgame.animplayer.util.ScaleType
@@ -78,7 +78,9 @@ class RoomNotifyCpBindDialog (private val context: Context) : BaseRoomNotifyDial
fun checkImg() {
if (index == 2){
show()
if (!context.isDestroyed()) {
show()
}
}
}

View File

@@ -193,9 +193,9 @@ public class GiftEffectView extends RelativeLayout {
return;
}
if (giftInfo.getOtherViewType() == 1 && !TextUtils.isEmpty(giftInfo.getViewUrl())) {
drawVAPEffect(giftInfo.getViewUrl());
drawVAPEffect(giftInfo.getViewUrl().trim());
} else if (giftInfo.isHasVggPic() && !StringUtil.isEmpty(giftInfo.getVggUrl())) {
drawSvgaEffect(giftInfo.getVggUrl());
drawSvgaEffect(giftInfo.getVggUrl().trim());
} else {
effectHandler.sendEmptyMessage(0);
}
@@ -205,26 +205,33 @@ public class GiftEffectView extends RelativeLayout {
}
private void drawSvgaEffect(String url) {
log("drawSvgaEffect url:" + url);
log("drawEffect drawSvgaEffect url:" + url);
GlideUtils.instance().downloadFromUrl(getContext(), url, new RequestListener<File>() {
GlideUtils.instance().downloadFromUrl2(getContext(), url, new RequestListener<File>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
log("drawSvgaEffect onDownloadError url:" + url);
String message = "";
if (e != null) {
message = e.getMessage();
}
log("drawEffect drawSvgaEffect onDownloadError url:" + url + " error = "+message);
effectHandler.sendEmptyMessage(0);
return true;
}
@Override
public boolean onResourceReady(File resource, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
String path = "";
if (resource != null) {
String path = resource.getPath();
log("drawSvgaEffect onDownloadCompleted url:" + url + " path:" + path);
path = resource.getPath();
drawSvgaEffectFile(path);
} else {
effectHandler.sendEmptyMessage(0);
}
log("drawEffect drawSvgaEffect onDownloadCompleted url:" + url + " path:" + path);
return true;
}
});
@@ -257,23 +264,33 @@ public class GiftEffectView extends RelativeLayout {
}
}
private void drawVAPEffect(String url) {
log("drawVAPEffect url:" + url);
GlideUtils.instance().downloadFromUrl(getContext(), url, new RequestListener<File>() {
private void drawVAPEffect(String url) {
log("drawEffect drawVAPEffect url:" + url);
GlideUtils.instance().downloadFromUrl2(getContext(), url, new RequestListener<File>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
log("drawVAPEffect onDownloadError url:" + url);
String message = "";
if (e != null) {
message = e.getMessage();
}
log("drawEffect drawVAPEffect onDownloadError url:" + url + " error = "+message);
effectHandler.sendEmptyMessageDelayed(0, 4000);
return true;
}
@Override
public boolean onResourceReady(File resource, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
String path = "";
if (resource != null) {
log("drawVAPEffect onDownloadCompleted url:" + url + " path:" + resource.getPath());
path = resource.getPath();
vapAnimView.startPlay(resource);
} else {
effectHandler.sendEmptyMessage(0);
}
log("drawEffect drawVAPEffect onDownloadCompleted url:" + url + " path:" + path);
return true;
}
});

View File

@@ -46,34 +46,11 @@ import androidx.fragment.app.FragmentManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chwl.app.notify.GlobalNotifyManager;
import com.chwl.app.utils.RoomBoomManager;
import com.chwl.core.gift.bean.BoomMsgAnimBean;
import com.chwl.core.gift.bean.BoomMsgDialogBean;
import com.chwl.core.im.custom.bean.BoomMsgAttachment;
import com.chwl.core.manager.AvRoomDataManager;
import com.chwl.core.utils.LogUtils;
import com.chwl.library.language.LanguageHelper;
import com.example.lib_utils.UiUtils;
import com.google.gson.Gson;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nimlib.chatroom.model.ChatRoomMessageImpl;
import com.netease.nimlib.sdk.NIMSDK;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage;
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
import com.netease.nimlib.sdk.msg.model.BroadcastMessage;
import com.netease.nimlib.session.IMMessageImpl;
import com.orhanobut.logger.Logger;
import com.readystatesoftware.systembartint.SystemBarTintManager;
import com.tbruyelle.rxpermissions2.RxPermissions;
import com.trello.rxlifecycle3.android.ActivityEvent;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import com.chwl.app.NimMiddleActivity;
import com.chwl.app.R;
import com.chwl.app.application.App;
import com.chwl.app.application.IReportConstants;
import com.chwl.app.application.ReportManager;
import com.chwl.app.application.App;
import com.chwl.app.avroom.activity.AVRoomActivity;
import com.chwl.app.common.LoadingFragment;
import com.chwl.app.common.NetworkErrorFragment;
@@ -83,6 +60,7 @@ import com.chwl.app.common.permission.PermissionActivity;
import com.chwl.app.common.widget.StatusLayout;
import com.chwl.app.common.widget.dialog.DialogManager;
import com.chwl.app.common.widget.dialog.DialogUiHelper;
import com.chwl.app.notify.GlobalNotifyManager;
import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity;
import com.chwl.app.ui.login.AddUserInfoActivity;
import com.chwl.app.ui.login.LoginCodeActivity;
@@ -94,14 +72,18 @@ import com.chwl.app.ui.widget.dialog.AllPlayEffectDialog;
import com.chwl.app.ui.widget.dialog.AllServiceGiftLevelDialog;
import com.chwl.app.ui.widget.dialog.AllServiceVipLevelUPDialog;
import com.chwl.app.ui.widget.dialog.OpenNobleGlobalNoticeDialog;
import com.chwl.app.utils.RoomBoomManager;
import com.chwl.app.utils.UserUtils;
import com.chwl.core.XConstants;
import com.chwl.core.bean.BaseProtocol;
import com.chwl.core.gift.bean.BoomMsgDialogBean;
import com.chwl.core.im.custom.bean.BoomMsgAttachment;
import com.chwl.core.im.custom.bean.CustomAttachment;
import com.chwl.core.im.custom.bean.NotifyH5Info;
import com.chwl.core.im.custom.bean.PlayEffectInfo;
import com.chwl.core.im.custom.bean.RoomLuckySeaMsgBean;
import com.chwl.core.im.custom.bean.TarotMsgBean;
import com.chwl.core.manager.AvRoomDataManager;
import com.chwl.core.manager.IMNetEaseManager;
import com.chwl.core.manager.RoomEvent;
import com.chwl.core.mentoring_relationship.event.GrabApprenticesEvent;
@@ -115,8 +97,10 @@ import com.chwl.core.pay.bean.WalletInfo;
import com.chwl.core.room.model.AvRoomModel;
import com.chwl.core.treasurefairy.bean.FairyMsgInfoBean;
import com.chwl.core.user.UserModel;
import com.chwl.core.utils.LogUtils;
import com.chwl.core.utils.net.RxHelper;
import com.chwl.core.vip.bean.VipMessageInfo;
import com.chwl.library.language.LanguageHelper;
import com.chwl.library.rxbus.RxBus;
import com.chwl.library.utils.NetworkUtils;
import com.chwl.library.utils.ResUtil;
@@ -125,6 +109,22 @@ import com.chwl.library.utils.UIUtils;
import com.chwl.library.utils.codec.DESUtils;
import com.chwl.library.utils.config.BasicConfig;
import com.chwl.library.utils.log.MLog;
import com.example.lib_utils.UiUtils;
import com.google.gson.Gson;
import com.netease.nim.uikit.StatusBarUtil;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nimlib.chatroom.model.ChatRoomMessageImpl;
import com.netease.nimlib.sdk.NIMSDK;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage;
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
import com.netease.nimlib.sdk.msg.model.BroadcastMessage;
import com.netease.nimlib.session.IMMessageImpl;
import com.orhanobut.logger.Logger;
import com.readystatesoftware.systembartint.SystemBarTintManager;
import com.tbruyelle.rxpermissions2.RxPermissions;
import com.trello.rxlifecycle3.android.ActivityEvent;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -276,7 +276,7 @@ public abstract class BaseActivity extends RxAppCompatActivity
}
}
public void initBlackTitleBar(String title) {
public void initDarkTitleBar(String title) {
mTitleBar = findViewById(R.id.title_bar);
if (mTitleBar != null) {
mTitleBar.setTitle(title);
@@ -285,6 +285,21 @@ public abstract class BaseActivity extends RxAppCompatActivity
mTitleBar.setLeftImageResource(R.drawable.icon_user_back);
mTitleBar.setBackgroundResource(R.color.transparent);
mTitleBar.setLeftClickListener(v -> onLeftClickListener());
StatusBarUtil.StatusBarLightMode(this,false);
StatusBarUtil.transparencyBar(this);
}
}
public void initLightTitleBar(String title) {
mTitleBar = findViewById(R.id.title_bar);
if (mTitleBar != null) {
mTitleBar.setTitle(title);
mTitleBar.setImmersive(false);
mTitleBar.setTitleColor(getResources().getColor(R.color.text_title_color));
mTitleBar.setLeftImageResource(R.drawable.arrow_left);
mTitleBar.setBackgroundResource(R.color.transparent);
mTitleBar.setLeftClickListener(v -> onLeftClickListener());
StatusBarUtil.StatusBarLightMode(this,true);
StatusBarUtil.transparencyBar(this);
}
}

View File

@@ -5,7 +5,11 @@ import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.*
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
@@ -27,6 +31,7 @@ abstract class BaseDialogFragment<T : ViewBinding> : RxDialogFragment() {
open var height = WindowManager.LayoutParams.WRAP_CONTENT
open var gravity = Gravity.CENTER
open var dimAmount = 0.5f
var mActionCallBack : Action?= null
override fun onStart() {
super.onStart()
@@ -120,4 +125,8 @@ abstract class BaseDialogFragment<T : ViewBinding> : RxDialogFragment() {
}
abstract fun init()
public interface Action{
fun <D:Any>onAction(type:Int,data:D?)
}
}

View File

@@ -0,0 +1,108 @@
package com.chwl.app.base
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chwl.app.R
import com.chwl.app.bindadapter.BaseBindingAdapter
import com.chwl.app.databinding.BaseListFragmentBinding
import com.chwl.library.common.util.setVis
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadmoreListener
abstract class BaseListFragment<D:Any>:
BaseViewBindingFragment<BaseListFragmentBinding>() {
lateinit var mAdapter: BaseBindingAdapter<*, D>
protected var mPageSize = 20;
protected var mPage = 1;
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = BaseListFragmentBinding.inflate(layoutInflater)
return binding.root
}
override fun init() {
mAdapter = getAdapter()
binding.rvList.layoutManager = getLayoutManager()
binding.rvList.adapter = mAdapter
binding.srlLayout.setOnRefreshLoadmoreListener(object : OnRefreshLoadmoreListener {
override fun onRefresh(refreshlayout: RefreshLayout?) {
onRefresh()
}
override fun onLoadmore(refreshlayout: RefreshLayout?) {
onLoad()
}
})
mAdapter.onItemClickListener = BaseQuickAdapter.OnItemClickListener { adapter, view, position ->
onItemClicks(mAdapter, view, position)
}
mAdapter.onItemChildClickListener = BaseQuickAdapter.OnItemChildClickListener { adapter, view, position ->
onItemChildClicks(mAdapter, view, position)
}
initView()
}
abstract fun getAdapter(): BaseBindingAdapter<*, D>
protected open fun getLayoutManager(): RecyclerView.LayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
protected open fun hasTitle(): Boolean = false
protected open fun onItemClicks(
adapter: BaseBindingAdapter<*, D>?,
view: View?,
position: Int
) {}
protected open fun onItemChildClicks(
adapter: BaseBindingAdapter<*, D>?,
view: View?,
position: Int
) {}
abstract fun onLoad()
abstract fun onRefresh()
abstract fun initView()
protected open fun stopAnim() {
binding.srlLayout.finishLoadmore()
binding.srlLayout.finishRefresh()
}
var mTitleBar : TitleBar?=null
open fun initWhiteTitleBar(title: String?,listener:View.OnClickListener) {
mTitleBar = _binding?.root?.findViewById<TitleBar>(R.id.title_bar)
if (mTitleBar != null) {
mTitleBar?.setTitle(title)
mTitleBar?.setImmersive(false)
mTitleBar?.setTitleColor(resources.getColor(R.color.text_title_color))
mTitleBar?.setLeftImageResource(R.drawable.arrow_left)
mTitleBar?.setBackgroundResource(R.color.transparent)
mTitleBar?.setLeftClickListener(listener)
mTitleBar?.setVis(true)
}
}
fun initBlackTitleBar(title: String?,listener:View.OnClickListener) {
mTitleBar = _binding?.root?.findViewById<TitleBar>(R.id.title_bar)
if (mTitleBar != null) {
mTitleBar?.setTitle(title)
mTitleBar?.setImmersive(false)
mTitleBar?.setTitleColor(resources.getColor(R.color.white))
mTitleBar?.setLeftImageResource(R.drawable.icon_user_back)
mTitleBar?.setBackgroundResource(R.color.transparent)
mTitleBar?.setLeftClickListener(listener)
mTitleBar?.setVis(true)
}
}
}

View File

@@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import androidx.annotation.Nullable
import androidx.viewbinding.ViewBinding
import com.netease.nim.uikit.StatusBarUtil
import java.lang.reflect.ParameterizedType
@@ -20,6 +21,11 @@ abstract class BaseViewBindingActivity<T : ViewBinding> : BaseActivity(){
val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
binding = method.invoke(null,layoutInflater) as T
setContentView(binding.root)
if (transparencyBar()) {
StatusBarUtil.transparencyBar(this)
}
init()
}
@@ -29,4 +35,5 @@ abstract class BaseViewBindingActivity<T : ViewBinding> : BaseActivity(){
protected open fun initBefore(@Nullable savedInstanceState: Bundle?) {}
abstract fun init()
protected open fun transparencyBar():Boolean=false
}

View File

@@ -15,8 +15,8 @@ open class BaseBindingAdapter<VB : ViewBinding?, T>() : BaseQuickAdapter<T, Base
//反射没有想象中的那么耗时
val type = javaClass.genericSuperclass as ParameterizedType
val aClass = type.actualTypeArguments[0] as Class<*>
val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
val binding = method.invoke(null, mLayoutInflater) as VB
val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java,ViewGroup::class.java, Boolean::class.java)
val binding = method.invoke(null, mLayoutInflater,parent,false) as VB
val view = binding?.root?:return View(mContext)
view.setTag(R.id.BaseQuickAdapter_databinding_support, binding)
return view

View File

@@ -0,0 +1,99 @@
package com.chwl.app.decoration.adapter
import android.view.Gravity
import com.chwl.app.R
import com.chwl.app.bindadapter.BaseBindingAdapter
import com.chwl.app.bindadapter.BaseBindingViewHolder
import com.chwl.app.databinding.ItemDressUpLayoutBinding
import com.chwl.app.decoration.ui.activity.DressUpTabActivity
import com.chwl.app.decoration.util.DressUpUtil
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.library.common.util.isVerify
import com.chwl.library.common.util.setVis
import com.example.lib_utils.ktx.getString
class DressUpAdapter : BaseBindingAdapter<ItemDressUpLayoutBinding, DressUpInfo>() {
override fun convert(
helper: BaseBindingViewHolder<ItemDressUpLayoutBinding>,
item: DressUpInfo
) {
val binding = helper.binding
setViewDef(binding)
if (item.isSelect) {
binding.root.setBackgroundResource(R.drawable.ic_dress_item_s)
} else {
binding.root.setBackgroundResource(R.drawable.ic_dress_item_n)
}
if (item.isNull) {
binding.empty.setVis(true)
binding.name.text = R.string.Not_used.getString()
binding.name.setVis(true)
return
}
DressUpUtil.setItemPic(item,binding.picLayout)
binding.picLayout.setVis(true)
binding.name.text = item.name
binding.name.gravity = if (item.isMy) Gravity.CENTER else Gravity.START
binding.name.setVis(true)
DressUpUtil.setTextPrice(binding.price,item)
binding.price.setVis(!item.isMy)
binding.discount.text = item.discount.toString()
binding.discount.setVis(!item.isMy)
if (item.dressType != DressUpTabActivity.TAB_USER_CARD && item.effect.isVerify()) {
binding.btnPlay.setVis(true)
} else {
binding.btnPlay.setVis(false)
}
if (item.isMy) {
if (item.isHasExpired) {
binding.limit.setVis(true)
binding.limit.text = R.string.Expired.getString()
} else {
if (item.expireDays != -1) {
binding.limit.text = R.string.sDays.getString(item.expireDays)
} else {
binding.limit.text = R.string.unDay.getString()
}
}
} else {
if (item.dressLimitStatus != 0) {
binding.limit.setVis(true)
} else {
binding.limit.setVis(false)
}
}
helper.addOnClickListener(R.id.btnPlay)
}
private fun setViewDef(binding : ItemDressUpLayoutBinding) {
// binding.bg.setVis(false)
// binding.picBg.setVis(false)
binding.picLayout.setVis(false)
// binding.name.setVis(false)
binding.price.setVis(false)
binding.discount.setVis(false)
binding.empty.setVis(false)
binding.btnPlay.setVis(false)
binding.limit.setVis(false)
}
}

View File

@@ -37,7 +37,7 @@ public class MyUserCardWearAdapter extends BaseAdapter<UserCardWearInfo> {
ItemMyUserCardWearBinding binding = (ItemMyUserCardWearBinding) helper.getBinding();
binding.ivUserCardWearMp4.setLoop(Integer.MAX_VALUE);
GlideUtils.instance().downloadFromUrl(binding.ivUserCardWearMp4.getContext(), item.getPic(), new RequestListener<File>() {
GlideUtils.instance().downloadFromUrl2(binding.ivUserCardWearMp4.getContext(), item.getPic(), new RequestListener<File>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
ImageLoadUtils.loadImage(mContext, item.getPic(), binding.ivUserCardWear);

View File

@@ -0,0 +1,137 @@
package com.chwl.app.decoration.ui
import android.view.Gravity
import com.chwl.app.R
import com.chwl.app.base.BaseDialogFragment
import com.chwl.app.databinding.DialogDressUpBinding
import com.chwl.app.decoration.util.DressUpUtil
import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.core.utils.net.RxHelper
import com.chwl.library.common.util.ClickUtils.click
import com.chwl.library.common.util.doToast
import com.chwl.library.net.rxnet.RxNet
import com.example.lib_utils.ktx.dp
import com.example.lib_utils.ktx.getString
import com.hjq.toast.ToastUtils
import io.reactivex.Single
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
class DressUpDialog : BaseDialogFragment<DialogDressUpBinding>() {
override var width = 284.dp
override var height = 353.dp
override var dimAmount = 0.3f
override var gravity = Gravity.CENTER
var mDressUpInfo : DressUpInfo? = null
var mTargetUid = -1L
override fun init() {
mDressUpInfo?.let {
binding.name.text = it.name
if (it.vipLimit == 0 && it.obtainWay == 1){
DressUpUtil.setTextPrice(binding.price,it)
}else{
if (it.obtainWay != 1) {
binding.price.text = R.string.obtainWayAction.getString()
}else if (it.vipLimit != 0) {
binding.price.text = R.string.vipLimit.getString(it.vipLimit)
}
}
DressUpUtil.setItemPic(it,binding.picLayout)
}
binding.btnBuy.text = if (mTargetUid != -1L) R.string.fairy_give.getString() else R.string.buy.getString()
binding.btnBuy.click {
mDressUpInfo?.let {
if (mTargetUid != -1L) {
postShopGive(it.dressType,it.id,mTargetUid)
.compose(bindToLifecycle())
.doOnSuccess{
ToastUtils.show(R.string.doSuccess)
dismiss()
}
.doOnError {
it?.message?.doToast()
}
.subscribe()
} else {
postShopBuy(it.dressType,it.id)
.compose(bindToLifecycle())
.doOnSuccess{
ToastUtils.show(R.string.doSuccess)
dismiss()
}
.doOnError {
it?.message?.doToast()
}
.subscribe()
}
}
}
binding.btnCancel.click {
dismiss()
}
}
private fun postShopBuy(dressType: Int,id: Int): Single<String> {
return api.postShopBuy(dressType,id)
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private fun postShopGive(dressType: Int,id: Int,targetUid:Long): Single<String> {
return api.postShopGive(dressType,id,targetUid)
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private val api: Api = RxNet.create(Api::class.java);
interface Api {
/**
* 购买装扮
*
* @return
*/
@FormUrlEncoded
@POST("/dress/shop/buy")
fun postShopBuy(
@Field("dressType") dressType: Int,
@Field("id") id: Int
): Single<ServiceResult<String>>
/**
* 赠送装扮
*
* @return
*/
@FormUrlEncoded
@POST("/dress/shop/give")
fun postShopGive(
@Field("dressType") dressType: Int,
@Field("id") id: Int,
@Field("targetUid") targetUid: Long,
): Single<ServiceResult<String>>
}
}

View File

@@ -0,0 +1,213 @@
package com.chwl.app.decoration.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.viewpager2.widget.ViewPager2
import com.alibaba.fastjson.JSON
import com.chwl.app.R
import com.chwl.app.base.BaseViewBindingActivity
import com.chwl.app.databinding.ActivityDressUpTabBinding
import com.chwl.app.databinding.TabDressUpLayoutBinding
import com.chwl.app.decoration.ui.DressUpDialog
import com.chwl.app.decoration.ui.fragment.DressUpMyFragment
import com.chwl.app.decoration.ui.fragment.DressUpStoreFragment
import com.chwl.app.decoration.util.DressUpUtil
import com.chwl.app.event.DressUpEvent
import com.chwl.app.ui.search.SearchUserActivity
import com.chwl.app.ui.utils.loadAvatar
import com.chwl.app.utils.AvatarHelper.loadAvatarFrame
import com.chwl.core.auth.AuthModel
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.core.home.bean.TabInfo
import com.chwl.core.user.UserModel
import com.chwl.library.common.util.ClickUtils.click
import com.chwl.library.common.util.setVis
import com.chwl.library.utils.ResUtil
import com.chwl.library.widget.tab.SmartTabLayout2
import com.chwl.library.widget.tab.TabTitleProvider
import com.chwl.library.widget.tab.util.FragmentPageAdapter
import com.example.lib_utils.ktx.getString
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class DressUpTabActivity : BaseViewBindingActivity<ActivityDressUpTabBinding>() {
private var mDressUpInfo : DressUpInfo ? = null
companion object{
const val TAB_HEAD_WEAR = 0
const val TAB_CAR = 1
const val TAB_NAMEPLATE = 2
const val TAB_USER_CARD = 3
const val TAB_CHAT_BUBBLE = 4
const val TAB_USER_INFO_BG = 5
fun start(context: Context,isMy:Boolean) {
val intent = Intent(context, DressUpTabActivity::class.java)
intent.putExtra("isMy",isMy)
context.startActivity(intent)
}
}
private val isMy : Boolean by lazy { intent.getBooleanExtra("isMy",false) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EventBus.getDefault().register(this)
}
override fun transparencyBar() = true
override fun init() {
if (isMy) {
binding.infoLayout.setVis(true)
binding.btnMyDressUp.setVis(false)
binding.avatar.loadAvatar(UserModel.get().cacheLoginUserInfo?.avatar)
initDarkTitleBar(R.string.decoration_view_mydecorationactivity_01.getString())
} else {
binding.infoLayout.setVis(false)
binding.btnMyDressUp.setVis(true)
initDarkTitleBar(R.string.decoration_view_decorationstoreactivity_01.getString())
}
initTab()
initListener()
if (isMy) {
UserModel.get().getUserInfo(AuthModel.get().currentUid)
.compose(bindToLifecycle())
.doOnSuccess {
it?.userHeadwear?.let { head->
loadAvatarFrame(
binding.avatarHead,
head.getFirstUrl(),
head.type
)
}
}.subscribe()
}
}
val fgLists = arrayListOf<Fragment>()
val tabList = arrayListOf<TabInfo>()
private fun initTab() {
tabList.clear()
tabList.add(TabInfo(TAB_CAR, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_04),R.drawable.ic_dress_tab_car))
tabList.add(TabInfo(TAB_HEAD_WEAR, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_03),R.drawable.ic_dress_tab_head))
tabList.add(TabInfo(TAB_NAMEPLATE, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_05),R.drawable.ic_dress_tab_nameplate))
tabList.add(TabInfo(TAB_USER_CARD, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_06),R.drawable.ic_dress_tab_card))
tabList.add(TabInfo(TAB_CHAT_BUBBLE, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_07),R.drawable.ic_dress_tab_chat))
tabList.add(TabInfo(TAB_USER_INFO_BG, ResUtil.getString(R.string.userInfoBg),R.drawable.ic_dress_tab_homepage))
fgLists.clear()
tabList.forEach {
if (isMy) {
fgLists.add(DressUpMyFragment.newInstance(it.id))
} else {
fgLists.add(DressUpStoreFragment.newInstance(it.id))
}
}
binding.tabLayout.setCustomTabView(SmartTabLayout2.TabProvider { container, position, pageTitle ->
val tabView = TabDressUpLayoutBinding.inflate(this@DressUpTabActivity.layoutInflater,container,false)
tabView.tabText.text = tabList.get(position).name
tabView.tabImg.setImageResource(tabList.get(position).res)
// tabView.root.layoutParams = LinearLayout.LayoutParams(
// LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT
// )
return@TabProvider tabView.root
})
val pageAdapter = FragmentPageAdapter(this,fgLists)
binding.tabLayout.setViewPager(binding.viewPage,pageAdapter,object : TabTitleProvider {
override fun getPageTitle(position: Int): CharSequence? {
return tabList.get(position).name
}
})
binding.viewPage.offscreenPageLimit = 6
binding.viewPage.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
selectTab(position)
mDressUpInfo = null
binding.bottomView.visibility = View.INVISIBLE
}
})
}
private fun initListener() {
binding.btnBuy.click {
mDressUpInfo?.let {
val dressUpDialog = DressUpDialog()
dressUpDialog.mDressUpInfo = it
dressUpDialog.show(context)
}
}
binding.btnGive.click {
mDressUpInfo?.let {
SearchUserActivity.start(context,JSON.toJSONString(it))
}
}
binding.btnMyDressUp.click {
DressUpTabActivity.start(context,true)
}
binding.playLayout.click {
binding.playLayout.setVis(false)
binding.playLayout.removeAllViews()
}
}
private fun selectTab(pos: Int) {
for (i in 0 until tabList.size) {
val tabAt = binding.tabLayout.getTabAt(i)
val tabView = TabDressUpLayoutBinding.bind(tabAt)
tabView.tabBg.setBackgroundResource(if (pos == i) R.drawable.ic_dress_tab_bg_s else R.drawable.ic_dress_tab_bg_n)
tabView.tabText.alpha = if (pos == i) 1f else 0.5f
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onDressUpEvent(event: DressUpEvent) {
val data = event.data
when (event.action) {
DressUpEvent.Action.Select -> {
mDressUpInfo = data
binding.bottomView.setVis(true)
DressUpUtil.setTextPrice(binding.price,data)
if (isMy) {
if (data.dressType == TAB_HEAD_WEAR) {
binding.avatarHead.loadUrl(data.effect)
}
}
}
DressUpEvent.Action.Play -> {
DressUpUtil.play(data,binding.playLayout)
}
else -> {}
}
}
override fun onDestroy() {
super.onDestroy()
EventBus.getDefault().unregister(this)
}
}

View File

@@ -0,0 +1,490 @@
package com.chwl.app.decoration.ui.fragment
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chwl.app.R
import com.chwl.app.base.BaseListFragment
import com.chwl.app.bindadapter.BaseBindingAdapter
import com.chwl.app.common.EmptyViewHelper
import com.chwl.app.decoration.adapter.DressUpAdapter
import com.chwl.app.decoration.ui.activity.DressUpTabActivity
import com.chwl.app.decoration.util.DressUpUtil
import com.chwl.app.event.DressUpEvent
import com.chwl.core.auth.AuthModel
import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.core.decoration.bean.ShopMine
import com.chwl.core.decoration.car.bean.CarInfo
import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo
import com.chwl.core.decoration.headwear.bean.UserCardWearInfo
import com.chwl.core.decoration.nameplate.bean.NamePlateInfo
import com.chwl.core.manager.AvRoomDataManager
import com.chwl.core.manager.IMNetEaseManager
import com.chwl.core.user.UserModel
import com.chwl.core.utils.net.RxHelper
import com.chwl.library.common.util.doToast
import com.chwl.library.common.util.isVerify
import com.chwl.library.common.util.setMargin
import com.chwl.library.net.rxnet.RxNet
import com.example.lib_utils.ktx.getString
import io.reactivex.Single
import org.greenrobot.eventbus.EventBus
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
class DressUpMyFragment : BaseListFragment<DressUpInfo>() {
companion object {
fun newInstance(dressType: Int): DressUpMyFragment {
val args = Bundle()
args.putInt("dressType", dressType)
val fragment = DressUpMyFragment()
fragment.arguments = args
return fragment
}
}
private val mDressType: Int by lazy { requireArguments().getInt("dressType") }
private var mPosition = -1
override fun initView() {
mAdapter.setEmptyView(
EmptyViewHelper.createEmptyTextViewHeight(
context,
R.string.empty_data.getString()
)
)
binding.rvList.setMargin(start = 10, end = 10)
mPosition = -1
mAdapter.setNewData(arrayListOf())
}
override fun onResume() {
super.onResume()
if (!mAdapter?.data.isVerify()){
onRefresh()
}
}
override fun getAdapter(): BaseBindingAdapter<*, DressUpInfo> {
return DressUpAdapter()
}
override fun getLayoutManager(): RecyclerView.LayoutManager {
return GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
}
override fun onLoad() {
loadDataByType(false)
}
override fun onRefresh() {
loadDataByType(true)
}
private fun loadDataByType(isRefresh: Boolean) {
if (isRefresh){
mPage = 1
}
when (mDressType) {
DressUpTabActivity.TAB_CHAT_BUBBLE -> {
getChatBubbleInfoList()
.compose(bindToLifecycle())
.doOnSuccess {
it?.let {
val newData = mutableListOf<DressUpInfo>()
it.forEach {
newData.add(DressUpUtil.tranData(it))
}
setData(newData)
}
}.doOnError {
stopAnim()
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_USER_CARD -> {
getMyUserCardWearList()
.compose(bindToLifecycle())
.doOnSuccess {
it?.let {
val newData = mutableListOf<DressUpInfo>()
it.forEach {
newData.add(DressUpUtil.tranData(it))
}
setData(newData)
}
}.doOnError {
stopAnim()
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_NAMEPLATE -> {
getNamePlateList()
.compose(bindToLifecycle())
.doOnSuccess {
it?.let {
val newData = mutableListOf<DressUpInfo>()
it.nameplateList.forEach {
newData.add(DressUpUtil.tranData(it))
}
setData(newData)
}
}.doOnError {
stopAnim()
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_HEAD_WEAR , DressUpTabActivity.TAB_USER_INFO_BG -> {
getShopMine()
.compose(bindToLifecycle())
.doOnSuccess {
it?.let {
val newData = mutableListOf<DressUpInfo>()
it.forEach {
newData.add(DressUpUtil.tranData(it))
}
setData(newData)
}
}.doOnError {
stopAnim()
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_CAR -> {
getUserCarsV2()
.compose(bindToLifecycle())
.doOnSuccess {
it?.let {
val newData = mutableListOf<DressUpInfo>()
it.forEach {
newData.add(DressUpUtil.tranData(it))
}
setData(newData)
}
}.doOnError {
stopAnim()
it?.message?.doToast()
}.subscribe()
}
else -> {}
}
}
private fun userByType(
data: DressUpInfo,
adapter: BaseBindingAdapter<*, DressUpInfo>?,
position: Int
) {
when (mDressType) {
DressUpTabActivity.TAB_CHAT_BUBBLE -> {
userChatBubble(data.dressId)
.compose(bindToLifecycle())
.doOnSuccess {
//更新用户信息
UserModel.get().updateCurrentUserInfo().subscribe()
setSelect(adapter, position)
}
.doOnError {
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_USER_CARD -> {
userMyUserCardWear(data.dressId)
.compose(bindToLifecycle())
.doOnSuccess {
//更新用户信息
UserModel.get().updateCurrentUserInfo().subscribe()
setSelect(adapter, position)
}
.doOnError {
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_NAMEPLATE -> {
useMyNamePlate(data.id,data.word)
.compose(bindToLifecycle())
.doOnSuccess {
if (AvRoomDataManager.get().mCurrentRoomInfo != null) {
// 更新房间信息
IMNetEaseManager.get().updateMyRoomRole()
}
//更新用户信息
UserModel.get().updateCurrentUserInfo().subscribe()
setSelect(adapter, position)
}
.doOnError {
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_HEAD_WEAR , DressUpTabActivity.TAB_USER_INFO_BG-> {
postOptDress(data.dressType, data.dressId)
.compose(bindToLifecycle())
.doOnSuccess {
//更新用户信息
UserModel.get().updateCurrentUserInfo().subscribe()
setSelect(adapter, position)
}
.doOnError {
it?.message?.doToast()
}.subscribe()
}
DressUpTabActivity.TAB_CAR -> {
driveThisCar(data.dressId)
.compose(bindToLifecycle())
.doOnSuccess {
//更换座驾状态,需要更新缓存
UserModel.get().onlyUpdateLoginUserInfoCache()
setSelect(adapter, position)
}
.doOnError {
it?.message?.doToast()
}.subscribe()
}
else -> {}
}
}
private fun setData(newData:MutableList<DressUpInfo>) {
if (mPage == 1) {
val find = newData.indexOfFirst { it.isSelect() }
newData.add(0,DressUpUtil.getEmpty(find == -1))
mPosition= if (find==-1) 0 else find+1
mAdapter.setNewData(newData)
} else {
mAdapter.addData(newData)
}
if (newData.size >= mPageSize) {
mPage++
binding.srlLayout.isEnableLoadmore = true
} else {
binding.srlLayout.isEnableLoadmore = false
}
stopAnim()
}
private fun setSelect(adapter: BaseBindingAdapter<*, DressUpInfo>?, position: Int) {
if (mPosition != -1) {
adapter?.data?.getOrNull(mPosition)?.isSelect = false
adapter?.notifyItemChanged(mPosition)
}
mPosition = position
adapter?.data?.getOrNull(mPosition)?.isSelect = true
adapter?.notifyItemChanged(mPosition)
R.string.doSuccess.doToast()
}
override fun onItemChildClicks(
adapter: BaseBindingAdapter<*, DressUpInfo>?,
view: View?,
position: Int
) {
view?.id?.let {
when (it) {
R.id.btnPlay -> {
adapter?.data?.getOrNull(position)?.let { data ->
EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Play, data))
}
}
else -> {}
}
}
}
override fun onItemClicks(
adapter: BaseBindingAdapter<*, DressUpInfo>?,
view: View?,
position: Int
) {
adapter?.data?.getOrNull(position)?.let { data ->
EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Select, data))
if (!data.isSelect() && !data.isHasExpired){
userByType(data,adapter, position)
}
}
}
private fun getShopMine(): Single<List<ShopMine>> {
return api.getShopMine(mDressType,mPage,mPageSize)
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private fun postOptDress(dressType: Int,dressId: Int): Single<String> {
return api.postOptDress(dressType,dressId)
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private fun getUserCarsV2(): Single<List<CarInfo>> {
return api.requestMyCarsV2(AuthModel.get().currentUid)
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private fun driveThisCar(carId: Int): Single<String> {
val ticket = AuthModel.get().ticket
val uid = AuthModel.get().currentUid
return api.driveThisCar(ticket, uid, carId)
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private fun getNamePlateList(): Single<NamePlateInfo> {
return api.getNamePlateList(AuthModel.get().currentUid.toString(), mPage.toString(), mPageSize.toString())
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private fun useMyNamePlate(id: Int,word: String): Single<String> {
val ticket = AuthModel.get().ticket
val uid = AuthModel.get().currentUid
return api.useMyNamePlate(ticket, uid.toString(), id.toString(),word)
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private fun userMyHeadWear(id: Int): Single<String> {
val ticket = AuthModel.get().ticket
val uid = AuthModel.get().currentUid
return api.userMyHeadWear(ticket, uid.toString(), id.toString())
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private fun getMyUserCardWearList(): Single<List<UserCardWearInfo>> {
return api.getMyUserCardWearList(mPage,mPageSize)
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private fun userMyUserCardWear(id: Int): Single<String> {
return api.userMyUserCardWear(id.toString())
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private fun getChatBubbleInfoList(): Single<List<ChatBubbleInfo>> {
return api.getChatBubbleInfoList(mPage,mPageSize)
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private fun userChatBubble(id: Int): Single<String> {
return api.userChatBubble(id.toString())
.compose(RxHelper.handleStringData())
.compose(RxHelper.handleSchedulers())
}
private val api: Api = RxNet.create(Api::class.java);
interface Api {
/**
* 获取 我的装扮 : dressType : 5-个人主页背景
*/
@GET("/dress/shop/mine")
fun getShopMine(@Query("dressType") dressType: Int,@Query("page") page: Int,@Query("pageSize") pageSize: Int): Single<ServiceResult<List<ShopMine>>>
/**
* 购买装扮
*/
@GET("/dress/shop/optDress")
fun postOptDress(@Query("dressType") dressType: Int, @Query("dressId") id: Int): Single<ServiceResult<String>>
/**
* 使用座驾
*
* @param ticket 用户的ticket
* @param uid 用户的uid
* @param carId 座驾的idid=0 则表示不使用座驾id!=0 表示使用该carId的座驾
*/
@POST("/car/carport/use")
@FormUrlEncoded
fun driveThisCar(@Field("ticket") ticket: String?, @Field("uid") uid: Long, @Field("carId") carId: Int): Single<ServiceResult<String>>
/**
* 获取自己的车库V2
*
* @param uid -
* @return -
*/
@GET("car/carport/v2/list")
fun requestMyCarsV2(@Query("uid") uid: Long): Single<ServiceResult<List<CarInfo>>>
/**
* 使用头饰
*/
@POST("v1/user/headwear/use")
fun userMyHeadWear(@Query("ticket") ticket: String?,@Query("uid") uid: String?, @Query("headwearId") headwear_id: String?): Single<ServiceResult<String>>
/**
* 获取铭牌列表
*/
@POST("nameplate/userNameplateList")
fun getNamePlateList(@Query("uid") uid: String?, @Query("page") page: String?, @Query("pageSize") pageSize: String?): Single<ServiceResult<NamePlateInfo?>?>
@POST("nameplate/useNameplate")
fun useMyNamePlate(@Query("uid") uid: String?, @Query("ticket") ticket: String?, @Query("userNameplateId") id: String?, @Query("word") word: String?): Single<ServiceResult<String>>
/**
* 分页获取用户资料卡装扮列表
*/
@GET("userInfoCard/listByPage")
fun getMyUserCardWearList(@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single<ServiceResult<List<UserCardWearInfo>>>
/**
* 使用资料卡装扮
*/
@GET("userInfoCard/optUserInfoCard")
fun userMyUserCardWear(@Query("cardId") cardId: String?): Single<ServiceResult<String>>
/**
* 分页获取用户聊天气泡列表
*/
@GET("userChatBubble/listByPage")
fun getChatBubbleInfoList(@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single<ServiceResult<List<ChatBubbleInfo>>>
/**
* 使用聊天气泡
*/
@FormUrlEncoded
@POST("userChatBubble/optUserChatBubble")
fun userChatBubble(@Field("bubbleId") cardId: String?): Single<ServiceResult<String>>
}
}

View File

@@ -0,0 +1,170 @@
package com.chwl.app.decoration.ui.fragment
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chwl.app.R
import com.chwl.app.base.BaseListFragment
import com.chwl.app.bindadapter.BaseBindingAdapter
import com.chwl.app.common.EmptyViewHelper
import com.chwl.app.decoration.adapter.DressUpAdapter
import com.chwl.app.decoration.util.DressUpUtil
import com.chwl.app.event.DressUpEvent
import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.decoration.bean.DecorationInfo
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.core.utils.net.RxHelper
import com.chwl.library.common.util.doToast
import com.chwl.library.common.util.setMargin
import com.chwl.library.net.rxnet.RxNet
import com.example.lib_utils.ktx.getString
import io.reactivex.Single
import org.greenrobot.eventbus.EventBus
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
class DressUpStoreFragment: BaseListFragment<DressUpInfo>() {
private var mPosition = -1
companion object {
fun newInstance(dressType: Int): DressUpStoreFragment {
val args = Bundle()
args.putInt("dressType", dressType)
val fragment = DressUpStoreFragment()
fragment.arguments = args
return fragment
}
}
private val mDressType: Int by lazy { requireArguments().getInt("dressType") }
override fun initView() {
binding.srlLayout.isEnableRefresh = false
binding.srlLayout.isEnableLoadmore = false
mAdapter.setEmptyView(EmptyViewHelper.createEmptyTextViewHeight(context, R.string.empty_data.getString()))
binding.rvList.setMargin(start = 10, end = 10)
}
override fun onResume() {
super.onResume()
mPosition = -1
onLoad()
}
override fun getAdapter(): BaseBindingAdapter<*, DressUpInfo> {
return DressUpAdapter()
}
override fun getLayoutManager(): RecyclerView.LayoutManager {
return GridLayoutManager(context,2,RecyclerView.VERTICAL,false)
}
override fun onLoad() {
getShopList()
.compose(bindToLifecycle())
.doOnSuccess {
it?.let {
val newData = mutableListOf<DressUpInfo>()
it.forEach {
newData.add(DressUpUtil.tranData(it))
}
mAdapter.setNewData(newData)
}
}
.doOnError {
it?.message?.doToast()
}
.subscribe()
}
override fun onRefresh() {
}
override fun onItemChildClicks(adapter: BaseBindingAdapter<*, DressUpInfo>?, view: View?, position: Int) {
view?.id?.let {
when (it) {
R.id.btnPlay -> {
adapter?.data?.getOrNull(position)?.let { data->
EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Play,data))
}
}
else -> {}
}
}
}
override fun onItemClicks(adapter: BaseBindingAdapter<*, DressUpInfo>?, view: View?, position: Int) {
adapter?.data?.getOrNull(position)?.let { data ->
if (mPosition != -1) {
adapter?.data?.getOrNull(mPosition)?.isSelect = false
adapter?.notifyItemChanged(mPosition)
}
mPosition = position
adapter?.data?.getOrNull(mPosition)?.isSelect = true
adapter?.notifyItemChanged(mPosition)
EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Select, data))
}
}
private fun getShopList(): Single<List<DecorationInfo>> {
return api.getShopList(mDressType)
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private val api: Api = RxNet.create(Api::class.java);
interface Api {
/**
* 获取装扮商城列表
*
* @return
*/
@GET("/dress/shop/list")
fun getShopList(@Query("dressType") dressType: Int): Single<ServiceResult<List<DecorationInfo>>>
/**
* 购买装扮
*
* @return
*/
@FormUrlEncoded
@POST("/dress/shop/buy")
fun postShopBuy(
@Field("dressType") dressType: Int,
@Field("id") id: Int
): Single<ServiceResult<String>>
/**
* 赠送装扮
*
* @return
*/
@FormUrlEncoded
@POST("/dress/shop/give")
fun postShopGive(
@Field("dressType") dressType: Int,
@Field("id") id: Int,
@Field("targetUid") targetUid: Long,
): Single<ServiceResult<String>>
}
}

View File

@@ -0,0 +1,260 @@
package com.chwl.app.decoration.util
import android.graphics.Typeface
import android.view.ViewGroup
import android.widget.ImageView
import com.chwl.app.R
import com.chwl.app.avroom.widget.GalleryLayoutManager.LayoutParams
import com.chwl.app.decoration.ui.activity.DressUpTabActivity
import com.chwl.app.decoration.ui.activity.DressUpTabActivity.Companion.TAB_HEAD_WEAR
import com.chwl.app.decoration.ui.activity.DressUpTabActivity.Companion.TAB_USER_CARD
import com.chwl.app.ui.utils.loadAnim2
import com.chwl.app.ui.utils.loadImage
import com.chwl.core.decoration.bean.DecorationInfo
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.core.decoration.bean.ShopMine
import com.chwl.core.decoration.car.bean.CarInfo
import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo
import com.chwl.core.decoration.headwear.bean.UserCardWearInfo
import com.chwl.core.decoration.nameplate.bean.NamePlateInfo
import com.chwl.library.common.util.isVerify
import com.chwl.library.common.util.setViewWH
import com.chwl.library.common.util.setVis
import com.chwl.library.widget.SVGAView
import com.chwl.library.widget.text.DrawableTextView
import com.example.lib_utils.ktx.getColor
import com.example.lib_utils.ktx.getString
import com.example.lib_utils.spannable.SpannableTextBuilder
import com.tencent.qgame.animplayer.AnimView
import com.tencent.qgame.animplayer.util.ScaleType
class DressUpUtil {
companion object {
fun getEmpty(use:Boolean): DressUpInfo {
val outData = DressUpInfo()
outData.dressId = 0
outData.isMy = true
outData.isNull = true
outData.isSelect = use
return outData
}
fun tranData(inData: DecorationInfo): DressUpInfo {
val outData = DressUpInfo()
outData.dressLimitStatus = inData.dressLimitStatus
outData.id = inData.id
outData.discount = inData.discount
outData.originalPrice = inData.dressPrice
outData.buyDay = inData.dressDay
outData.price = inData.discountPrice.toInt()
outData.name = inData.name
outData.pic = inData.pic
outData.effect = inData.effect
outData.effectType = inData.effectType
outData.dressType = inData.dressType
outData.vipLimit = inData.vipLimit
outData.dressId = inData.dressId
outData.obtainWay = inData.obtainWay
return outData
}
// 个人主页 , 头饰
fun tranData(inData: ShopMine): DressUpInfo {
val outData = DressUpInfo()
outData.isMy = true
outData.isSelect = inData.isUsed
outData.name = inData.name
outData.pic = inData.pic
outData.effect = inData.effect
outData.effectType = inData.effectType
outData.dressType = inData.dressType
outData.dressId = inData.dressId
outData.obtainWay = inData.obtainWay
outData.hasExpired = inData.hasExpired
outData.expireDays = inData.expireDays
return outData
}
fun tranData(inData: ChatBubbleInfo): DressUpInfo {
val outData = DressUpInfo()
outData.isMy = true
outData.isSelect = inData.isHasUsed
outData.name = inData.name
outData.pic = inData.bubbleUrl
outData.dressType = DressUpTabActivity.TAB_CHAT_BUBBLE
if (inData.bubbleId.isVerify()) {
outData.dressId = inData.bubbleId.toInt()
}
outData.hasExpired = inData.isHasExpired
outData.expireDays = inData.expireDays
return outData
}
fun tranData(inData: UserCardWearInfo): DressUpInfo {
val outData = DressUpInfo()
outData.isMy = true
outData.isSelect = inData.isUsed
outData.name = inData.name
outData.pic = inData.pic
outData.effect = inData.pic
outData.effectType = DressUpInfo.EffectType.MP4
outData.dressType = DressUpTabActivity.TAB_USER_CARD
if (inData.cardId.isVerify()) {
outData.dressId = inData.cardId.toInt()
}
outData.hasExpired = inData.isHasExpired
outData.expireDays = inData.expireDays
return outData
}
fun tranData(inData: NamePlateInfo.NameplateListBean): DressUpInfo {
val outData = DressUpInfo()
outData.isMy = true
outData.isSelect = inData.isUsing
outData.name = inData.nameplateName
outData.word = inData.word
outData.pic = inData.nameplateImage
outData.dressType = DressUpTabActivity.TAB_NAMEPLATE
outData.dressId = inData.nameplateId
outData.id = inData.id
outData.hasExpired = inData.isExpired
outData.expireDays = inData.expireDays
return outData
}
fun tranData(inData: CarInfo): DressUpInfo {
val outData = DressUpInfo()
outData.isMy = true
outData.isSelect = inData.using == 1
outData.name = inData.name
outData.pic = inData.pic
if (inData.viewUrl.isVerify()) {
outData.effect = inData.viewUrl
outData.effectType = inData.otherViewType
}else{
outData.effect = inData.effect
outData.effectType = inData.otherViewType
}
outData.dressType = DressUpTabActivity.TAB_CAR
outData.dressId = inData.carId
outData.hasExpired = inData.status != CarInfo.STATUS_USER_CAN_USE
// val cTime = System.currentTimeMillis()
// val dTime = inData.expireDays - cTime
// val dDay = TimeUnit.MICROSECONDS.toDays(dTime)
// if (dDay < TimeUnit.DAYS.toMillis(1)) {
// // < 1 天
// } else {
// // dDay天后过期
// }
outData.expireDays = inData.days
return outData
}
fun setTextPrice(textView: DrawableTextView, item: DressUpInfo) {
val message = R.string.s_sDays_s.getString(item.price, item.buyDay, item.originalPrice)
SpannableTextBuilder(textView).appendText(message)
.setTextStyle(
text = item.price.toString(),
textStyle = Typeface.BOLD
).setTextStyle(
text = item.buyDay.toString(),
textStyle = Typeface.NORMAL
).setTextStyle(
text = item.originalPrice.toString(),
textColor = R.color.color_d9e7f7.getColor(),
delLine = true
).apply()
textView.setVis(true)
}
fun setItemPic(data:DressUpInfo,layout: ViewGroup) {
if (data.dressType == DressUpTabActivity.TAB_USER_CARD) {
//此时传回的是mp4..
// layout.setViewWH()
play(data,layout,true)
} else {
layout.removeAllViews()
val pic = ImageView(layout.context)
layout.addView(pic)
if (data.dressType == DressUpTabActivity.TAB_CAR) {
pic.setViewWH(129,129)
}else if (data.dressType == DressUpTabActivity.TAB_HEAD_WEAR) {
pic.setViewWH(117,117)
}else if (data.dressType == DressUpTabActivity.TAB_NAMEPLATE) {
pic.setViewWH(98,28)
}else if (data.dressType == DressUpTabActivity.TAB_CHAT_BUBBLE) {
pic.setViewWH(90,46)
}else if (data.dressType == DressUpTabActivity.TAB_USER_INFO_BG) {
pic.setViewWH(127,125)
}
pic.loadImage(data.pic)
}
}
fun play(data:DressUpInfo,layout: ViewGroup,isItem :Boolean = false){
if (data.effect.isVerify()) {
var animView : AnimView?=null
var svgaView : SVGAView?=null
layout.setVis(true)
layout.removeAllViews()
if (data.effectType == DressUpInfo.EffectType.MP4) {
animView = AnimView(layout.context)
layout.addView(animView)
animView.setLoop(Int.MAX_VALUE)
animView.setScaleType(ScaleType.FIT_XY)
} else {
svgaView = SVGAView(layout.context)
layout.addView(svgaView)
svgaView.loops = Int.MAX_VALUE
svgaView.setScaleType(ImageView.ScaleType.FIT_XY)
}
//item 时占满就行
if (isItem) {
animView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, false)
svgaView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,false)
} else {
if (data.dressType == TAB_HEAD_WEAR) {
animView?.setViewWH(183, 183, true)
svgaView?.setViewWH(183, 183, true)
}else if (data.dressType == TAB_USER_CARD) {
animView?.setViewWH(285, 250, true)
svgaView?.setViewWH(285, 250, true)
} else {
animView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, false)
svgaView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,false)
}
}
animView?.loadAnim2(data.effect,false)
svgaView?.loadUrl(data.effect,true)
}
}
}
}

View File

@@ -11,6 +11,7 @@ import com.chwl.app.R
import com.chwl.app.base.BaseViewBindingActivity
import com.chwl.app.base.TitleBar
import com.chwl.app.databinding.ActivityDecorationStoreBinding
import com.chwl.app.decoration.ui.activity.DressUpTabActivity
import com.chwl.app.decoration.view.widgets.CarMagicIndicator
import com.chwl.app.decoration.view.widgets.MyDecorationMagicIndicator
import com.chwl.app.decoration.viewmodel.DecorationViewModel
@@ -60,7 +61,7 @@ class DecorationStoreActivity : BaseViewBindingActivity<ActivityDecorationStoreB
ResUtil.getString(R.string.decoration_view_decorationstoreactivity_02), Color.parseColor("#999999")
) {
override fun performAction(view: View) {
MyDecorationActivity.start(this@DecorationStoreActivity, 0)
DressUpTabActivity.start(this@DecorationStoreActivity,true)
}
})
mPosition = intent.getIntExtra(Constants.KEY_POSITION, 0)

View File

@@ -0,0 +1,29 @@
package com.chwl.app.event;
import com.chwl.core.decoration.bean.DressUpInfo;
import lombok.Data;
@Data
public class DressUpEvent {
public int action;
public DressUpInfo data;
public DressUpEvent() {
}
public DressUpEvent(int action) {
this.action = action;
}
public DressUpEvent(int action, DressUpInfo data) {
this.action = action;
this.data = data;
}
public @interface Action{
int Select = 1;
int Play = 2;
}
}

View File

@@ -7,7 +7,6 @@ import android.view.View;
import androidx.fragment.app.Fragment;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.chwl.app.R;
import com.chwl.app.base.BaseBindingActivity;
import com.chwl.app.base.TitleBar;
@@ -34,6 +33,7 @@ import com.chwl.core.utils.net.DontWarnObserver;
import com.chwl.library.annatation.ActLayoutRes;
import com.chwl.library.utils.ResUtil;
import com.chwl.library.utils.SingleToastUtil;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import java.util.ArrayList;
import java.util.List;

View File

@@ -21,6 +21,7 @@ import com.chwl.app.avroom.dialog.RoomBgSetDialog
import com.chwl.app.base.BaseActivity
import com.chwl.app.base.BaseFragment
import com.chwl.app.databinding.FragmentMeBinding
import com.chwl.app.decoration.ui.activity.DressUpTabActivity
import com.chwl.app.home.HomeViewModel
import com.chwl.app.home.MeViewModel
import com.chwl.app.home.activity.AssociationActivity
@@ -39,7 +40,6 @@ import com.chwl.app.ui.webview.CommonWebViewActivity
import com.chwl.app.utils.HomeUIManager
import com.chwl.app.view.GenderAgeTextView
import com.chwl.app.vip.VipCenterActivity
import com.chwl.app.vip.VipCenterActivity.Companion.start
import com.chwl.app.vip.VipViewModel
import com.chwl.core.auth.AuthModel
import com.chwl.core.initial.InitialModel
@@ -374,7 +374,7 @@ class MeFragment : BaseFragment(), View.OnClickListener {
R.id.tv_user_name -> {
//todo do 测试按钮
if (BuildConfig.DEBUG) {
start(requireActivity(), 8)
DressUpTabActivity.start(requireActivity(),false)
}
}

View File

@@ -7,17 +7,18 @@ import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.chwl.app.BuildConfig
import com.chwl.app.base.BaseViewModel
import com.chwl.library.utils.PathHelper
import com.chwl.core.home.model.HomeModel
import com.chwl.core.utils.LogUtils
import com.chwl.library.common.glide.GlideUtils
import com.chwl.library.common.util.SPUtils
import com.chwl.library.utils.NetworkUtils
import com.chwl.library.utils.PathHelper
import com.example.lib_utils.AppUtils
import com.example.lib_utils.FileUtils2
import com.example.lib_utils.log.ILog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.File
@@ -33,18 +34,24 @@ class PreloadResourceViewModel : BaseViewModel(), ILog , RequestListener<File?>
private var mContext : Context? = null
//todo 预加载
fun start(context: Context) {
mContext = context
if (BuildConfig.DEBUG) {
// 太多请求了,影响查看控制台日志
return
}
// if (BuildConfig.DEBUG) {
// // 太多请求了,影响查看控制台日志
// return
// }
if (isStarted) {
return
}
getPreloadResourceList {
isStarted = true
nextTask(null)
viewModelScope?.launch(Dispatchers.IO) {
getPreloadResourceList {
isStarted = true
nextTask(null)
}
}
}
@@ -91,7 +98,7 @@ class PreloadResourceViewModel : BaseViewModel(), ILog , RequestListener<File?>
}
}
private fun downloadTask(url: String) {
private fun downloadTask(url: String?) {
// val path = PathHelper.generateResourcesFilePath(url)
// logI("downloadTask() url:${url} path:${path}")
@@ -104,9 +111,13 @@ class PreloadResourceViewModel : BaseViewModel(), ILog , RequestListener<File?>
// )
// DownloadManager.download(request, this)
GlideUtils.instance().downloadFromUrl(mContext,url,this)
viewModelScope.launch {
delay(500)
LogUtils.d("预加载 -> downloadTask url = ${url?.trim()}")
if (url != null) {
GlideUtils.instance().downloadFromUrl2(mContext,url.trim(),this@PreloadResourceViewModel)
}
}
}
override fun onLoadFailed(
@@ -119,6 +130,7 @@ class PreloadResourceViewModel : BaseViewModel(), ILog , RequestListener<File?>
logI("onDownloadError() url:${model} message:${e?.message}")
nextTask(model)
}
LogUtils.d("预加载 onLoadFailed 失败 url = ${model}")
return true
}
@@ -134,7 +146,7 @@ class PreloadResourceViewModel : BaseViewModel(), ILog , RequestListener<File?>
makeDownloadRecord(model)
nextTask(null)
}
LogUtils.d("预加载 onResourceReady 成功 url = ${model}")
return true
}

View File

@@ -4,16 +4,6 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import com.chwl.app.decoration.view.DecorationStoreActivity;
import com.chwl.app.earn.activity.EarnRecordActivity;
import com.chwl.app.pay.activity.GiveGoldActivity;
import com.chwl.app.ui.feedback.FeedbackActivity;
import com.chwl.app.ui.game_team.record.GameTeamRecordActivity;
import com.chwl.app.ui.setting.VipSetActivity;
import com.chwl.app.vip.VipCenterActivity;
import com.chwl.core.module_hall.hall.bean.H5FamilyInfo;
import com.chwl.core.module_hall.hall.bean.UserClanInfo;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import com.chwl.app.R;
import com.chwl.app.UIHelper;
import com.chwl.app.audio.VoiceMatchActivity;
@@ -22,31 +12,38 @@ import com.chwl.app.avroom.recommendcard.MyRecommendCardActivity;
import com.chwl.app.base.BaseActivity;
import com.chwl.app.base.DialogManagerInterface;
import com.chwl.app.common.widget.dialog.DialogManager;
import com.chwl.app.decoration.view.MyDecorationActivity;
import com.chwl.app.decoration.ui.activity.DressUpTabActivity;
import com.chwl.app.earn.activity.EarnRecordActivity;
import com.chwl.app.home.activity.CollectionRoomActivity;
import com.chwl.app.home.activity.VisitorListActivity;
import com.chwl.app.home.helper.OpenRoomHelper;
import com.chwl.app.module_hall.HallDataManager;
import com.chwl.app.module_hall.hall.activity.ModuleClanActivity;
import com.chwl.app.module_hall.hall.activity.ModuleHallActivity;
import com.chwl.app.pay.activity.GiveGoldActivity;
import com.chwl.app.radish.task.activity.TaskCenterActivity;
import com.chwl.app.relation.cp.activity.CpHomeActivity;
import com.chwl.app.relation.cp.activity.CpInviteRecordActivity;
import com.chwl.app.relation.cp.activity.CpTaskActivity;
import com.chwl.app.team.view.NimTeamMessageActivity;
import com.chwl.app.ui.feedback.FeedbackActivity;
import com.chwl.app.ui.game_team.record.GameTeamRecordActivity;
import com.chwl.app.ui.login.BindPhoneActivity;
import com.chwl.app.ui.login.ShowBindPhoneActivity;
import com.chwl.app.ui.pay.ChargeActivity;
import com.chwl.app.ui.setting.ModifyPwdActivity;
import com.chwl.app.ui.user.activity.UserInfoActivity;
import com.chwl.app.ui.webview.CommonWebViewActivity;
import com.chwl.app.vip.VipCenterActivity;
import com.chwl.core.DemoCache;
import com.chwl.core.auth.AuthModel;
import com.chwl.core.community.event.SquareTaskEvent;
import com.chwl.core.im.custom.bean.RouterType;
import com.chwl.core.manager.AvRoomDataManager;
import com.chwl.core.module_hall.hall.HallModel;
import com.chwl.core.module_hall.hall.bean.H5FamilyInfo;
import com.chwl.core.module_hall.hall.bean.HallInfo;
import com.chwl.core.module_hall.hall.bean.UserClanInfo;
import com.chwl.core.room.bean.RoomInfo;
import com.chwl.core.room.model.AvRoomModel;
import com.chwl.core.utils.net.BeanObserver;
@@ -55,6 +52,7 @@ import com.chwl.library.net.rxnet.callback.CallBack;
import com.chwl.library.utils.JavaUtil;
import com.chwl.library.utils.ResUtil;
import com.chwl.library.utils.SingleToastUtil;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import org.greenrobot.eventbus.EventBus;
@@ -104,27 +102,27 @@ public class RouterHandler {
break;
case RouterType.CAR:
if (JavaUtil.str2int(routerValue) == 0) {
DecorationStoreActivity.start(context, DecorationStoreActivity.TAB_CAR);
DressUpTabActivity.Companion.start(context,false);
} else {
MyDecorationActivity.start(context, 1);
DressUpTabActivity.Companion.start(context,true);
}
break;
case RouterType.DECORATION:
if (JavaUtil.str2int(routerValue) == 0) {
DecorationStoreActivity.start(context, 0);
DressUpTabActivity.Companion.start(context,false);
} else {
MyDecorationActivity.start(context, 0);
DressUpTabActivity.Companion.start(context,true);
}
break;
case RouterType.NAMEPLATE:
if (JavaUtil.str2int(routerValue) == 0) {
DecorationStoreActivity.start(context, DecorationStoreActivity.TAB_NAMEPLATE);
DressUpTabActivity.Companion.start(context,false);
} else {
MyDecorationActivity.start(context, 2);
DressUpTabActivity.Companion.start(context,true);
}
break;
case RouterType.USER_CARD_WEAR:
MyDecorationActivity.start(context, 3);
DressUpTabActivity.Companion.start(context,true);
break;
case RouterType.TEAM:
NimTeamMessageActivity.start(context, routerValue);
@@ -226,10 +224,10 @@ public class RouterHandler {
CpTaskActivity.Companion.start(context);
break;
case RouterType.CP_WARE:
MyDecorationActivity.start(context, 0);
DressUpTabActivity.Companion.start(context,true);
break;
case RouterType.USER_BUBBLE:
MyDecorationActivity.start(context, 4);
DressUpTabActivity.Companion.start(context,true);
break;
case RouterType.MY_ROOM:
//我的房间,开房
@@ -278,13 +276,13 @@ public class RouterHandler {
if (intRouterValue < 0 || intRouterValue > 4) {
intRouterValue = 0;
}
DecorationStoreActivity.start(context, intRouterValue);
DressUpTabActivity.Companion.start(context,false);
break;
case RouterType.MY_DECORATION:
if (intRouterValue < 0 || intRouterValue > 4) {
intRouterValue = 0;
}
MyDecorationActivity.start(context, intRouterValue);
DressUpTabActivity.Companion.start(context,true);
break;
case RouterType.MY_SET:
UIHelper.showSettingAct(context);
@@ -299,7 +297,7 @@ public class RouterHandler {
GameTeamRecordActivity.Companion.start(context);
break;
case RouterType.MY_DRESS_ITEM:
MyDecorationActivity.start(context, 0);
DressUpTabActivity.Companion.start(context,true);
break;
default:
SingleToastUtil.showToast(ResUtil.getString(R.string.ui_im_routerhandler_07));

View File

@@ -7,11 +7,8 @@ import android.text.style.ForegroundColorSpan;
import android.view.View;
import android.widget.TextView;
import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase;
import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter;
import com.netease.nimlib.sdk.msg.attachment.MsgAttachment;
import com.chwl.app.R;
import com.chwl.app.decoration.view.MyDecorationActivity;
import com.chwl.app.decoration.ui.activity.DressUpTabActivity;
import com.chwl.app.ui.im.RouterHandler;
import com.chwl.app.ui.webview.CommonWebViewActivity;
import com.chwl.app.utils.SpannableBuilder;
@@ -28,6 +25,9 @@ import com.chwl.core.im.custom.bean.NobleAttachment;
import com.chwl.core.im.custom.bean.VoiceBottleShakeHeartAttachment;
import com.chwl.core.manager.IMNetEaseManager;
import com.chwl.library.utils.ResUtil;
import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase;
import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter;
import com.netease.nimlib.sdk.msg.attachment.MsgAttachment;
import org.greenrobot.eventbus.EventBus;
@@ -151,7 +151,7 @@ public class MsgViewHolderText extends MsgViewHolderBase {
} else if (mCarAttachment != null) {
if (mCarAttachment.mSecond == CUSTOM_MESS_SUB_CAR_EXPIRE) {
MyDecorationActivity.start(mTvMsg.getContext(), 1);
DressUpTabActivity.Companion.start(context,true);
}
} else if (awardAttachment != null) {
RouterHandler.handle(context, awardAttachment.routerType, awardAttachment.routerValue);

View File

@@ -0,0 +1,158 @@
package com.chwl.app.ui.search
import android.content.Context
import android.content.Intent
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chwl.app.R
import com.chwl.app.base.BaseViewBindingActivity
import com.chwl.app.bindadapter.BaseBindingAdapter
import com.chwl.app.bindadapter.BaseBindingViewHolder
import com.chwl.app.common.EmptyViewHelper
import com.chwl.app.databinding.ActivitySearchUserBinding
import com.chwl.app.databinding.ItemSearchUserBinding
import com.chwl.app.decoration.ui.DressUpDialog
import com.chwl.app.ui.utils.loadAvatar
import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.decoration.bean.DressUpInfo
import com.chwl.core.im.friend.IMFriendModel
import com.chwl.core.room.bean.SearchRoomInfo
import com.chwl.core.user.UserModel
import com.chwl.core.user.bean.UserInfo
import com.chwl.core.utils.net.RxHelper
import com.chwl.library.common.util.doToast
import com.chwl.library.common.util.isVerify
import com.chwl.library.net.rxnet.RxNet
import com.example.lib_utils.ktx.getString
import com.google.gson.Gson
import io.reactivex.Single
import retrofit2.http.GET
import retrofit2.http.Query
class SearchUserActivity : BaseViewBindingActivity<ActivitySearchUserBinding>() {
companion object{
fun start(context: Context, data:String) {
val intent = Intent(context, SearchUserActivity::class.java)
intent.putExtra("json",data)
context.startActivity(intent)
}
}
private var mDressUpInfo : DressUpInfo? = null
private val mJson : String by lazy { intent.getStringExtra("json")?:"" }
lateinit var mAdapter : UserAdapter
override fun transparencyBar() = true
override fun init() {
initDarkTitleBar(R.string.search.getString())
if (mJson.isVerify()) {
mDressUpInfo = Gson().fromJson(mJson,DressUpInfo::class.java)
}
mAdapter= UserAdapter()
binding.rvList.layoutManager = LinearLayoutManager(context,RecyclerView.VERTICAL,false)
binding.rvList.adapter = mAdapter
mAdapter.setEmptyView(EmptyViewHelper.createEmptyTextViewHeight(context,R.string.no_frenids_text.getString()))
mAdapter.setOnItemChildClickListener { adapter, view, position ->
when (view.id) {
R.id.btnGive -> {
val uid = mAdapter?.data?.getOrNull(position)?.uid
if (uid != null && mDressUpInfo != null) {
val dressUpDialog = DressUpDialog()
dressUpDialog.mDressUpInfo = mDressUpInfo
dressUpDialog.mTargetUid = uid
dressUpDialog.show(context)
}
}
else -> {}
}
}
binding.etSearch.doOnTextChanged { text, start, before, count ->
text?.let {
doSearch(text.toString())
}
}
loadFriends()
}
private fun loadFriends() {
val accounts = IMFriendModel.get().myFriendsAccounts
if (accounts.isVerify()) {
UserModel.get().loadUserInfoByUids(accounts)
.compose(bindToLifecycle())
.doOnSuccess {
mAdapter.setNewData(it)
}
.doOnError {
it?.message?.doToast()
}.subscribe()
}
}
private fun doSearch(key: String) {
roomSearch(key)
.compose(bindToLifecycle())
.doOnSuccess {
if (it.isVerify()) {
val newData = mutableListOf<UserInfo>()
it.forEach {
newData.add(UserInfo().apply {
avatar = it.avatar
uid = it.uid
erbanNo = it.erbanNo
nick = it.nick
})
mAdapter.setNewData(newData)
}
}
}.doOnError {
it?.message?.doToast()
}.subscribe()
}
class UserAdapter : BaseBindingAdapter<ItemSearchUserBinding, UserInfo>() {
override fun convert(helper: BaseBindingViewHolder<ItemSearchUserBinding>, item: UserInfo) {
helper.binding.let {
it.avatar.loadAvatar(item.avatar)
it.name.text = item.nick
it.id.text = item.erbanNo.toString()
helper.addOnClickListener(it.btnGive.id)
}
}
}
private fun roomSearch(key: String) : Single<List<SearchRoomInfo>>{
return api.roomSearch(key,2)
.compose(RxHelper.handleBeanData())
.compose(RxHelper.handleSchedulers())
}
private val api: Api = RxNet.create(Api::class.java);
interface Api {
@GET("/search/room")
fun roomSearch(
@Query("key") key: String?,
@Query("type") type: Int
): Single<ServiceResult<List<SearchRoomInfo>>>
}
}

View File

@@ -3,7 +3,6 @@ package com.chwl.app.ui.user.activity
import android.content.Context
import android.content.Intent
import android.view.View
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -21,18 +20,13 @@ import com.chwl.core.UriProvider
import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.user.bean.UserCPListBean
import com.chwl.core.utils.LogUtils
import com.chwl.core.utils.net.DontWarnObserver
import com.chwl.core.utils.net.RxHelper
import com.chwl.library.net.rxnet.RxNet
import com.chwl.library.utils.ResUtil
import com.example.lib_utils.ktx.getString
import com.google.gson.JsonElement
import com.hjq.toast.ToastUtils
import com.netease.nim.uikit.StatusBarUtil
import com.trello.rxlifecycle3.android.ActivityEvent
import io.reactivex.Single
import io.reactivex.SingleObserver
import io.reactivex.disposables.Disposable
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
@@ -59,7 +53,7 @@ class UserCpListActivity : BaseViewBindingActivity<ActivityUserCpListBinding>()
}
private fun initTitle() {
initBlackTitleBar(ResUtil.getString(R.string.My_Cp))
initDarkTitleBar(ResUtil.getString(R.string.My_Cp))
val titleBar = findViewById<View>(R.id.title_bar) as TitleBar
titleBar.addAction(object : ImageAction(R.drawable.ic_cp_list_more) {
override fun performAction(view: View?) {

View File

@@ -173,9 +173,9 @@ fun AnimView.loadAnim(url: String) {
})
}
fun AnimView.loadAnim2(url: String) {
fun AnimView.loadAnim2(url: String,isSafe:Boolean = true) {
if (context.isDestroyed()) return
GlideUtils.instance().downloadFromUrl(context,url.trim(),object : RequestListener<File?> {
GlideUtils.instance().downloadFromUrl2(context,url.trim(),object : RequestListener<File?> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
@@ -193,9 +193,14 @@ fun AnimView.loadAnim2(url: String) {
isFirstResource: Boolean
): Boolean {
if (resource != null) {
if (this@loadAnim2.isAttachedToWindow){
if (isSafe) {
if (this@loadAnim2.isAttachedToWindow){
this@loadAnim2.startPlay(resource)
}
} else {
this@loadAnim2.startPlay(resource)
}
}
return true
}

View File

@@ -5,9 +5,7 @@ import static android.content.Context.CLIPBOARD_SERVICE;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
@@ -18,34 +16,27 @@ import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chwl.app.earn.activity.EarnRecordActivity;
import com.chwl.app.ui.invite.InviteImageHelper;
import com.chwl.app.ui.invite.ShareInviteDialog;
import com.chwl.app.ui.invite.ShareInviteInfo;
import com.chwl.app.ui.wallet.payment.GPaymentClient;
import com.chwl.app.ui.wallet.payment.IPaymentClient;
import com.chwl.app.ui.wallet.payment.PaymentIntent;
import com.chwl.app.ui.wallet.payment.PaymentResult;
import com.chwl.library.language.LanguageHelper;
import com.chwl.library.utils.json.JsonUtils;
import com.example.lib_utils.ICleared;
import com.google.gson.Gson;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.orhanobut.logger.Logger;
import com.chwl.app.UIHelper;
import com.chwl.app.application.IReportConstants;
import com.chwl.app.application.ReportManager;
import com.chwl.app.avroom.activity.AVRoomActivity;
import com.chwl.app.earn.activity.EarnRecordActivity;
import com.chwl.app.ui.im.RouterHandler;
import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity;
import com.chwl.app.ui.invite.InviteImageHelper;
import com.chwl.app.ui.invite.ShareInviteDialog;
import com.chwl.app.ui.invite.ShareInviteInfo;
import com.chwl.app.ui.pay.ChargeActivity;
import com.chwl.app.ui.wallet.payment.GPaymentClient;
import com.chwl.app.ui.wallet.payment.IPaymentClient;
import com.chwl.app.ui.wallet.payment.PaymentIntent;
import com.chwl.app.ui.wallet.payment.PaymentResult;
import com.chwl.app.ui.webview.event.H5NotifyClientEvent;
import com.chwl.app.ui.webview.event.ShowNavEvent;
import com.chwl.app.ui.webview.event.TaroPayResultEvent;
import com.chwl.core.XConstants;
import com.chwl.core.auth.AuthModel;
import com.chwl.core.decoration.bean.DecorationStoreRouterType;
import com.chwl.core.file.FileModel;
import com.chwl.core.manager.AvRoomDataManager;
import com.chwl.core.market_verify.MarketVerifyModel;
import com.chwl.core.pay.PayModel;
@@ -55,18 +46,21 @@ import com.chwl.core.room.bean.RoomInfo;
import com.chwl.core.user.UserModel;
import com.chwl.core.web.bean.WebJsBeanInfo;
import com.chwl.library.common.util.DeviceUtil;
import com.chwl.library.record.AuditRecorderConfiguration;
import com.chwl.library.record.ExtAudioRecorder;
import com.chwl.library.language.LanguageHelper;
import com.chwl.library.rxbus.RxBus;
import com.chwl.library.utils.AppMetaDataUtil;
import com.chwl.library.utils.DeviceUuidFactory;
import com.chwl.library.utils.SystemUtils;
import com.chwl.library.utils.VersionUtil;
import com.chwl.library.utils.config.BasicConfig;
import com.chwl.library.utils.json.JsonUtils;
import com.example.lib_utils.ICleared;
import com.google.gson.Gson;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.orhanobut.logger.Logger;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.HashMap;
/**
@@ -79,9 +73,9 @@ public class JSInterface implements ICleared {
private CommonWebViewActivity mActivity;
private Context context;
private int mPosition;
private MediaRecorder recorder;
private File myRecAudioFile;
private ExtAudioRecorder extAudioRecorder;
// private MediaRecorder recorder;
// private File myRecAudioFile;
// private ExtAudioRecorder extAudioRecorder;
private GPaymentClient paymentClient;
public JSInterface(WebView webView, CommonWebViewActivity activity) {
@@ -420,45 +414,45 @@ public class JSInterface implements ICleared {
NimP2PMessageActivity.start(context, uid);
}
@JavascriptInterface
public boolean startRecode() {
// recorder 实例
AuditRecorderConfiguration configuration = new AuditRecorderConfiguration.Builder()
.uncompressed(true)
.builder();
extAudioRecorder = new ExtAudioRecorder(configuration);
// 录音地址
File sdcardDir = new File(context.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath() +
File.separator + "wewawa");
if (!sdcardDir.exists()) {
boolean mkdirResult = sdcardDir.mkdir();
Log.e(TAG, "startRecode: mkdirResult: " + mkdirResult);
}
myRecAudioFile = new File(sdcardDir.getAbsolutePath(), "wewawa-" + System.currentTimeMillis() + ".wav");
Log.i(TAG, "startRecode: myRecAudioFile path: " + myRecAudioFile.getAbsolutePath());
// 设置输出文件
extAudioRecorder.setOutputFile(myRecAudioFile.getAbsolutePath());
extAudioRecorder.prepare();
extAudioRecorder.start();
return true;
}
@JavascriptInterface
public String stopRecode() {
if (extAudioRecorder == null || myRecAudioFile == null)
return null;
if (!myRecAudioFile.exists()) {
return null;
}
extAudioRecorder.stop();
extAudioRecorder.release();
String url = FileModel.get()
.uploadFile(myRecAudioFile.getAbsolutePath())
.blockingGet();
myRecAudioFile.delete();
Log.i(TAG, "stopRecord: url: " + url);
return url;
}
// @JavascriptInterface
// public boolean startRecode() {
// // recorder 实例
// AuditRecorderConfiguration configuration = new AuditRecorderConfiguration.Builder()
// .uncompressed(true)
// .builder();
// extAudioRecorder = new ExtAudioRecorder(configuration);
// // 录音地址
// File sdcardDir = new File(context.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath() +
// File.separator + "wewawa");
// if (!sdcardDir.exists()) {
// boolean mkdirResult = sdcardDir.mkdir();
// Log.e(TAG, "startRecode: mkdirResult: " + mkdirResult);
// }
// myRecAudioFile = new File(sdcardDir.getAbsolutePath(), "wewawa-" + System.currentTimeMillis() + ".wav");
// Log.i(TAG, "startRecode: myRecAudioFile path: " + myRecAudioFile.getAbsolutePath());
// // 设置输出文件
// extAudioRecorder.setOutputFile(myRecAudioFile.getAbsolutePath());
// extAudioRecorder.prepare();
// extAudioRecorder.start();
// return true;
// }
//
// @JavascriptInterface
// public String stopRecode() {
// if (extAudioRecorder == null || myRecAudioFile == null)
// return null;
// if (!myRecAudioFile.exists()) {
// return null;
// }
// extAudioRecorder.stop();
// extAudioRecorder.release();
// String url = FileModel.get()
// .uploadFile(myRecAudioFile.getAbsolutePath())
// .blockingGet();
// myRecAudioFile.delete();
// Log.i(TAG, "stopRecord: url: " + url);
// return url;
// }
@JavascriptInterface
public void openFamilyPage(String familyId) {

View File

@@ -81,7 +81,10 @@ class BaiShunGameWebFragment : BaseViewBindingFragment<RoomGameFragmentBinding>(
super.onPageStarted(view, url, favicon)
isLoadError = false
if (url == gameUrl) {
dialogManager.showProgressDialog(requireContext())
context?.let {
dialogManager.showProgressDialog(it)
}
}
}
@@ -162,7 +165,7 @@ class BaiShunGameWebFragment : BaseViewBindingFragment<RoomGameFragmentBinding>(
settings?.domStorageEnabled = true
//设置开启数据库缓存
settings?.databaseEnabled = true
settings?.databasePath = (requireContext().applicationContext.filesDir.absolutePath)
settings?.databasePath = (context?.applicationContext?.filesDir?.absolutePath)
//设置⽀持缩放
settings?.setSupportZoom(true)
//设置⾃适应

View File

@@ -86,7 +86,7 @@ class LeaderccGameWebFragment : BaseViewBindingFragment<RoomGameFragmentBinding>
super.onPageStarted(view, url, favicon)
isLoadError = false
if (url == gameUrl) {
dialogManager.showProgressDialog(requireContext())
dialogManager.showProgressDialog(context)
}
}
@@ -162,7 +162,7 @@ class LeaderccGameWebFragment : BaseViewBindingFragment<RoomGameFragmentBinding>
settings?.domStorageEnabled = true
//设置开启数据库缓存
settings?.databaseEnabled = true
settings?.databasePath = (requireContext().applicationContext.filesDir.absolutePath)
settings?.databasePath = (context?.applicationContext?.filesDir?.absolutePath)
//设置⽀持缩放
settings?.setSupportZoom(true)
//设置⾃适应

View File

@@ -667,7 +667,7 @@ public class UserInfoDialog extends AppCompatDialog implements View.OnClickListe
private void drawVAPEffect(String url) {
GlideUtils.instance().downloadFromUrl(getContext(), url, new RequestListener<File>() {
GlideUtils.instance().downloadFromUrl2(getContext(), url, new RequestListener<File>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
ImageLoadUtils.loadImage(context, userInfo.getUserInfoCardPic(), ivUserCardWear);

View File

@@ -115,7 +115,7 @@ object RoomBoomManager {
urls.forEach { url ->
LogUtils.dd(" RoomBoomManager startDownAnim() forEach url=$url")
mAnimLayout?.let { animLayout ->
GlideUtils.instance().downloadFromUrl(
GlideUtils.instance().downloadFromUrl2(
animLayout.context,
url.trim(),
object : RequestListener<File?> {

View File

@@ -135,8 +135,7 @@ class VipCenterBannerAdapter(
})
//todo do , liulishuo 下载器 换 glide 下载 , 注意 .trim() 去掉前后空格符
GlideUtils.instance().downloadFromUrl(holder.vapAnimView.context,data.vipLogo.trim(),object : RequestListener<File?> {
GlideUtils.instance().downloadFromUrl2(holder.vapAnimView.context,data.vipLogo.trim(),object : RequestListener<File?> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#02061d">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@drawable/ic_dress_top_bg"
app:layout_constraintTop_toTopOf="parent" />
<com.chwl.app.base.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_30"
app:layout_constraintTop_toTopOf="parent" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/btnMyDressUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="15dp"
android:drawablePadding="2dp"
android:gravity="center"
android:paddingHorizontal="7dp"
android:paddingVertical="2dp"
android:text="@string/My_Dress"
android:textColor="@color/color_d9e7f7"
android:textSize="12sp"
app:dt_drawableRightHeight="13dp"
app:dt_drawableRightSrc="@drawable/ic_derss_avatar"
app:dt_drawableRightWidth="13dp"
app:dt_drawableType="shape"
app:dt_endColor="#11215b"
app:dt_radius="198dp"
app:dt_startColor="#004a4f"
app:dt_strikeColor="#75b4df"
app:dt_strikeWidth="1dp"
app:layout_constraintBottom_toBottomOf="@+id/title_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/title_bar" />
<FrameLayout
android:id="@+id/infoLayout"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintTop_toBottomOf="@id/title_bar">
<com.chwl.library.widget.text.DrawableTextView
android:layout_width="73dp"
app:dt_drawableType="shape"
app:dt_soildColor="#fbd99a"
android:layout_gravity="center"
app:dt_radius="150dp"
android:layout_height="73dp"/>
<ImageView
android:id="@+id/avatar"
android:layout_width="71dp"
android:src="@drawable/default_avatar"
android:layout_height="71dp"
android:layout_gravity="center" />
<com.chwl.library.widget.SVGAView
android:id="@+id/avatarHead"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center" />
</FrameLayout>
<com.chwl.library.widget.tab.SmartTabLayout2
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="0dp"
app:layout_constraintTop_toBottomOf="@id/infoLayout"
app:stl_distributeEvenly="true"
app:stl_indicatorThickness="0dp"
app:stl_indicatorWidth="0dp"
tools:layout_height="40dp" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPage"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toTopOf="@+id/bottomView"
app:layout_constraintTop_toBottomOf="@id/tabLayout" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/bottomView"
android:layout_width="match_parent"
android:layout_height="66dp"
app:layout_constraintBottom_toBottomOf="parent">
<com.chwl.library.widget.text.DrawableTextView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:dt_drawableType="shape"
app:dt_endColor="#0f1435"
app:dt_leftTopRadius="8dp"
app:dt_rightTopRadius="8dp"
app:dt_startColor="#012e4d" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:drawablePadding="4dp"
android:gravity="center"
android:textColor="#f8ce1f"
android:textStyle="bold"
app:autoSizeStepGranularity="@dimen/picker_default_text_size"
app:dt_drawableLeftHeight="25dp"
app:dt_drawableLeftSrc="@drawable/ic_coin_84"
app:dt_drawableLeftWidth="25dp"
app:dt_drawableType="shape"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/s_sDays_s" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/btnBuy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:gravity="center"
android:minWidth="74dp"
android:minHeight="32dp"
android:paddingHorizontal="12dp"
android:paddingVertical="6dp"
android:text="@string/buy"
android:textColor="#172055"
android:textSize="14sp"
android:textStyle="bold"
app:dt_drawableType="shape"
app:dt_endColor="#e9a71d"
app:dt_radius="47dp"
app:dt_startColor="#FFE3b2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnGive"
app:layout_constraintTop_toTopOf="parent" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/btnGive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="15dp"
android:gravity="center"
android:minWidth="74dp"
android:minHeight="32dp"
android:paddingHorizontal="12dp"
android:paddingVertical="6dp"
android:text="@string/ui_search_searchadapter_03"
android:textColor="#172055"
android:textSize="14sp"
android:textStyle="bold"
app:dt_drawableType="shape"
app:dt_endColor="#4da2ea"
app:dt_radius="47dp"
app:dt_startColor="#b2fcff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/playLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_transparent_50"
android:gravity="center"
android:visibility="gone"
tools:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#02061d">
<com.chwl.app.base.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_30"
app:layout_constraintTop_toTopOf="parent" />
<com.chwl.library.widget.text.DrawableTextView
android:layout_width="0dp"
android:layout_height="0dp"
app:dt_drawableType="shape"
app:dt_radius="436dp"
app:dt_soildColor="#061337"
app:layout_constraintBottom_toBottomOf="@+id/etSearch"
app:layout_constraintEnd_toEndOf="@+id/etSearch"
app:layout_constraintStart_toStartOf="@+id/etSearch"
app:layout_constraintTop_toTopOf="@+id/etSearch" />
<EditText
android:id="@+id/etSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="8dp"
android:background="@color/transparent"
android:gravity="center"
android:paddingVertical="10dp"
android:paddingStart="45dp"
android:paddingEnd="10dp"
android:textColor="@color/color_d9e7f7"
android:textColorHint="@color/color_d9e7f7"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title_bar"
tools:text="111" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="15dp"
android:src="@drawable/ic_send_search"
app:layout_constraintBottom_toBottomOf="@id/etSearch"
app:layout_constraintStart_toStartOf="@id/etSearch"
app:layout_constraintTop_toTopOf="@+id/etSearch"
app:tint="#707d97" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etSearch" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -537,14 +537,14 @@
<!-- avatar -->
<ImageView
android:id="@+id/ivUserHead"
android:layout_width="@dimen/dp_82"
android:layout_height="@dimen/dp_82"
android:layout_width="92dp"
android:layout_height="96dp"
android:src="@drawable/default_avatar"
tools:src="@color/white"
app:layout_constraintBottom_toBottomOf="@+id/ivHeadWear"
app:layout_constraintEnd_toEndOf="@+id/ivHeadWear"
app:layout_constraintStart_toStartOf="@+id/ivHeadWear"
app:layout_constraintTop_toTopOf="@id/ivHeadWear" />
app:layout_constraintTop_toTopOf="@id/ivHeadWear"
tools:src="@color/white" />
<com.chwl.library.widget.SVGAView
android:id="@+id/ivHeadWear"

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.chwl.app.base.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginTop="@dimen/dp_30"
app:layout_constraintTop_toTopOf="parent" />
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_bar">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="@drawable/ic_dress_dialog_bg"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/picLayout"
android:layout_width="155dp"
android:layout_height="155dp"
android:layout_marginTop="32dp"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_gif" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:gravity="center"
android:textColor="@color/color_d9e7f7"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/picLayout"
tools:text="sssss" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="9dp"
android:layout_marginTop="7dp"
android:drawablePadding="2dp"
android:gravity="center"
android:textColor="#f8ce1f"
android:textSize="18sp"
android:visibility="gone"
app:dt_drawableLeftHeight="18dp"
app:dt_drawableLeftSrc="@drawable/ic_gif"
app:dt_drawableLeftWidth="18dp"
app:dt_drawableType="shape"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/name"
tools:text="@string/s_sDays_s"
tools:visibility="visible" />
<ImageView
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ic_dress_dialog_line"
android:layout_marginHorizontal="23dp"
android:layout_marginTop="18dp"
app:layout_constraintTop_toBottomOf="@id/price" />
<View
android:layout_width="match_parent"
android:layout_height="90dp"
app:layout_constraintTop_toBottomOf="@id/line" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/btnCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:gravity="center"
android:minWidth="74dp"
android:minHeight="32dp"
android:paddingHorizontal="12dp"
android:paddingVertical="6dp"
android:text="@string/cancel"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
app:dt_drawableType="shape"
app:dt_radius="47dp"
app:dt_soildColor="@color/black_transparent_30"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnBuy"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/line" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/btnBuy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:gravity="center"
android:minWidth="74dp"
android:minHeight="32dp"
android:paddingHorizontal="12dp"
android:paddingVertical="6dp"
android:text="@string/buy"
android:textColor="#172055"
android:textSize="14sp"
android:textStyle="bold"
app:dt_drawableType="shape"
app:dt_endColor="#e9a71d"
app:dt_radius="47dp"
app:dt_startColor="#FFE3b2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/btnCancel"
app:layout_constraintTop_toBottomOf="@id/line" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -44,6 +44,7 @@
android:textColor="@color/white"
android:textSize="10sp"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="5dp"
android:layout_marginBottom="10dp"
android:background="@drawable/ic_dress_item_n">
<com.chwl.app.common.widget.RectRoundImageView
android:id="@+id/picBg"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="9dp"
android:background="#04184A"
app:borderRadius="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:type="round" />
<LinearLayout
android:gravity="center"
android:id="@+id/picLayout"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginTop="9dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="9dp"
android:lines="1"
android:paddingVertical="6dp"
android:textColor="#d9e7f7"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/picBg"
tools:text="11111" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="9dp"
android:drawablePadding="2dp"
android:gravity="center"
android:paddingBottom="7dp"
android:textColor="#f8ce1f"
android:textSize="15sp"
android:visibility="gone"
app:dt_drawableLeftHeight="18dp"
app:dt_drawableLeftSrc="@drawable/ic_coin_84"
app:dt_drawableLeftWidth="18dp"
app:dt_drawableType="shape"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/name"
tools:text="@string/s_sDays_s"
tools:visibility="visible" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/discount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="3dp"
android:gravity="center"
android:paddingVertical="6dp"
android:textColor="#D9E7F7"
android:textSize="12sp"
android:visibility="gone"
app:dt_drawableType="shape"
app:dt_leftBottomRadius="13dp"
app:dt_rightBottomRadius="13dp"
app:dt_soildColor="#002840"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/price"
tools:text="111"
tools:visibility="visible" />
<View
android:layout_width="match_parent"
android:layout_height="3dp"
app:layout_constraintTop_toBottomOf="@+id/discount" />
<ImageView
android:id="@+id/empty"
android:layout_width="55dp"
android:layout_height="55dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/picBg"
app:layout_constraintEnd_toEndOf="@id/picBg"
app:layout_constraintStart_toStartOf="@id/picBg"
app:layout_constraintTop_toTopOf="@id/picBg"
tools:background="@drawable/icon_room_bg_gif_type"
tools:visibility="visible" />
<ImageView
android:id="@+id/btnPlay"
android:layout_width="46dp"
android:layout_height="42dp"
android:layout_marginEnd="-8dp"
android:layout_marginBottom="-8dp"
android:paddingHorizontal="10dp"
android:paddingVertical="10dp"
android:src="@drawable/ic_dress_play"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/picLayout"
app:layout_constraintEnd_toEndOf="@id/picLayout"
tools:visibility="visible" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/limit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="7dp"
android:paddingVertical="2dp"
android:textColor="#51281b"
android:textSize="12sp"
app:dt_drawableType="shape"
app:dt_endColor="#E9A71D"
app:dt_leftBottomRadius="0dp"
app:dt_leftTopRadius="10dp"
app:dt_rightBottomRadius="10dp"
app:dt_rightTopRadius="0dp"
app:dt_startColor="#FFE3B2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Limited" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="72dp">
<ImageView
android:id="@+id/avatar"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="4dp"
android:textColor="@color/color_d9e7f7"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="@+id/avatar"
app:layout_constraintTop_toTopOf="@+id/avatar" />
<TextView
android:id="@+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="4dp"
android:alpha="0.5"
android:textColor="@color/color_d9e7f7"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/avatar"
app:layout_constraintStart_toEndOf="@+id/avatar" />
<com.chwl.library.widget.text.DrawableTextView
android:id="@+id/btnGive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="15dp"
android:gravity="center"
android:minWidth="60dp"
android:minHeight="26dp"
android:paddingHorizontal="12dp"
android:paddingVertical="6dp"
android:text="@string/ui_search_searchadapter_03"
android:textColor="#172055"
android:textSize="14sp"
android:textStyle="bold"
app:dt_drawableType="shape"
app:dt_endColor="#4da2ea"
app:dt_radius="47dp"
app:dt_startColor="#b2fcff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="70dp"
android:layout_height="85dp"
android:layout_marginHorizontal="5dp"
android:layout_gravity="center">
<ImageView
android:id="@+id/tabBg"
android:background="@drawable/ic_dress_tab_bg_n"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/tabImg"
android:layout_width="37dp"
android:layout_height="37dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@color/white" />
<TextView
android:id="@+id/tabText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:lines="1"
android:alpha="0.5"
android:textColor="#D9E7F7"
android:textSize="11sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tabImg"
tools:text="tab" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -5343,4 +5343,5 @@
<string name="s_sDays">%s/%s يوم</string>
<string name="sDays">%s يوم</string>
<string name="unDay">&lt;1 يوم</string>
<string name="s_sDays_s">%s/%s يوم %s</string>
</resources>

View File

@@ -5139,4 +5139,5 @@ Toplam imza alın, ilgili ödülü alın
<string name="s_sDays">%s/%s gün</string>
<string name="sDays">%s gün</string>
<string name="unDay">&lt;1 gün</string>
<string name="s_sDays_s">%s/%s gün %s</string>
</resources>

View File

@@ -5286,5 +5286,6 @@
<string name="s_sDays">%s/%s天</string>
<string name="sDays">%s天</string>
<string name="unDay">&lt;1天</string>
<string name="s_sDays_s">%s/%s天 %s</string>
</resources>

View File

@@ -769,5 +769,6 @@
<color name="color_696969">#696969</color>
<color name="color_ff9741">#ff9741</color>
<color name="color_ff5656">#ff5656</color>
<color name="color_d9e7f7">#d9e7f7</color>
</resources>

View File

@@ -5350,6 +5350,14 @@ You cannot join again within 24 hours after leaving</string>
<string name="sDays">%sDays</string>
<string name="unDay">&lt;1Days</string>
<string name="Not_used">Not used</string>
<string name="userInfoBg">userInfoBg</string>
<string name="My_Dress">My Dress</string>
<string name="vipLimit">VIP限制 %s</string>
<string name="obtainWayAction">活动获取 不可购买</string>
<string name="s_sDays_s">%s/%sDays %s</string>
</resources>

View File

@@ -16,6 +16,8 @@
<!-- 记得移除测试用代码,正式包 别包含进去 -->
<domain includeSubdomains="true">beta.api.molistar.xyz</domain>
<domain includeSubdomains="true">beta.img.pekolive.com</domain>
<domain includeSubdomains="true">image.lecheng163.com</domain>
<domain includeSubdomains="true">image.hfighting.com</domain>
</domain-config>
<domain-config cleartextTrafficPermitted="false">

View File

@@ -10,5 +10,12 @@ data class DecorationInfo(
val iosPic: String = "",
val name: String = "",
val pic: String = "",
val dressLimitStatus: Int = 0
val dressLimitStatus: Int = 0,
val effect: String = "", //装扮动效图片
val effectType: Int = 0, //动效类型
val discountPrice: Double = 0.0, //折扣价格
val vipLevel: Int = 0, //VIP等级
val discount: Int = 0, // 折扣百分比
val vipLimit: Int = 0, //VIP等级限定 ,0=不限定
val obtainWay: Int = 0 //1-普通 2-活动
)

View File

@@ -0,0 +1,45 @@
package com.chwl.core.decoration.bean;
import lombok.Data;
@Data
public class DressUpInfo {
public boolean isNull;
public boolean isMy;
public boolean isSelect;
public int dressLimitStatus;
public String pic;
public String name;
public String word;
public int price;
public int buyDay;
public int originalPrice;
public String effect; //装扮动效图片
/**
* 特效类型 1-mp4 2-svga
*/
public int effectType;
public int dressType; // 商品类型
public int dressId; // 商品类型
public int discountPrice; //折扣价格
public int vipLevel; //当前用户VIP等级
public int discount; // 折扣百分比
public int vipLimit; //VIP等级限定 ,0=不限定
/**
* //1-普通 2-活动
*/
public int obtainWay;
public int id; //商品类型id
public int expireDays; //剩余天数
public boolean hasExpired; //是否过期
public @interface EffectType{
int MP4 = 1;
int SVGA = 2;
}
}

View File

@@ -0,0 +1,20 @@
package com.chwl.core.decoration.bean;
import lombok.Data;
@Data
public class ShopMine {
public int dressId; //装扮id
public int dressType; //装扮类型
public int obtainWay; //获取方式 1-普通 2-活动
public String pic;
public String name;
public String effect;
public boolean used;
public int expireDays = -1; //剩余天数
public int effectType;
public boolean hasExpired; //是否过期
}

View File

@@ -122,6 +122,7 @@ public class HeadwearModel extends BaseModel implements IHeadwearModel {
/**
* 使用已经购买的头饰
* id == 0标识不使用头饰
*
* @param headwearId
* @return

View File

@@ -36,6 +36,7 @@ public class TabInfo implements Parcelable,Serializable {
protected String name;
protected String pict;
protected int seq;
protected int res;
protected int type;
protected boolean status;
protected boolean istop;
@@ -49,6 +50,12 @@ public class TabInfo implements Parcelable,Serializable {
this.name = name;
}
public TabInfo(int id, String name,int res) {
this.id = id;
this.name = name;
this.res = res;
}
protected TabInfo(Parcel in) {
id = in.readInt();

View File

@@ -7,21 +7,12 @@ import android.annotation.SuppressLint;
import android.text.TextUtils;
import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.chwl.core.utils.MyUriUtils;
import com.chwl.library.common.glide.GlideUtils;
import com.google.gson.Gson;
import com.netease.nim.uikit.common.util.string.StringUtil;
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder;
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage;
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
import com.orhanobut.logger.Logger;
import com.chwl.core.DemoCache;
import com.chwl.core.auth.AuthModel;
import com.chwl.core.base.BaseModel;
@@ -41,12 +32,20 @@ import com.chwl.core.room.queue.bean.MicMemberInfo;
import com.chwl.core.user.UserModel;
import com.chwl.core.user.bean.UserInfo;
import com.chwl.core.utils.LogUtils;
import com.chwl.core.utils.MyUriUtils;
import com.chwl.core.vip.bean.UserVipInfo;
import com.chwl.library.common.glide.GlideUtils;
import com.chwl.library.utils.ListUtils;
import com.chwl.library.utils.NetworkUtils;
import com.chwl.library.utils.codec.DESUtils;
import com.chwl.library.utils.codec.MD5Utils;
import com.chwl.library.utils.config.BasicConfig;
import com.google.gson.Gson;
import com.netease.nim.uikit.common.util.string.StringUtil;
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder;
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage;
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum;
import com.orhanobut.logger.Logger;
import org.greenrobot.eventbus.EventBus;
@@ -55,7 +54,6 @@ import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -67,11 +65,6 @@ import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.BiConsumer;
import io.reactivex.functions.Consumer;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.http.GET;
import retrofit2.http.Headers;
@@ -634,7 +627,7 @@ public class DynamicFaceModel extends BaseModel implements IDynamicFaceModel {
String url = onlineFacesList.getZipUrl();
GlideUtils.instance().downloadFromUrl(getContext(), url, new RequestListener<File>() {
GlideUtils.instance().downloadFromUrl2(getContext(), url, new RequestListener<File>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
Logger.d("face.zip download onLoadFailed");

View File

@@ -6,6 +6,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import com.chwl.core.manager.AvRoomDataManager;
import com.chwl.library.utils.BitmapLruCacheHelper;
import java.util.ArrayList;
import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.chwl.core.utils;
package com.chwl.library.utils;
import android.graphics.Bitmap;
import android.util.Log;

View File

@@ -1,8 +1,15 @@
package com.chwl.library.widget
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.graphics.drawable.AnimationDrawable
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.LruCache
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
@@ -76,7 +83,7 @@ class SVGAView : SVGAImageView, ILog {
}
fun loadUrl(url: String?,autoPayer:Boolean = true) {
logD("loadUrl() url:$url")
logD("SVGAView loadUrl() url:$url")
if (url.isNullOrEmpty()) {
this.resourceUrl = null
this.setImageDrawable(null)
@@ -84,17 +91,8 @@ class SVGAView : SVGAImageView, ILog {
return
}
if (!url.endsWith(".svga")) {
this.resourceUrl = null
this.setImageDrawable(null)
onViewStateChanged(0)
GlideUtils.instance().load(url,this)
return
}
if (url == resourceUrl && drawable is SVGADrawable) {
logD("loadUrl() 已加载 isAnimating:$isAnimating")
logD("SVGAView loadUrl() 已加载 isAnimating:$isAnimating")
if (!isAnimating) {
if (autoPayer) {
startAnimation()
@@ -107,7 +105,7 @@ class SVGAView : SVGAImageView, ILog {
this.resourceUrl = url
val cacheItem = svgaCache?.get(url)
if (cacheItem != null) {
logD("loadUrl() 有缓存")
logD("SVGAView loadUrl() 有缓存")
this@SVGAView.setImageDrawable(SVGADrawable(cacheItem))
if (autoPayer) {
this@SVGAView.startAnimation()
@@ -118,15 +116,15 @@ class SVGAView : SVGAImageView, ILog {
}
private fun loadSVGAUrl(url: String,autoPayer:Boolean = true) {
logD("loadSVGAUrl url:$url")
GlideUtils.instance().downloadFromUrl(context,url,object : RequestListener<File?> {
logD("SVGAView loadSVGAUrl url:$url")
GlideUtils.instance().downloadFromUrl2(context,url,object : RequestListener<File?> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<File?>?,
isFirstResource: Boolean
): Boolean {
logD("loadSVGAUrl onDownloadError url:$url")
logD("SVGAView loadSVGAUrl onDownloadError url:$url")
if (resourceUrl == url) {
onViewStateChanged(-1)
}
@@ -142,20 +140,112 @@ class SVGAView : SVGAImageView, ILog {
): Boolean {
if (resource != null) {
val path = resource.path
logD("loadSVGAUrl onDownloadCompleted url:$url path:$path")
if (resourceUrl == url) {
loadSVGAFile(url, path,autoPayer)
var isImg = false
var outMimeType = "null"
try {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
val decodeFile = BitmapFactory.decodeFile(path, options)
outMimeType = options.outMimeType
isImg = true
} catch (e: Exception) {
isImg = false
}
logD("SVGAView loadSVGAUrl onDownloadCompleted url:$url isImg=$isImg outMimeType=$outMimeType path:$path")
if (!isImg) {
loadSVGAFile(url, path, autoPayer)
} else {
this@SVGAView.post {
this@SVGAView.resourceUrl = null
onViewStateChanged(0)
loadImage(url)
}
}
}
}
return true
}
})
}
private fun loadImage(url: String) {
Glide.with(this)
.asBitmap()
.dontAnimate()
.dontTransform()
.load(url)
.listener(object : RequestListener<Bitmap?> {
override fun onLoadFailed(
e: GlideException?,
model: Any,
target: Target<Bitmap?>,
isFirstResource: Boolean
): Boolean {
this@SVGAView.resourceUrl = null
onViewStateChanged(0)
return false
}
override fun onResourceReady(
resource: Bitmap?,
model: Any,
target: Target<Bitmap?>,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
if (resource == null) return false
val split: List<Drawable> = split(resource)
val animationDrawable = AnimationDrawable()
for (i in split.indices) {
animationDrawable.addFrame(split[i], 200)
}
this@SVGAView.post(Runnable {
this@SVGAView.setImageDrawable(animationDrawable)
animationDrawable.isOneShot = false
animationDrawable.start()
})
return false
}
}).submit()
}
fun split(bitmap: Bitmap?): List<Drawable> {
val pieces: MutableList<Drawable> = ArrayList()
try {
if (bitmap!!.width == bitmap.height) {
pieces.add(BitmapDrawable(bitmap))
} else {
val matrix = Matrix()
matrix.setScale(0.5f, 0.5f)
val width = bitmap.width
val pieceWidth = bitmap.height
val pieceHeight = bitmap.height
val xPiece = width / pieceWidth
for (j in 0 until xPiece) {
val xValue = j * pieceWidth
pieces.add(
BitmapDrawable(
Bitmap.createBitmap(
bitmap, xValue, 0,
pieceWidth, pieceHeight, matrix, true
)
)
)
}
}
} catch (e: java.lang.Exception) {
}
return pieces
}
private fun loadSVGAFile(url: String, path: String,autoPayer:Boolean = true) {
try {
logD("loadSVGAFile path:$path url:$url")
logD("SVGAView loadSVGAFile path:$path url:$url")
val inputStream = BufferedInputStream(FileInputStream(path))
shareParser().decodeFromInputStream(
inputStream,
@@ -188,7 +278,7 @@ class SVGAView : SVGAImageView, ILog {
)
} catch (e: Exception) {
e.printStackTrace()
logD("loadSVGAFile url:$url e:${e.message}")
logD("SVGAView loadSVGAFile url:$url e:${e.message}")
onViewStateChanged(-1)
}
}
@@ -197,16 +287,16 @@ class SVGAView : SVGAImageView, ILog {
* @param state -1 异常、0 空、1 成功
*/
private fun onViewStateChanged(state: Int) {
logD("onViewStateChanged state:$state")
logD("SVGAView onViewStateChanged state:$state")
}
fun bindCache(cache: SVGACache?) {
logD("bindCache() cache:$cache")
logD("SVGAView bindCache() cache:$cache")
this.svgaCache = cache
}
fun setLogTag(tag: String) {
logD("setLogTag() newTag:$tag oldTag:$logTag")
logD("SVGAView setLogTag() newTag:$tag oldTag:$logTag")
this.logTag = tag
}
@@ -219,23 +309,25 @@ class SVGAView : SVGAImageView, ILog {
}
override fun onDetachedFromWindow() {
logD("onDetachedFromWindow()")
logD("SVGAView onDetachedFromWindow()")
super.onDetachedFromWindow()
}
override fun onAttachedToWindow() {
logD("onAttachedToWindow()")
logD("SVGAView onAttachedToWindow()")
super.onAttachedToWindow()
if (resumePlayAfterAttached) {
if (drawable is SVGADrawable) {
if (!isAnimating) {
logD("onAttachedToWindow() startAnimation")
logD("SVGAView onAttachedToWindow() startAnimation")
startAnimation()
}
}
}
}
interface SVGACache {
fun get(key: String): SVGAVideoEntity?

View File

@@ -0,0 +1,96 @@
/**
* Copyright (C) 2015 ogaclejapan
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
public abstract class SmartTabIndicationInterpolator {
public static final SmartTabIndicationInterpolator SMART = new SmartIndicationInterpolator();
public static final SmartTabIndicationInterpolator LINEAR = new LinearIndicationInterpolator();
static final int ID_SMART = 0;
static final int ID_LINEAR = 1;
public static SmartTabIndicationInterpolator of(int id) {
switch (id) {
case ID_SMART:
return SMART;
case ID_LINEAR:
return LINEAR;
default:
throw new IllegalArgumentException("Unknown id: " + id);
}
}
public abstract float getLeftEdge(float offset);
public abstract float getRightEdge(float offset);
public float getThickness(float offset) {
return 1f; //Always the same thickness by default
}
public static class SmartIndicationInterpolator extends SmartTabIndicationInterpolator {
private static final float DEFAULT_INDICATOR_INTERPOLATION_FACTOR = 3.0f;
private final Interpolator leftEdgeInterpolator;
private final Interpolator rightEdgeInterpolator;
public SmartIndicationInterpolator() {
this(DEFAULT_INDICATOR_INTERPOLATION_FACTOR);
}
public SmartIndicationInterpolator(float factor) {
leftEdgeInterpolator = new AccelerateInterpolator(factor);
rightEdgeInterpolator = new DecelerateInterpolator(factor);
}
@Override
public float getLeftEdge(float offset) {
return leftEdgeInterpolator.getInterpolation(offset);
}
@Override
public float getRightEdge(float offset) {
return rightEdgeInterpolator.getInterpolation(offset);
}
@Override
public float getThickness(float offset) {
return 1f / (1.0f - getLeftEdge(offset) + getRightEdge(offset));
}
}
public static class LinearIndicationInterpolator extends SmartTabIndicationInterpolator {
@Override
public float getLeftEdge(float offset) {
return offset;
}
@Override
public float getRightEdge(float offset) {
return offset;
}
}
}

View File

@@ -0,0 +1,644 @@
/**
* Copyright (C) 2015 ogaclejapan
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.core.view.ViewCompat;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.chwl.library.R;
/**
* To be used with ViewPager to provide a tab indicator component which give constant feedback as
* to
* the user's scroll progress.
* <p>
* To use the component, simply add it to your view hierarchy. Then in your
* {@link android.app.Activity} or {@link androidx.fragment.app.Fragment} call
* {@link #setViewPager(ViewPager)} providing it the ViewPager this
* layout
* is being used for.
* <p>
* The colors can be customized in two ways. The first and simplest is to provide an array of
* colors
* via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
* alternative is via the {@link TabColorizer} interface which provides you complete control over
* which color is used for any individual position.
* <p>
* The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
* providing the layout ID of your custom layout.
* <p>
* Forked from Google Samples &gt; SlidingTabsBasic &gt;
* <a href="https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html">SlidingTabLayout</a>
*/
public class SmartTabLayout extends HorizontalScrollView {
private static final boolean DEFAULT_DISTRIBUTE_EVENLY = false;
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TITLE_OFFSET_AUTO_CENTER = -1;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final boolean TAB_VIEW_TEXT_ALL_CAPS = true;
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
private static final int TAB_VIEW_TEXT_COLOR = 0xFC000000;
private static final int TAB_VIEW_TEXT_MIN_WIDTH = 0;
private static final boolean TAB_CLICKABLE = true;
private static final int NO_TEXT_STYLE = -1;
protected final SmartTabStrip tabStrip;
private int titleOffset;
private int tabViewBackgroundResId;
private boolean tabViewTextAllCaps;
private ColorStateList tabViewTextColors;
private float tabViewTextSize;
private int tabViewTextHorizontalPadding;
private int tabViewTextMinWidth;
private ViewPager viewPager;
private ViewPager.OnPageChangeListener viewPagerPageChangeListener;
private OnScrollChangeListener onScrollChangeListener;
private TabProvider tabProvider;
private InternalTabClickListener internalTabClickListener;
private OnTabClickListener onTabClickListener;
private boolean distributeEvenly;
private int textAppearance;
public SmartTabLayout(Context context) {
this(context, null);
}
public SmartTabLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SmartTabLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Disable the Scroll Bar
setHorizontalScrollBarEnabled(false);
final DisplayMetrics dm = getResources().getDisplayMetrics();
final float density = dm.density;
int tabBackgroundResId = NO_ID;
boolean textAllCaps = TAB_VIEW_TEXT_ALL_CAPS;
ColorStateList textColors;
float textSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP, dm);
int textHorizontalPadding = (int) (TAB_VIEW_PADDING_DIPS * density);
int textMinWidth = (int) (TAB_VIEW_TEXT_MIN_WIDTH * density);
boolean distributeEvenly = DEFAULT_DISTRIBUTE_EVENLY;
int customTabLayoutId = NO_ID;
int customTabTextViewId = NO_ID;
boolean clickable = TAB_CLICKABLE;
int titleOffset = (int) (TITLE_OFFSET_DIPS * density);
int textStyle = NO_TEXT_STYLE;
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.stl_SmartTabLayout, defStyle, 0);
tabBackgroundResId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_defaultTabBackground, tabBackgroundResId);
textAllCaps = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextAllCaps, textAllCaps);
textColors = a.getColorStateList(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextColor);
textSize = a.getDimension(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextSize, textSize);
textHorizontalPadding = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextHorizontalPadding, textHorizontalPadding);
textMinWidth = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextMinWidth, textMinWidth);
customTabLayoutId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_customTabTextLayoutId, customTabLayoutId);
customTabTextViewId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_customTabTextViewId, customTabTextViewId);
distributeEvenly = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_distributeEvenly, distributeEvenly);
clickable = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_clickable, clickable);
titleOffset = a.getLayoutDimension(
R.styleable.stl_SmartTabLayout_stl_titleOffset, titleOffset);
textStyle = a.getResourceId(R.styleable.stl_SmartTabLayout_stl_tabTextStyle, textStyle);
a.recycle();
this.titleOffset = titleOffset;
this.tabViewBackgroundResId = tabBackgroundResId;
this.tabViewTextAllCaps = textAllCaps;
this.tabViewTextColors = (textColors != null)
? textColors
: ColorStateList.valueOf(TAB_VIEW_TEXT_COLOR);
this.tabViewTextSize = textSize;
this.tabViewTextHorizontalPadding = textHorizontalPadding;
this.tabViewTextMinWidth = textMinWidth;
this.internalTabClickListener = clickable ? new InternalTabClickListener() : null;
this.distributeEvenly = distributeEvenly;
this.textAppearance = textStyle;
if (customTabLayoutId != NO_ID) {
setCustomTabView(customTabLayoutId, customTabTextViewId);
}
this.tabStrip = new SmartTabStrip(context, attrs);
if (distributeEvenly && tabStrip.isIndicatorAlwaysInCenter()) {
throw new UnsupportedOperationException(
"'distributeEvenly' and 'indicatorAlwaysInCenter' both use does not support");
}
// Make sure that the Tab Strips fills this View
setFillViewport(!tabStrip.isIndicatorAlwaysInCenter());
addView(tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (onScrollChangeListener != null) {
onScrollChangeListener.onScrollChanged(l, oldl);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (tabStrip.isIndicatorAlwaysInCenter() && tabStrip.getChildCount() > 0) {
View firstTab = tabStrip.getChildAt(0);
View lastTab = tabStrip.getChildAt(tabStrip.getChildCount() - 1);
int start = (w - Utils.getMeasuredWidth(firstTab)) / 2 - Utils.getMarginStart(firstTab);
int end = (w - Utils.getMeasuredWidth(lastTab)) / 2 - Utils.getMarginEnd(lastTab);
tabStrip.setMinimumWidth(tabStrip.getMeasuredWidth());
ViewCompat.setPaddingRelative(this, start, getPaddingTop(), end, getPaddingBottom());
setClipToPadding(false);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// Ensure first scroll
if (changed && viewPager != null) {
scrollToTab(viewPager.getCurrentItem(), 0);
}
}
/**
* Set the behavior of the Indicator scrolling feedback.
*
* @param interpolator {@link com.ogaclejapan.smarttablayout.SmartTabIndicationInterpolator}
*/
public void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) {
tabStrip.setIndicationInterpolator(interpolator);
}
/**
* Set the custom {@link TabColorizer} to be used.
*
* If you only require simple customisation then you can use
* {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
* similar effects.
*/
public void setCustomTabColorizer(TabColorizer tabColorizer) {
tabStrip.setCustomTabColorizer(tabColorizer);
}
/**
* Set the color used for styling the tab text. This will need to be called prior to calling
* {@link #setViewPager(ViewPager)} otherwise it will not get set
*
* @param color to use for tab text
*/
public void setDefaultTabTextColor(int color) {
tabViewTextColors = ColorStateList.valueOf(color);
}
/**
* Sets the colors used for styling the tab text. This will need to be called prior to calling
* {@link #setViewPager(ViewPager)} otherwise it will not get set
*
* @param colors ColorStateList to use for tab text
*/
public void setDefaultTabTextColor(ColorStateList colors) {
tabViewTextColors = colors;
}
/**
* Set the same weight for tab
*/
public void setDistributeEvenly(boolean distributeEvenly) {
this.distributeEvenly = distributeEvenly;
}
/**
* Sets the colors to be used for indicating the selected tab. These colors are treated as a
* circular array. Providing one color will mean that all tabs are indicated with the same color.
*/
public void setSelectedIndicatorColors(int... colors) {
tabStrip.setSelectedIndicatorColors(colors);
}
/**
* Sets the colors to be used for tab dividers. These colors are treated as a circular array.
* Providing one color will mean that all tabs are indicated with the same color.
*/
public void setDividerColors(int... colors) {
tabStrip.setDividerColors(colors);
}
/**
* Set the {@link ViewPager.OnPageChangeListener}. When using {@link SmartTabLayout} you are
* required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
* that the layout can update it's scroll position correctly.
*
* @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
*/
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
viewPagerPageChangeListener = listener;
}
/**
* Set {@link OnScrollChangeListener} for obtaining values of scrolling.
*
* @param listener the {@link OnScrollChangeListener} to set
*/
public void setOnScrollChangeListener(OnScrollChangeListener listener) {
onScrollChangeListener = listener;
}
/**
* Set {@link OnTabClickListener} for obtaining click event.
*
* @param listener the {@link OnTabClickListener} to set
*/
public void setOnTabClickListener(OnTabClickListener listener) {
onTabClickListener = listener;
}
/**
* Set the custom layout to be inflated for the tab views.
*
* @param layoutResId Layout id to be inflated
* @param textViewId id of the {@link TextView} in the inflated view
*/
public void setCustomTabView(int layoutResId, int textViewId) {
tabProvider = new SimpleTabProvider(getContext(), layoutResId, textViewId);
}
/**
* Set the custom layout to be inflated for the tab views.
*
* @param provider {@link TabProvider}
*/
public void setCustomTabView(TabProvider provider) {
tabProvider = provider;
}
/**
* Sets the associated view pager. Note that the assumption here is that the pager content
* (number of tabs and tab titles) does not change after this call has been made.
*/
public void setViewPager(ViewPager viewPager) {
tabStrip.removeAllViews();
this.viewPager = viewPager;
if (viewPager != null && viewPager.getAdapter() != null) {
viewPager.addOnPageChangeListener(new InternalViewPagerListener());
populateTabStrip();
}
}
/**
* Returns the view at the specified position in the tabs.
*
* @param position the position at which to get the view from
* @return the view at the specified position or null if the position does not exist within the
* tabs
*/
public View getTabAt(int position) {
return tabStrip.getChildAt(position);
}
/**
* Create a default view to be used for tabs. This is called if a custom tab view is not set via
* {@link #setCustomTabView(int, int)}.
*/
protected TextView createDefaultTabView(CharSequence title) {
TextView textView = new TextView(getContext());
textView.setGravity(Gravity.CENTER);
textView.setText(title);
if (textAppearance != NO_TEXT_STYLE) {
textView.setTextAppearance(getContext(), textAppearance);
} else {
textView.setTextColor(tabViewTextColors);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabViewTextSize);
textView.setTypeface(Typeface.DEFAULT_BOLD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
textView.setAllCaps(tabViewTextAllCaps);
}
if (tabViewTextMinWidth > 0) {
textView.setMinWidth(tabViewTextMinWidth);
}
}
if (tabViewBackgroundResId != NO_ID) {
textView.setBackgroundResource(tabViewBackgroundResId);
} else {
// If we're running on Honeycomb or newer, then we can use the Theme's
// selectableItemBackground to ensure that the View has a pressed state
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
outValue, true);
textView.setBackgroundResource(outValue.resourceId);
}
textView.setPadding(
tabViewTextHorizontalPadding, 0,
tabViewTextHorizontalPadding, 0);
textView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = viewPager.getAdapter();
for (int i = 0; i < adapter.getCount(); i++) {
final View tabView = (tabProvider == null)
? createDefaultTabView(adapter.getPageTitle(i))
: tabProvider.createTabView(tabStrip, i, adapter);
if (tabView == null) {
throw new IllegalStateException("tabView is null.");
}
if (distributeEvenly) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
lp.width = 0;
lp.weight = 1;
}
if (internalTabClickListener != null) {
tabView.setOnClickListener(internalTabClickListener);
}
tabStrip.addView(tabView);
if (i == viewPager.getCurrentItem()) {
tabView.setSelected(true);
}
}
}
private void scrollToTab(int tabIndex, float positionOffset) {
final int tabStripChildCount = tabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
return;
}
final boolean isLayoutRtl = Utils.isLayoutRtl(this);
View selectedTab = tabStrip.getChildAt(tabIndex);
int widthPlusMargin = Utils.getWidth(selectedTab) + Utils.getMarginHorizontally(selectedTab);
int extraOffset = (int) (positionOffset * widthPlusMargin);
if (tabStrip.isIndicatorAlwaysInCenter()) {
if (0f < positionOffset && positionOffset < 1f) {
View nextTab = tabStrip.getChildAt(tabIndex + 1);
int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
}
View firstTab = tabStrip.getChildAt(0);
int x;
if (isLayoutRtl) {
int first = Utils.getWidth(firstTab) + Utils.getMarginEnd(firstTab);
int selected = Utils.getWidth(selectedTab) + Utils.getMarginEnd(selectedTab);
x = Utils.getEnd(selectedTab) - Utils.getMarginEnd(selectedTab) - extraOffset;
x -= (first - selected) / 2;
} else {
int first = Utils.getWidth(firstTab) + Utils.getMarginStart(firstTab);
int selected = Utils.getWidth(selectedTab) + Utils.getMarginStart(selectedTab);
x = Utils.getStart(selectedTab) - Utils.getMarginStart(selectedTab) + extraOffset;
x -= (first - selected) / 2;
}
scrollTo(x, 0);
return;
}
int x;
if (titleOffset == TITLE_OFFSET_AUTO_CENTER) {
if (0f < positionOffset && positionOffset < 1f) {
View nextTab = tabStrip.getChildAt(tabIndex + 1);
int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
}
if (isLayoutRtl) {
x = -Utils.getWidthWithMargin(selectedTab) / 2 + getWidth() / 2;
x -= Utils.getPaddingStart(this);
} else {
x = Utils.getWidthWithMargin(selectedTab) / 2 - getWidth() / 2;
x += Utils.getPaddingStart(this);
}
} else {
if (isLayoutRtl) {
x = (tabIndex > 0 || positionOffset > 0) ? titleOffset : 0;
} else {
x = (tabIndex > 0 || positionOffset > 0) ? -titleOffset : 0;
}
}
int start = Utils.getStart(selectedTab);
int startMargin = Utils.getMarginStart(selectedTab);
if (isLayoutRtl) {
x += start + startMargin - extraOffset - getWidth() + Utils.getPaddingHorizontally(this);
} else {
x += start - startMargin + extraOffset;
}
scrollTo(x, 0);
}
/**
* Interface definition for a callback to be invoked when the scroll position of a view changes.
*/
public interface OnScrollChangeListener {
/**
* Called when the scroll position of a view changes.
*
* @param scrollX Current horizontal scroll origin.
* @param oldScrollX Previous horizontal scroll origin.
*/
void onScrollChanged(int scrollX, int oldScrollX);
}
/**
* Interface definition for a callback to be invoked when a tab is clicked.
*/
public interface OnTabClickListener {
/**
* Called when a tab is clicked.
*
* @param position tab's position
*/
void onTabClicked(int position);
}
/**
* Create the custom tabs in the tab layout. Set with
* {@link #setCustomTabView(com.ogaclejapan.smarttablayout.SmartTabLayout.TabProvider)}
*/
public interface TabProvider {
/**
* @return Return the View of {@code position} for the Tabs
*/
View createTabView(ViewGroup container, int position, PagerAdapter adapter);
}
private static class SimpleTabProvider implements TabProvider {
private final LayoutInflater inflater;
private final int tabViewLayoutId;
private final int tabViewTextViewId;
private SimpleTabProvider(Context context, int layoutResId, int textViewId) {
inflater = LayoutInflater.from(context);
tabViewLayoutId = layoutResId;
tabViewTextViewId = textViewId;
}
@Override
public View createTabView(ViewGroup container, int position, PagerAdapter adapter) {
View tabView = null;
TextView tabTitleView = null;
if (tabViewLayoutId != NO_ID) {
tabView = inflater.inflate(tabViewLayoutId, container, false);
}
if (tabViewTextViewId != NO_ID && tabView != null) {
tabTitleView = (TextView) tabView.findViewById(tabViewTextViewId);
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
if (tabTitleView != null) {
tabTitleView.setText(adapter.getPageTitle(position));
}
return tabView;
}
}
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
private int scrollState;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int tabStripChildCount = tabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
return;
}
tabStrip.onViewPagerPageChanged(position, positionOffset);
scrollToTab(position, positionOffset);
if (viewPagerPageChangeListener != null) {
viewPagerPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageScrollStateChanged(int state) {
scrollState = state;
if (viewPagerPageChangeListener != null) {
viewPagerPageChangeListener.onPageScrollStateChanged(state);
}
}
@Override
public void onPageSelected(int position) {
if (scrollState == ViewPager.SCROLL_STATE_IDLE) {
tabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
for (int i = 0, size = tabStrip.getChildCount(); i < size; i++) {
tabStrip.getChildAt(i).setSelected(position == i);
}
if (viewPagerPageChangeListener != null) {
viewPagerPageChangeListener.onPageSelected(position);
}
}
}
private class InternalTabClickListener implements OnClickListener {
@Override
public void onClick(View v) {
for (int i = 0; i < tabStrip.getChildCount(); i++) {
if (v == tabStrip.getChildAt(i)) {
if (onTabClickListener != null) {
onTabClickListener.onTabClicked(i);
}
viewPager.setCurrentItem(i);
return;
}
}
}
}
}

View File

@@ -0,0 +1,705 @@
/**
* Copyright (C) 2015 ogaclejapan
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.chwl.library.R;
/**
* To be used with ViewPager2 to provide a tab indicator component which give constant feedback as
* to
* the user's scroll progress.
* <p>
* To use the component, simply add it to your view hierarchy. Then in your
* {@link android.app.Activity} or {@link androidx.fragment.app.Fragment} call
* {@link #setViewPager(ViewPager2, RecyclerView.Adapter, TabTitleProvider)} providing it the ViewPager this
* layout
* is being used for.
* <p>
* The colors can be customized in two ways. The first and simplest is to provide an array of
* colors
* via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
* alternative is via the {@link TabColorizer} interface which provides you complete control over
* which color is used for any individual position.
* <p>
* The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
* providing the layout ID of your custom layout.
* <p>
* Forked from Google Samples &gt; SlidingTabsBasic &gt;
* <a href="https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html">SlidingTabLayout</a>
*/
public class SmartTabLayout2 extends HorizontalScrollView {
private static final boolean DEFAULT_DISTRIBUTE_EVENLY = false;
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TITLE_OFFSET_AUTO_CENTER = -1;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final boolean TAB_VIEW_TEXT_ALL_CAPS = true;
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
private static final int TAB_VIEW_TEXT_COLOR = 0xFC000000;
private static final int TAB_VIEW_TEXT_MIN_WIDTH = 0;
private static final boolean TAB_CLICKABLE = true;
private static final int NO_TEXT_STYLE = -1;
protected final SmartTabStrip tabStrip;
private int titleOffset;
private int tabViewBackgroundResId;
private boolean tabViewTextAllCaps;
private ColorStateList tabViewTextColors;
private float tabViewTextSize;
private int tabViewTextHorizontalPadding;
private int tabViewTextMinWidth;
private ViewPager2 viewPager;
private ViewPager2.OnPageChangeCallback viewPagerPageChangeCallback;
@Nullable
private TabTitleProvider tabTitleProvider;
private OnScrollChangeListener onScrollChangeListener;
private TabProvider tabProvider;
private InternalTabClickListener internalTabClickListener;
private InternalTabLongClickListener internalTabLongClickListener;
private OnTabClickListener onTabClickListener;
private OnTabLongClickListener onTabLongClickListener;
private boolean distributeEvenly;
private int textAppearance;
private int childCountCache = 0;
public SmartTabLayout2(Context context) {
this(context, null);
}
public SmartTabLayout2(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SmartTabLayout2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Disable the Scroll Bar
setHorizontalScrollBarEnabled(false);
final DisplayMetrics dm = getResources().getDisplayMetrics();
final float density = dm.density;
int tabBackgroundResId = NO_ID;
boolean textAllCaps = TAB_VIEW_TEXT_ALL_CAPS;
ColorStateList textColors;
float textSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP, dm);
int textHorizontalPadding = (int) (TAB_VIEW_PADDING_DIPS * density);
int textMinWidth = (int) (TAB_VIEW_TEXT_MIN_WIDTH * density);
boolean distributeEvenly = DEFAULT_DISTRIBUTE_EVENLY;
int customTabLayoutId = NO_ID;
int customTabTextViewId = NO_ID;
boolean clickable = TAB_CLICKABLE;
int titleOffset = (int) (TITLE_OFFSET_DIPS * density);
int textStyle = NO_TEXT_STYLE;
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.stl_SmartTabLayout, defStyle, 0);
tabBackgroundResId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_defaultTabBackground, tabBackgroundResId);
textAllCaps = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextAllCaps, textAllCaps);
textColors = a.getColorStateList(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextColor);
textSize = a.getDimension(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextSize, textSize);
textHorizontalPadding = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextHorizontalPadding, textHorizontalPadding);
textMinWidth = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_defaultTabTextMinWidth, textMinWidth);
customTabLayoutId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_customTabTextLayoutId, customTabLayoutId);
customTabTextViewId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_customTabTextViewId, customTabTextViewId);
distributeEvenly = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_distributeEvenly, distributeEvenly);
clickable = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_clickable, clickable);
titleOffset = a.getLayoutDimension(
R.styleable.stl_SmartTabLayout_stl_titleOffset, titleOffset);
textStyle = a.getResourceId(R.styleable.stl_SmartTabLayout_stl_tabTextStyle, textStyle);
a.recycle();
this.titleOffset = titleOffset;
this.tabViewBackgroundResId = tabBackgroundResId;
this.tabViewTextAllCaps = textAllCaps;
this.tabViewTextColors = (textColors != null)
? textColors
: ColorStateList.valueOf(TAB_VIEW_TEXT_COLOR);
this.tabViewTextSize = textSize;
this.tabViewTextHorizontalPadding = textHorizontalPadding;
this.tabViewTextMinWidth = textMinWidth;
this.internalTabClickListener = clickable ? new InternalTabClickListener() : null;
this.internalTabLongClickListener = clickable ? new InternalTabLongClickListener() : null;
this.distributeEvenly = distributeEvenly;
this.textAppearance = textStyle;
if (customTabLayoutId != NO_ID) {
setCustomTabView(customTabLayoutId, customTabTextViewId);
}
this.tabStrip = new SmartTabStrip(context, attrs);
if (distributeEvenly && tabStrip.isIndicatorAlwaysInCenter()) {
throw new UnsupportedOperationException(
"'distributeEvenly' and 'indicatorAlwaysInCenter' both use does not support");
}
// Make sure that the Tab Strips fills this View
setFillViewport(!tabStrip.isIndicatorAlwaysInCenter());
addView(tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (onScrollChangeListener != null) {
onScrollChangeListener.onScrollChanged(l, oldl);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
adjustForIndicatorAlwaysInCenter(w, h);
}
private void adjustForIndicatorAlwaysInCenter(int w, int h) {
if (tabStrip.isIndicatorAlwaysInCenter() && tabStrip.getChildCount() > 0) {
View firstTab = tabStrip.getChildAt(0);
View lastTab = tabStrip.getChildAt(tabStrip.getChildCount() - 1);
int start = (w - Utils.getMeasuredWidth(firstTab)) / 2 - Utils.getMarginStart(firstTab);
int end = (w - Utils.getMeasuredWidth(lastTab)) / 2 - Utils.getMarginEnd(lastTab);
tabStrip.setMinimumWidth(tabStrip.getMeasuredWidth());
ViewCompat.setPaddingRelative(this, start, getPaddingTop(), end, getPaddingBottom());
setClipToPadding(false);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// Ensure first scroll
if (changed && viewPager != null) {
scrollToTab(viewPager.getCurrentItem(), 0);
}
if (childCountCache != tabStrip.getChildCount()) {
adjustForIndicatorAlwaysInCenter(getMeasuredWidth(), getMeasuredHeight());
}
childCountCache = tabStrip.getChildCount();
}
/**
* Set the behavior of the Indicator scrolling feedback.
*
* @param interpolator {@link SmartTabIndicationInterpolator}
*/
public void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) {
tabStrip.setIndicationInterpolator(interpolator);
}
/**
* Set the custom {@link TabColorizer} to be used.
*
* If you only require simple customisation then you can use
* {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
* similar effects.
*/
public void setCustomTabColorizer(TabColorizer tabColorizer) {
tabStrip.setCustomTabColorizer(tabColorizer);
}
/**
* Set the color used for styling the tab text. This will need to be called prior to calling
* {@link #setViewPager(ViewPager2, RecyclerView.Adapter, TabTitleProvider)} otherwise it will not get set
*
* @param color to use for tab text
*/
public void setDefaultTabTextColor(int color) {
tabViewTextColors = ColorStateList.valueOf(color);
}
/**
* Sets the colors used for styling the tab text. This will need to be called prior to calling
* {@link #setViewPager(ViewPager2, RecyclerView.Adapter, TabTitleProvider)} otherwise it will not get set
*
* @param colors ColorStateList to use for tab text
*/
public void setDefaultTabTextColor(ColorStateList colors) {
tabViewTextColors = colors;
}
/**
* Set the same weight for tab
*/
public void setDistributeEvenly(boolean distributeEvenly) {
this.distributeEvenly = distributeEvenly;
}
/**
* Sets the colors to be used for indicating the selected tab. These colors are treated as a
* circular array. Providing one color will mean that all tabs are indicated with the same color.
*/
public void setSelectedIndicatorColors(int... colors) {
tabStrip.setSelectedIndicatorColors(colors);
}
/**
* Sets the colors to be used for tab dividers. These colors are treated as a circular array.
* Providing one color will mean that all tabs are indicated with the same color.
*/
public void setDividerColors(int... colors) {
tabStrip.setDividerColors(colors);
}
/**
* Set the {@link ViewPager2.OnPageChangeCallback}. When using {@link SmartTabLayout2} you are
* required to set any {@link ViewPager2.OnPageChangeCallback} through this method. This is so
* that the layout can update it's scroll position correctly.
*
* @see ViewPager2#registerOnPageChangeCallback(ViewPager2.OnPageChangeCallback)
*/
public void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback listener) {
viewPagerPageChangeCallback = listener;
}
/**
* Set {@link OnScrollChangeListener} for obtaining values of scrolling.
*
* @param listener the {@link OnScrollChangeListener} to set
*/
public void setOnScrollChangeListener(OnScrollChangeListener listener) {
onScrollChangeListener = listener;
}
/**
* Set {@link OnTabClickListener} for obtaining click event.
*
* @param listener the {@link OnTabClickListener} to set
*/
public void setOnTabClickListener(OnTabClickListener listener) {
onTabClickListener = listener;
}
public void setOnTabLongClickListener(OnTabLongClickListener listener) {
onTabLongClickListener = listener;
}
/**
* Set the custom layout to be inflated for the tab views.
*
* @param layoutResId Layout id to be inflated
* @param textViewId id of the {@link TextView} in the inflated view
*/
public void setCustomTabView(int layoutResId, int textViewId) {
tabProvider = new SimpleTabProvider(getContext(), layoutResId, textViewId);
}
/**
* Set the custom layout to be inflated for the tab views.
*
* @param provider {@link TabProvider}
*/
public void setCustomTabView(TabProvider provider) {
tabProvider = provider;
}
/**
* Sets the associated view pager. Note that the assumption here is that the pager content
* (number of tabs and tab titles) does not change after this call has been made.
*/
public void setViewPager(@NonNull ViewPager2 viewPager, @NonNull RecyclerView.Adapter adapter,
@Nullable TabTitleProvider titleProvider) {
tabStrip.removeAllViews();
this.viewPager = viewPager;
if (this.viewPager.getAdapter() != adapter){
this.viewPager.setAdapter(adapter);
}
this.tabTitleProvider = titleProvider;
if (viewPager != null && viewPager.getAdapter() != null) {
viewPager.registerOnPageChangeCallback(new InternalViewPagerListener());
populateTabStrip();
}
}
/**
* Returns the view at the specified position in the tabs.
*
* @param position the position at which to get the view from
* @return the view at the specified position or null if the position does not exist within the
* tabs
*/
public View getTabAt(int position) {
return tabStrip.getChildAt(position);
}
/**
* Create a default view to be used for tabs. This is called if a custom tab view is not set via
* {@link #setCustomTabView(int, int)}.
*/
protected TextView createDefaultTabView(CharSequence title) {
TextView textView = new TextView(getContext());
textView.setGravity(Gravity.CENTER);
textView.setText(title);
if (textAppearance != NO_TEXT_STYLE) {
textView.setTextAppearance(getContext(), textAppearance);
} else {
textView.setTextColor(tabViewTextColors);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabViewTextSize);
textView.setTypeface(Typeface.DEFAULT_BOLD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
textView.setAllCaps(tabViewTextAllCaps);
}
if (tabViewTextMinWidth > 0) {
textView.setMinWidth(tabViewTextMinWidth);
}
}
if (tabViewBackgroundResId != NO_ID) {
textView.setBackgroundResource(tabViewBackgroundResId);
} else {
// If we're running on Honeycomb or newer, then we can use the Theme's
// selectableItemBackground to ensure that the View has a pressed state
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
outValue, true);
textView.setBackgroundResource(outValue.resourceId);
}
textView.setPadding(
tabViewTextHorizontalPadding, 0,
tabViewTextHorizontalPadding, 0);
textView.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
return textView;
}
private void populateTabStrip() {
final RecyclerView.Adapter adapter = viewPager.getAdapter();
for (int i = 0; i < adapter.getItemCount(); i++) {
CharSequence pageTitle = null;
if (tabTitleProvider != null) {
pageTitle = tabTitleProvider.getPageTitle(i);
}
final View tabView = (tabProvider == null)
? createDefaultTabView(pageTitle)
: tabProvider.createTabView(tabStrip, i, pageTitle);
if (tabView == null) {
throw new IllegalStateException("tabView is null.");
}
if (distributeEvenly) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
lp.width = 0;
lp.weight = 1;
}
if (internalTabClickListener != null) {
tabView.setOnClickListener(internalTabClickListener);
}
if (internalTabLongClickListener != null) {
tabView.setOnLongClickListener(internalTabLongClickListener);
}
tabStrip.addView(tabView);
if (i == viewPager.getCurrentItem()) {
tabView.setSelected(true);
}
}
}
private void scrollToTab(int tabIndex, float positionOffset) {
final int tabStripChildCount = tabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
return;
}
final boolean isLayoutRtl = Utils.isLayoutRtl(this);
View selectedTab = tabStrip.getChildAt(tabIndex);
int widthPlusMargin = Utils.getWidth(selectedTab) + Utils.getMarginHorizontally(selectedTab);
int extraOffset = (int) (positionOffset * widthPlusMargin);
if (tabStrip.isIndicatorAlwaysInCenter()) {
if (0f < positionOffset && positionOffset < 1f) {
View nextTab = tabStrip.getChildAt(tabIndex + 1);
int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
}
View firstTab = tabStrip.getChildAt(0);
int x;
if (isLayoutRtl) {
int first = Utils.getWidth(firstTab) + Utils.getMarginEnd(firstTab);
int selected = Utils.getWidth(selectedTab) + Utils.getMarginEnd(selectedTab);
x = Utils.getEnd(selectedTab) - Utils.getMarginEnd(selectedTab) - extraOffset;
x -= (first - selected) / 2;
} else {
int first = Utils.getWidth(firstTab) + Utils.getMarginStart(firstTab);
int selected = Utils.getWidth(selectedTab) + Utils.getMarginStart(selectedTab);
x = Utils.getStart(selectedTab) - Utils.getMarginStart(selectedTab) + extraOffset;
x -= (first - selected) / 2;
}
scrollTo(x, 0);
return;
}
int x;
if (titleOffset == TITLE_OFFSET_AUTO_CENTER) {
if (0f < positionOffset && positionOffset < 1f) {
View nextTab = tabStrip.getChildAt(tabIndex + 1);
int selectHalfWidth = Utils.getWidth(selectedTab) / 2 + Utils.getMarginEnd(selectedTab);
int nextHalfWidth = Utils.getWidth(nextTab) / 2 + Utils.getMarginStart(nextTab);
extraOffset = Math.round(positionOffset * (selectHalfWidth + nextHalfWidth));
}
if (isLayoutRtl) {
x = -Utils.getWidthWithMargin(selectedTab) / 2 + getWidth() / 2;
x -= Utils.getPaddingStart(this);
} else {
x = Utils.getWidthWithMargin(selectedTab) / 2 - getWidth() / 2;
x += Utils.getPaddingStart(this);
}
} else {
if (isLayoutRtl) {
x = (tabIndex > 0 || positionOffset > 0) ? titleOffset : 0;
} else {
x = (tabIndex > 0 || positionOffset > 0) ? -titleOffset : 0;
}
}
int start = Utils.getStart(selectedTab);
int startMargin = Utils.getMarginStart(selectedTab);
if (isLayoutRtl) {
x += start + startMargin - extraOffset - getWidth() + Utils.getPaddingHorizontally(this);
} else {
x += start - startMargin + extraOffset;
}
scrollTo(x, 0);
}
/**
* Interface definition for a callback to be invoked when the scroll position of a view changes.
*/
public interface OnScrollChangeListener {
/**
* Called when the scroll position of a view changes.
*
* @param scrollX Current horizontal scroll origin.
* @param oldScrollX Previous horizontal scroll origin.
*/
void onScrollChanged(int scrollX, int oldScrollX);
}
/**
* Interface definition for a callback to be invoked when a tab is clicked.
*/
public interface OnTabClickListener {
/**
* Called when a tab is clicked.
*
* @param position tab's position
*/
void onTabClicked(int position);
}
/**
* Interface definition for a callback to be invoked when a tab is long clicked.
*/
public interface OnTabLongClickListener {
/**
* Called when a tab is clicked.
*
* @param position tab's position
*/
void onTabLongClicked(int position);
}
/**
* Create the custom tabs in the tab layout. Set with
* {@link #setCustomTabView(TabProvider)}
*/
public interface TabProvider {
/**
* @return Return the View of {@code position} for the Tabs
*/
View createTabView(ViewGroup container, int position, @Nullable CharSequence pageTitle);
}
private static class SimpleTabProvider implements TabProvider {
private final LayoutInflater inflater;
private final int tabViewLayoutId;
private final int tabViewTextViewId;
private SimpleTabProvider(Context context, int layoutResId, int textViewId) {
inflater = LayoutInflater.from(context);
tabViewLayoutId = layoutResId;
tabViewTextViewId = textViewId;
}
@Override
public View createTabView(ViewGroup container, int position, CharSequence pageTitle) {
View tabView = null;
TextView tabTitleView = null;
if (tabViewLayoutId != NO_ID) {
tabView = inflater.inflate(tabViewLayoutId, container, false);
}
if (tabViewTextViewId != NO_ID && tabView != null) {
tabTitleView = (TextView) tabView.findViewById(tabViewTextViewId);
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
if (tabTitleView != null) {
tabTitleView.setText(pageTitle);
}
return tabView;
}
}
private class InternalViewPagerListener extends ViewPager2.OnPageChangeCallback {
private int scrollState;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int tabStripChildCount = tabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
return;
}
tabStrip.onViewPagerPageChanged(position, positionOffset);
scrollToTab(position, positionOffset);
if (viewPagerPageChangeCallback != null) {
viewPagerPageChangeCallback.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageScrollStateChanged(int state) {
scrollState = state;
if (viewPagerPageChangeCallback != null) {
viewPagerPageChangeCallback.onPageScrollStateChanged(state);
}
}
@Override
public void onPageSelected(int position) {
if (scrollState == ViewPager2.SCROLL_STATE_IDLE) {
tabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
for (int i = 0, size = tabStrip.getChildCount(); i < size; i++) {
tabStrip.getChildAt(i).setSelected(position == i);
}
if (viewPagerPageChangeCallback != null) {
viewPagerPageChangeCallback.onPageSelected(position);
}
}
}
private class InternalTabClickListener implements OnClickListener {
@Override
public void onClick(View v) {
for (int i = 0; i < tabStrip.getChildCount(); i++) {
if (v == tabStrip.getChildAt(i)) {
if (onTabClickListener != null) {
onTabClickListener.onTabClicked(i);
}
viewPager.setCurrentItem(i);
return;
}
}
}
}
private class InternalTabLongClickListener implements OnLongClickListener {
@Override
public boolean onLongClick(View v) {
for (int i = 0; i < tabStrip.getChildCount(); i++) {
if (v == tabStrip.getChildAt(i)) {
if (onTabLongClickListener != null) {
onTabLongClickListener.onTabLongClicked(i);
}
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,446 @@
/**
* Copyright (C) 2015 ogaclejapan
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;
import com.chwl.library.R;
/**
* <p>
* Forked from Google Samples &gt; SlidingTabsBasic &gt;
* <a href="https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html">SlidingTabStrip</a>
*/
class SmartTabStrip extends LinearLayout {
private static final int GRAVITY_BOTTOM = 0;
private static final int GRAVITY_TOP = 1;
private static final int GRAVITY_CENTER = 2;
private static final int AUTO_WIDTH = -1;
private static final int DEFAULT_TOP_BORDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_TOP_BORDER_COLOR_ALPHA = 0x26;
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
private static final float DEFAULT_INDICATOR_CORNER_RADIUS = 0f;
private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
private static final boolean DEFAULT_INDICATOR_IN_CENTER = false;
private static final boolean DEFAULT_INDICATOR_IN_FRONT = false;
private static final boolean DEFAULT_INDICATOR_WITHOUT_PADDING = false;
private static final int DEFAULT_INDICATOR_GRAVITY = GRAVITY_BOTTOM;
private static final boolean DEFAULT_DRAW_DECORATION_AFTER_TAB = false;
private final int topBorderThickness;
private final int topBorderColor;
private final int bottomBorderThickness;
private final int bottomBorderColor;
private final Paint borderPaint;
private final RectF indicatorRectF = new RectF();
private final boolean indicatorWithoutPadding;
private final boolean indicatorAlwaysInCenter;
private final boolean indicatorInFront;
private final int indicatorThickness;
private final int indicatorWidth;
private final int indicatorGravity;
private final float indicatorCornerRadius;
private final Paint indicatorPaint;
private final int dividerThickness;
private final Paint dividerPaint;
private final float dividerHeight;
private final SimpleTabColorizer defaultTabColorizer;
private final boolean drawDecorationAfterTab;
private int lastPosition;
private int selectedPosition;
private float selectionOffset;
private SmartTabIndicationInterpolator indicationInterpolator;
private TabColorizer customTabColorizer;
SmartTabStrip(Context context, AttributeSet attrs) {
super(context);
setWillNotDraw(false);
final float density = getResources().getDisplayMetrics().density;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
final int themeForegroundColor = outValue.data;
boolean indicatorWithoutPadding = DEFAULT_INDICATOR_WITHOUT_PADDING;
boolean indicatorInFront = DEFAULT_INDICATOR_IN_FRONT;
boolean indicatorAlwaysInCenter = DEFAULT_INDICATOR_IN_CENTER;
int indicationInterpolatorId = SmartTabIndicationInterpolator.ID_SMART;
int indicatorGravity = DEFAULT_INDICATOR_GRAVITY;
int indicatorColor = DEFAULT_SELECTED_INDICATOR_COLOR;
int indicatorColorsId = NO_ID;
int indicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
int indicatorWidth = AUTO_WIDTH;
float indicatorCornerRadius = DEFAULT_INDICATOR_CORNER_RADIUS * density;
int overlineColor = setColorAlpha(themeForegroundColor, DEFAULT_TOP_BORDER_COLOR_ALPHA);
int overlineThickness = (int) (DEFAULT_TOP_BORDER_THICKNESS_DIPS * density);
int underlineColor = setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
int underlineThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
int dividerColor = setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA);
int dividerColorsId = NO_ID;
int dividerThickness = (int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density);
boolean drawDecorationAfterTab = DEFAULT_DRAW_DECORATION_AFTER_TAB;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.stl_SmartTabLayout);
indicatorAlwaysInCenter = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_indicatorAlwaysInCenter, indicatorAlwaysInCenter);
indicatorWithoutPadding = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_indicatorWithoutPadding, indicatorWithoutPadding);
indicatorInFront = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_indicatorInFront, indicatorInFront);
indicationInterpolatorId = a.getInt(
R.styleable.stl_SmartTabLayout_stl_indicatorInterpolation, indicationInterpolatorId);
indicatorGravity = a.getInt(
R.styleable.stl_SmartTabLayout_stl_indicatorGravity, indicatorGravity);
indicatorColor = a.getColor(
R.styleable.stl_SmartTabLayout_stl_indicatorColor, indicatorColor);
indicatorColorsId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_indicatorColors, indicatorColorsId);
indicatorThickness = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_indicatorThickness, indicatorThickness);
indicatorWidth = a.getLayoutDimension(
R.styleable.stl_SmartTabLayout_stl_indicatorWidth, indicatorWidth);
indicatorCornerRadius = a.getDimension(
R.styleable.stl_SmartTabLayout_stl_indicatorCornerRadius, indicatorCornerRadius);
overlineColor = a.getColor(
R.styleable.stl_SmartTabLayout_stl_overlineColor, overlineColor);
overlineThickness = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_overlineThickness, overlineThickness);
underlineColor = a.getColor(
R.styleable.stl_SmartTabLayout_stl_underlineColor, underlineColor);
underlineThickness = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_underlineThickness, underlineThickness);
dividerColor = a.getColor(
R.styleable.stl_SmartTabLayout_stl_dividerColor, dividerColor);
dividerColorsId = a.getResourceId(
R.styleable.stl_SmartTabLayout_stl_dividerColors, dividerColorsId);
dividerThickness = a.getDimensionPixelSize(
R.styleable.stl_SmartTabLayout_stl_dividerThickness, dividerThickness);
drawDecorationAfterTab = a.getBoolean(
R.styleable.stl_SmartTabLayout_stl_drawDecorationAfterTab, drawDecorationAfterTab);
a.recycle();
final int[] indicatorColors = (indicatorColorsId == NO_ID)
? new int[] { indicatorColor }
: getResources().getIntArray(indicatorColorsId);
final int[] dividerColors = (dividerColorsId == NO_ID)
? new int[] { dividerColor }
: getResources().getIntArray(dividerColorsId);
this.defaultTabColorizer = new SimpleTabColorizer();
this.defaultTabColorizer.setIndicatorColors(indicatorColors);
this.defaultTabColorizer.setDividerColors(dividerColors);
this.topBorderThickness = overlineThickness;
this.topBorderColor = overlineColor;
this.bottomBorderThickness = underlineThickness;
this.bottomBorderColor = underlineColor;
this.borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.indicatorAlwaysInCenter = indicatorAlwaysInCenter;
this.indicatorWithoutPadding = indicatorWithoutPadding;
this.indicatorInFront = indicatorInFront;
this.indicatorThickness = indicatorThickness;
this.indicatorWidth = indicatorWidth;
this.indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.indicatorCornerRadius = indicatorCornerRadius;
this.indicatorGravity = indicatorGravity;
this.dividerHeight = DEFAULT_DIVIDER_HEIGHT;
this.dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.dividerPaint.setStrokeWidth(dividerThickness);
this.dividerThickness = dividerThickness;
this.drawDecorationAfterTab = drawDecorationAfterTab;
this.indicationInterpolator = SmartTabIndicationInterpolator.of(indicationInterpolatorId);
}
/**
* Set the alpha value of the {@code color} to be the given {@code alpha} value.
*/
private static int setColorAlpha(int color, byte alpha) {
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
}
/**
* Blend {@code color1} and {@code color2} using the given ratio.
*
* @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
* 0.0 will return {@code color2}.
*/
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRation = 1f - ratio;
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
return Color.rgb((int) r, (int) g, (int) b);
}
void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) {
indicationInterpolator = interpolator;
invalidate();
}
void setCustomTabColorizer(TabColorizer customTabColorizer) {
this.customTabColorizer = customTabColorizer;
invalidate();
}
void setSelectedIndicatorColors(int... colors) {
// Make sure that the custom colorizer is removed
customTabColorizer = null;
defaultTabColorizer.setIndicatorColors(colors);
invalidate();
}
void setDividerColors(int... colors) {
// Make sure that the custom colorizer is removed
customTabColorizer = null;
defaultTabColorizer.setDividerColors(colors);
invalidate();
}
void onViewPagerPageChanged(int position, float positionOffset) {
selectedPosition = position;
selectionOffset = positionOffset;
if (positionOffset == 0f && lastPosition != selectedPosition) {
lastPosition = selectedPosition;
}
invalidate();
}
boolean isIndicatorAlwaysInCenter() {
return indicatorAlwaysInCenter;
}
TabColorizer getTabColorizer() {
return (customTabColorizer != null) ? customTabColorizer : defaultTabColorizer;
}
@Override
protected void onDraw(Canvas canvas) {
if (!drawDecorationAfterTab) {
drawDecoration(canvas);
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (drawDecorationAfterTab) {
drawDecoration(canvas);
}
}
private void drawDecoration(Canvas canvas) {
final int height = getHeight();
final int width = getWidth();
final int tabCount = getChildCount();
final TabColorizer tabColorizer = getTabColorizer();
final boolean isLayoutRtl = Utils.isLayoutRtl(this);
if (indicatorInFront) {
drawOverline(canvas, 0, width);
drawUnderline(canvas, 0, width, height);
}
// Thick colored underline below the current selection
if (tabCount > 0) {
View selectedTab = getChildAt(selectedPosition);
int selectedStart = Utils.getStart(selectedTab, indicatorWithoutPadding);
int selectedEnd = Utils.getEnd(selectedTab, indicatorWithoutPadding);
int left;
int right;
if (isLayoutRtl) {
left = selectedEnd;
right = selectedStart;
} else {
left = selectedStart;
right = selectedEnd;
}
int color = tabColorizer.getIndicatorColor(selectedPosition);
float thickness = indicatorThickness;
if (selectionOffset > 0f && selectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(selectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, selectionOffset);
}
// Draw the selection partway between the tabs
float startOffset = indicationInterpolator.getLeftEdge(selectionOffset);
float endOffset = indicationInterpolator.getRightEdge(selectionOffset);
float thicknessOffset = indicationInterpolator.getThickness(selectionOffset);
View nextTab = getChildAt(selectedPosition + 1);
int nextStart = Utils.getStart(nextTab, indicatorWithoutPadding);
int nextEnd = Utils.getEnd(nextTab, indicatorWithoutPadding);
if (isLayoutRtl) {
left = (int) (endOffset * nextEnd + (1.0f - endOffset) * left);
right = (int) (startOffset * nextStart + (1.0f - startOffset) * right);
} else {
left = (int) (startOffset * nextStart + (1.0f - startOffset) * left);
right = (int) (endOffset * nextEnd + (1.0f - endOffset) * right);
}
thickness = thickness * thicknessOffset;
}
drawIndicator(canvas, left, right, height, thickness, color);
}
if (!indicatorInFront) {
drawOverline(canvas, 0, width);
drawUnderline(canvas, 0, getWidth(), height);
}
// Vertical separators between the titles
drawSeparator(canvas, height, tabCount);
}
private void drawSeparator(Canvas canvas, int height, int tabCount) {
if (dividerThickness <= 0) {
return;
}
final int dividerHeightPx = (int) (Math.min(Math.max(0f, dividerHeight), 1f) * height);
final TabColorizer tabColorizer = getTabColorizer();
// Vertical separators between the titles
final int separatorTop = (height - dividerHeightPx) / 2;
final int separatorBottom = separatorTop + dividerHeightPx;
final boolean isLayoutRtl = Utils.isLayoutRtl(this);
for (int i = 0; i < tabCount - 1; i++) {
View child = getChildAt(i);
int end = Utils.getEnd(child);
int endMargin = Utils.getMarginEnd(child);
int separatorX = isLayoutRtl ? end - endMargin : end + endMargin;
dividerPaint.setColor(tabColorizer.getDividerColor(i));
canvas.drawLine(separatorX, separatorTop, separatorX, separatorBottom, dividerPaint);
}
}
private void drawIndicator(Canvas canvas, int left, int right, int height, float thickness,
int color) {
if (indicatorThickness <= 0 || indicatorWidth == 0) {
return;
}
float center;
float top;
float bottom;
switch (indicatorGravity) {
case GRAVITY_TOP:
center = indicatorThickness / 2f;
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
break;
case GRAVITY_CENTER:
center = height / 2f;
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
break;
case GRAVITY_BOTTOM:
default:
center = height - (indicatorThickness / 2f);
top = center - (thickness / 2f);
bottom = center + (thickness / 2f);
}
indicatorPaint.setColor(color);
if (indicatorWidth == AUTO_WIDTH) {
indicatorRectF.set(left, top, right, bottom);
} else {
float padding = (Math.abs(left - right) - indicatorWidth) / 2f;
indicatorRectF.set(left + padding, top, right - padding, bottom);
}
if (indicatorCornerRadius > 0f) {
canvas.drawRoundRect(
indicatorRectF, indicatorCornerRadius,
indicatorCornerRadius, indicatorPaint);
} else {
canvas.drawRect(indicatorRectF, indicatorPaint);
}
}
private void drawOverline(Canvas canvas, int left, int right) {
if (topBorderThickness <= 0) {
return;
}
// Thin overline along the entire top edge
borderPaint.setColor(topBorderColor);
canvas.drawRect(left, 0, right, topBorderThickness, borderPaint);
}
private void drawUnderline(Canvas canvas, int left, int right, int height) {
if (bottomBorderThickness <= 0) {
return;
}
// Thin underline along the entire bottom edge
borderPaint.setColor(bottomBorderColor);
canvas.drawRect(left, height - bottomBorderThickness, right, height, borderPaint);
}
private static class SimpleTabColorizer implements TabColorizer {
private int[] indicatorColors;
private int[] dividerColors;
@Override
public final int getIndicatorColor(int position) {
return indicatorColors[position % indicatorColors.length];
}
@Override
public final int getDividerColor(int position) {
return dividerColors[position % dividerColors.length];
}
void setIndicatorColors(int... colors) {
indicatorColors = colors;
}
void setDividerColors(int... colors) {
dividerColors = colors;
}
}
}

View File

@@ -0,0 +1,19 @@
package com.chwl.library.widget.tab;
/**
* Allows complete control over the colors drawn in the tab layout. Set with
* {@link SmartTabLayout#setCustomTabColorizer(TabColorizer)}.
*/
public interface TabColorizer {
/**
* @return return the color of the indicator used when {@code position} is selected.
*/
int getIndicatorColor(int position);
/**
* @return return the color of the divider drawn to the right of {@code position}.
*/
int getDividerColor(int position);
}

View File

@@ -0,0 +1,8 @@
package com.chwl.library.widget.tab;
import androidx.annotation.Nullable;
public interface TabTitleProvider {
@Nullable
CharSequence getPageTitle(int position);
}

View File

@@ -0,0 +1,120 @@
/**
* Copyright (C) 2015 ogaclejapan
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.view.MarginLayoutParamsCompat;
import androidx.core.view.ViewCompat;
final class Utils {
private Utils() { }
static int getMeasuredWidth(View v) {
return (v == null) ? 0 : v.getMeasuredWidth();
}
static int getWidth(View v) {
return (v == null) ? 0 : v.getWidth();
}
static int getWidthWithMargin(View v) {
return getWidth(v) + getMarginHorizontally(v);
}
static int getStart(View v) {
return getStart(v, false);
}
static int getStart(View v, boolean withoutPadding) {
if (v == null) {
return 0;
}
if (isLayoutRtl(v)) {
return (withoutPadding) ? v.getRight() - getPaddingStart(v) : v.getRight();
} else {
return (withoutPadding) ? v.getLeft() + getPaddingStart(v) : v.getLeft();
}
}
static int getEnd(View v) {
return getEnd(v, false);
}
static int getEnd(View v, boolean withoutPadding) {
if (v == null) {
return 0;
}
if (isLayoutRtl(v)) {
return (withoutPadding) ? v.getLeft() + getPaddingEnd(v) : v.getLeft();
} else {
return (withoutPadding) ? v.getRight() - getPaddingEnd(v) : v.getRight();
}
}
static int getPaddingStart(View v) {
if (v == null) {
return 0;
}
return ViewCompat.getPaddingStart(v);
}
static int getPaddingEnd(View v) {
if (v == null) {
return 0;
}
return ViewCompat.getPaddingEnd(v);
}
static int getPaddingHorizontally(View v) {
if (v == null) {
return 0;
}
return v.getPaddingLeft() + v.getPaddingRight();
}
static int getMarginStart(View v) {
if (v == null) {
return 0;
}
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
return MarginLayoutParamsCompat.getMarginStart(lp);
}
static int getMarginEnd(View v) {
if (v == null) {
return 0;
}
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
return MarginLayoutParamsCompat.getMarginEnd(lp);
}
static int getMarginHorizontally(View v) {
if (v == null) {
return 0;
}
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
return MarginLayoutParamsCompat.getMarginStart(lp) + MarginLayoutParamsCompat.getMarginEnd(lp);
}
static boolean isLayoutRtl(View v) {
return ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_RTL;
}
}

View File

@@ -0,0 +1,19 @@
package com.chwl.library.widget.tab.util
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
class FragmentPageAdapter(fragmentManager: FragmentActivity, var fgList: List<Fragment>?) :
FragmentStateAdapter(fragmentManager) {
override fun getItemCount(): Int {
return fgList?.size?:0
}
override fun createFragment(position: Int): Fragment {
return fgList?.get(position) ?: Fragment()
}
}

View File

@@ -0,0 +1,38 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util;
public abstract class PagerItem {
protected static final float DEFAULT_WIDTH = 1.f;
private final CharSequence title;
private final float width;
protected PagerItem(CharSequence title, float width) {
this.title = title;
this.width = width;
}
public CharSequence getTitle() {
return title;
}
public float getWidth() {
return width;
}
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util;
import android.content.Context;
import java.util.ArrayList;
public abstract class PagerItems<T extends PagerItem> extends ArrayList<T> {
private final Context context;
protected PagerItems(Context context) {
this.context = context;
}
public Context getContext() {
return context;
}
}

View File

@@ -0,0 +1,45 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
public class ViewPagerItem extends PagerItem {
private final int resource;
protected ViewPagerItem(CharSequence title, float width, @LayoutRes int resource) {
super(title, width);
this.resource = resource;
}
public static ViewPagerItem of(CharSequence title, @LayoutRes int resource) {
return of(title, DEFAULT_WIDTH, resource);
}
public static ViewPagerItem of(CharSequence title, float width, @LayoutRes int resource) {
return new ViewPagerItem(title, width, resource);
}
public View initiate(LayoutInflater inflater, ViewGroup container) {
return inflater.inflate(resource, container, false);
}
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.collection.SparseArrayCompat;
import androidx.viewpager.widget.PagerAdapter;
import java.lang.ref.WeakReference;
public class ViewPagerItemAdapter extends PagerAdapter {
private final ViewPagerItems pages;
private final SparseArrayCompat<WeakReference<View>> holder;
private final LayoutInflater inflater;
public ViewPagerItemAdapter(ViewPagerItems pages) {
this.pages = pages;
this.holder = new SparseArrayCompat<>(pages.size());
this.inflater = LayoutInflater.from(pages.getContext());
}
@Override
public int getCount() {
return pages.size();
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View view = getPagerItem(position).initiate(inflater, container);
container.addView(view);
holder.put(position, new WeakReference<View>(view));
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
holder.remove(position);
container.removeView((View) object);
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return object == view;
}
@Override
public CharSequence getPageTitle(int position) {
return getPagerItem(position).getTitle();
}
@Override
public float getPageWidth(int position) {
return getPagerItem(position).getWidth();
}
public View getPage(int position) {
final WeakReference<View> weakRefItem = holder.get(position);
return (weakRefItem != null) ? weakRefItem.get() : null;
}
protected ViewPagerItem getPagerItem(int position) {
return pages.get(position);
}
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util;
import android.content.Context;
import androidx.annotation.LayoutRes;
import androidx.annotation.StringRes;
public class ViewPagerItems extends PagerItems<ViewPagerItem> {
public ViewPagerItems(Context context) {
super(context);
}
public static Creator with(Context context) {
return new Creator(context);
}
public static class Creator {
private final ViewPagerItems items;
public Creator(Context context) {
items = new ViewPagerItems(context);
}
public Creator add(@StringRes int title, @LayoutRes int resource) {
return add(ViewPagerItem.of(items.getContext().getString(title), resource));
}
public Creator add(@StringRes int title, float width, @LayoutRes int resource) {
return add(ViewPagerItem.of(items.getContext().getString(title), width, resource));
}
public Creator add(CharSequence title, @LayoutRes int resource) {
return add(ViewPagerItem.of(title, resource));
}
public Creator add(ViewPagerItem item) {
items.add(item);
return this;
}
public ViewPagerItems create() {
return items;
}
}
}

View File

@@ -0,0 +1,520 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util.v4;
import android.annotation.TargetApi;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.util.Size;
import android.util.SizeF;
import android.util.SparseArray;
import androidx.fragment.app.Fragment;
import java.io.Serializable;
import java.util.ArrayList;
public class Bundler {
private final Bundle bundle;
/**
* Constructs a new, empty Bundle.
*/
public Bundler() {
this(null);
}
private Bundler(Bundle b) {
bundle = (b == null) ? new Bundle() : new Bundle(b);
}
/**
* Constructs a Bundle containing a copy of the mappings from the given
* Bundle.
*
* @param b a Bundle to be copied.
*/
public static Bundler of(Bundle b) {
return new Bundler(b);
}
/**
* Inserts all mappings from the given Bundle into this Bundle.
*
* @param bundle a Bundle
* @return this
*/
public Bundler putAll(Bundle bundle) {
this.bundle.putAll(bundle);
return this;
}
/**
* Inserts a byte value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value a byte
* @return this
*/
public Bundler putByte(String key, byte value) {
bundle.putByte(key, value);
return this;
}
/**
* Inserts a char value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value a char, or null
* @return this
*/
public Bundler putChar(String key, char value) {
bundle.putChar(key, value);
return this;
}
/**
* Inserts a short value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value a short
* @return this
*/
public Bundler putShort(String key, short value) {
bundle.putShort(key, value);
return this;
}
/**
* Inserts a float value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value a float
* @return this
*/
public Bundler putFloat(String key, float value) {
bundle.putFloat(key, value);
return this;
}
/**
* Inserts a CharSequence value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a CharSequence, or null
* @return this
*/
public Bundler putCharSequence(String key, CharSequence value) {
bundle.putCharSequence(key, value);
return this;
}
/**
* Inserts a Parcelable value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a Parcelable object, or null
* @return this
*/
public Bundler putParcelable(String key, Parcelable value) {
bundle.putParcelable(key, value);
return this;
}
/**
* Inserts a Size value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a Size object, or null
* @return this
*/
@TargetApi(21)
public Bundler putSize(String key, Size value) {
bundle.putSize(key, value);
return this;
}
/**
* Inserts a SizeF value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a SizeF object, or null
* @return this
*/
@TargetApi(21)
public Bundler putSizeF(String key, SizeF value) {
bundle.putSizeF(key, value);
return this;
}
/**
* Inserts an array of Parcelable values into the mapping of this Bundle,
* replacing any existing value for the given key. Either key or value may
* be null.
*
* @param key a String, or null
* @param value an array of Parcelable objects, or null
* @return this
*/
public Bundler putParcelableArray(String key, Parcelable[] value) {
bundle.putParcelableArray(key, value);
return this;
}
/**
* Inserts a List of Parcelable values into the mapping of this Bundle,
* replacing any existing value for the given key. Either key or value may
* be null.
*
* @param key a String, or null
* @param value an ArrayList of Parcelable objects, or null
* @return this
*/
public Bundler putParcelableArrayList(String key,
ArrayList<? extends Parcelable> value) {
bundle.putParcelableArrayList(key, value);
return this;
}
/**
* Inserts a SparceArray of Parcelable values into the mapping of this
* Bundle, replacing any existing value for the given key. Either key
* or value may be null.
*
* @param key a String, or null
* @param value a SparseArray of Parcelable objects, or null
* @return this
*/
public Bundler putSparseParcelableArray(String key,
SparseArray<? extends Parcelable> value) {
bundle.putSparseParcelableArray(key, value);
return this;
}
/**
* Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value an ArrayList<Integer> object, or null
* @return this
*/
public Bundler putIntegerArrayList(String key, ArrayList<Integer> value) {
bundle.putIntegerArrayList(key, value);
return this;
}
/**
* Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value an ArrayList<String> object, or null
* @return this
*/
public Bundler putStringArrayList(String key, ArrayList<String> value) {
bundle.putStringArrayList(key, value);
return this;
}
/**
* Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value an ArrayList<CharSequence> object, or null
* @return this
*/
@TargetApi(8)
public Bundler putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
bundle.putCharSequenceArrayList(key, value);
return this;
}
/**
* Inserts a Serializable value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a Serializable object, or null
* @return this
*/
public Bundler putSerializable(String key, Serializable value) {
bundle.putSerializable(key, value);
return this;
}
/**
* Inserts a byte array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a byte array object, or null
* @return this
*/
public Bundler putByteArray(String key, byte[] value) {
bundle.putByteArray(key, value);
return this;
}
/**
* Inserts a short array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a short array object, or null
* @return this
*/
public Bundler putShortArray(String key, short[] value) {
bundle.putShortArray(key, value);
return this;
}
/**
* Inserts a char array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a char array object, or null
* @return this
*/
public Bundler putCharArray(String key, char[] value) {
bundle.putCharArray(key, value);
return this;
}
/**
* Inserts a float array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a float array object, or null
* @return this
*/
public Bundler putFloatArray(String key, float[] value) {
bundle.putFloatArray(key, value);
return this;
}
/**
* Inserts a CharSequence array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a CharSequence array object, or null
* @return this
*/
@TargetApi(8)
public Bundler putCharSequenceArray(String key, CharSequence[] value) {
bundle.putCharSequenceArray(key, value);
return this;
}
/**
* Inserts a Bundle value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a Bundle object, or null
* @return this
*/
public Bundler putBundle(String key, Bundle value) {
bundle.putBundle(key, value);
return this;
}
/**
* Inserts an {@link IBinder} value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* <p class="note">You should be very careful when using this function. In many
* places where Bundles are used (such as inside of Intent objects), the Bundle
* can live longer inside of another process than the process that had originally
* created it. In that case, the IBinder you supply here will become invalid
* when your process goes away, and no longer usable, even if a new process is
* created for you later on.</p>
*
* @param key a String, or null
* @param value an IBinder object, or null
* @return this
*/
@TargetApi(18)
public Bundler putBinder(String key, IBinder value) {
bundle.putBinder(key, value);
return this;
}
/**
* Inserts a Boolean value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a Boolean, or null
* @return this
*/
public Bundler putBoolean(String key, boolean value) {
bundle.putBoolean(key, value);
return this;
}
/**
* Inserts an int value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value an int, or null
* @return this
*/
public Bundler putInt(String key, int value) {
bundle.putInt(key, value);
return this;
}
/**
* Inserts a long value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value a long
* @return this
*/
public Bundler putLong(String key, long value) {
bundle.putLong(key, value);
return this;
}
/**
* Inserts a double value into the mapping of this Bundle, replacing
* any existing value for the given key.
*
* @param key a String, or null
* @param value a double
* @return this
*/
public Bundler putDouble(String key, double value) {
bundle.putDouble(key, value);
return this;
}
/**
* Inserts a String value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a String, or null
* @return this
*/
public Bundler putString(String key, String value) {
bundle.putString(key, value);
return this;
}
/**
* Inserts a boolean array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a boolean array object, or null
* @return this
*/
public Bundler putBooleanArray(String key, boolean[] value) {
bundle.putBooleanArray(key, value);
return this;
}
/**
* Inserts an int array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value an int array object, or null
* @return this
*/
public Bundler putIntArray(String key, int[] value) {
bundle.putIntArray(key, value);
return this;
}
/**
* Inserts a long array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a long array object, or null
* @return this
*/
public Bundler putLongArray(String key, long[] value) {
bundle.putLongArray(key, value);
return this;
}
/**
* Inserts a double array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a double array object, or null
* @return this
*/
public Bundler putDoubleArray(String key, double[] value) {
bundle.putDoubleArray(key, value);
return this;
}
/**
* Inserts a String array value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
* @param key a String, or null
* @param value a String array object, or null
* @return this
*/
public Bundler putStringArray(String key, String[] value) {
bundle.putStringArray(key, value);
return this;
}
/**
* Get the bundle.
*
* @return a bundle
*/
public Bundle get() {
return bundle;
}
/**
* Set the argument of Fragment.
*
* @param fragment a fragment
* @return a fragment
*/
public <T extends Fragment> T into(T fragment) {
fragment.setArguments(get());
return fragment;
}
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util.v4;
import android.content.Context;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.chwl.library.widget.tab.util.PagerItem;
public class FragmentPagerItem extends PagerItem {
private static final String TAG = "FragmentPagerItem";
private static final String KEY_POSITION = TAG + ":Position";
private final String className;
private final Bundle args;
protected FragmentPagerItem(CharSequence title, float width, String className, Bundle args) {
super(title, width);
this.className = className;
this.args = args;
}
public static FragmentPagerItem of(CharSequence title, Class<? extends Fragment> clazz) {
return of(title, DEFAULT_WIDTH, clazz);
}
public static FragmentPagerItem of(CharSequence title, Class<? extends Fragment> clazz,
Bundle args) {
return of(title, DEFAULT_WIDTH, clazz, args);
}
public static FragmentPagerItem of(CharSequence title, float width,
Class<? extends Fragment> clazz) {
return of(title, width, clazz, new Bundle());
}
public static FragmentPagerItem of(CharSequence title, float width,
Class<? extends Fragment> clazz, Bundle args) {
return new FragmentPagerItem(title, width, clazz.getName(), args);
}
public static boolean hasPosition(Bundle args) {
return args != null && args.containsKey(KEY_POSITION);
}
public static int getPosition(Bundle args) {
return (hasPosition(args)) ? args.getInt(KEY_POSITION) : 0;
}
static void setPosition(Bundle args, int position) {
args.putInt(KEY_POSITION, position);
}
public Fragment instantiate(Context context, int position) {
setPosition(args, position);
return Fragment.instantiate(context, className, args);
}
}

View File

@@ -0,0 +1,84 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util.v4;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.collection.SparseArrayCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.lang.ref.WeakReference;
public class FragmentPagerItemAdapter extends FragmentPagerAdapter {
private final FragmentPagerItems pages;
private final SparseArrayCompat<WeakReference<Fragment>> holder;
public FragmentPagerItemAdapter(FragmentManager fm, FragmentPagerItems pages) {
super(fm);
this.pages = pages;
this.holder = new SparseArrayCompat<>(pages.size());
}
@Override
public int getCount() {
return pages.size();
}
@Override
public Fragment getItem(int position) {
return getPagerItem(position).instantiate(pages.getContext(), position);
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Object item = super.instantiateItem(container, position);
if (item instanceof Fragment) {
holder.put(position, new WeakReference<Fragment>((Fragment) item));
}
return item;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
holder.remove(position);
super.destroyItem(container, position, object);
}
@Override
public CharSequence getPageTitle(int position) {
return getPagerItem(position).getTitle();
}
@Override
public float getPageWidth(int position) {
return super.getPageWidth(position);
}
public Fragment getPage(int position) {
final WeakReference<Fragment> weakRefItem = holder.get(position);
return (weakRefItem != null) ? weakRefItem.get() : null;
}
protected FragmentPagerItem getPagerItem(int position) {
return pages.get(position);
}
}

View File

@@ -0,0 +1,81 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util.v4;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import com.chwl.library.widget.tab.util.PagerItems;
public class FragmentPagerItems extends PagerItems<FragmentPagerItem> {
public FragmentPagerItems(Context context) {
super(context);
}
public static Creator with(Context context) {
return new Creator(context);
}
public static class Creator {
private final FragmentPagerItems items;
public Creator(Context context) {
items = new FragmentPagerItems(context);
}
public Creator add(@StringRes int title, Class<? extends Fragment> clazz) {
return add(FragmentPagerItem.of(items.getContext().getString(title), clazz));
}
public Creator add(@StringRes int title, Class<? extends Fragment> clazz, Bundle args) {
return add(FragmentPagerItem.of(items.getContext().getString(title), clazz, args));
}
public Creator add(@StringRes int title, float width, Class<? extends Fragment> clazz) {
return add(FragmentPagerItem.of(items.getContext().getString(title), width, clazz));
}
public Creator add(@StringRes int title, float width, Class<? extends Fragment> clazz,
Bundle args) {
return add(FragmentPagerItem.of(items.getContext().getString(title), width, clazz, args));
}
public Creator add(CharSequence title, Class<? extends Fragment> clazz) {
return add(FragmentPagerItem.of(title, clazz));
}
public Creator add(CharSequence title, Class<? extends Fragment> clazz, Bundle args) {
return add(FragmentPagerItem.of(title, clazz, args));
}
public Creator add(FragmentPagerItem item) {
items.add(item);
return this;
}
public FragmentPagerItems create() {
return items;
}
}
}

View File

@@ -0,0 +1,84 @@
/**
* Copyright (C) 2015 ogaclejapan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chwl.library.widget.tab.util.v4;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.collection.SparseArrayCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import java.lang.ref.WeakReference;
public class FragmentStatePagerItemAdapter extends FragmentStatePagerAdapter {
private final FragmentPagerItems pages;
private final SparseArrayCompat<WeakReference<Fragment>> holder;
public FragmentStatePagerItemAdapter(FragmentManager fm, FragmentPagerItems pages) {
super(fm);
this.pages = pages;
this.holder = new SparseArrayCompat<>(pages.size());
}
@Override
public int getCount() {
return pages.size();
}
@Override
public Fragment getItem(int position) {
return getPagerItem(position).instantiate(pages.getContext(), position);
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Object item = super.instantiateItem(container, position);
if (item instanceof Fragment) {
holder.put(position, new WeakReference<Fragment>((Fragment) item));
}
return item;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
holder.remove(position);
super.destroyItem(container, position, object);
}
@Override
public CharSequence getPageTitle(int position) {
return getPagerItem(position).getTitle();
}
@Override
public float getPageWidth(int position) {
return getPagerItem(position).getWidth();
}
public Fragment getPage(int position) {
final WeakReference<Fragment> weakRefItem = holder.get(position);
return (weakRefItem != null) ? weakRefItem.get() : null;
}
protected FragmentPagerItem getPagerItem(int position) {
return pages.get(position);
}
}

View File

@@ -120,7 +120,7 @@ public class DrawableTextView extends AppCompatTextView {
strikeColor = a.getColor(R.styleable.DrawableTextView_dt_strikeColor, -1);
strikeWidth = a.getDimensionPixelSize(R.styleable.DrawableTextView_dt_strikeWidth, 0);
//填充颜色
soildColor = a.getColor(R.styleable.DrawableTextView_dt_soildColor, 0xffffffff);
soildColor = a.getColor(R.styleable.DrawableTextView_dt_soildColor, 0x00000000);
//渐变相关
angle = a.getInt(R.styleable.DrawableTextView_dt_angle, 0);
startColor = a.getColor(R.styleable.DrawableTextView_dt_startColor, -1);

View File

@@ -191,4 +191,64 @@
<attr name="dt_lineColor" format="color" />
</declare-styleable>
<declare-styleable name="stl_SmartTabLayout">
<!-- 设置为true时与权重互斥, 不能都设置为true-->
<attr name="stl_indicatorAlwaysInCenter" format="boolean"/>
<attr name="stl_indicatorWithoutPadding" format="boolean"/>
<attr name="stl_indicatorInFront" format="boolean"/>
<attr name="stl_indicatorInterpolation" format="enum">
<enum name="smart" value="0"/>
<enum name="linear" value="1"/>
</attr>
<attr name="stl_indicatorGravity" format="enum">
<enum name="bottom" value="0"/>
<enum name="top" value="1"/>
<enum name="center" value="2"/>
</attr>
<attr name="stl_indicatorColor" format="color"/>
<attr name="stl_indicatorColors" format="reference"/>
<!-- 指示器高-->
<attr name="stl_indicatorThickness" format="dimension"/>
<!-- 指示器宽-->
<attr name="stl_indicatorWidth" format="dimension">
<enum name="auto" value="-1"/>
</attr>
<attr name="stl_indicatorCornerRadius" format="dimension"/>
<attr name="stl_overlineColor" format="color"/>
<attr name="stl_overlineThickness" format="dimension"/>
<attr name="stl_underlineColor" format="color"/>
<attr name="stl_underlineThickness" format="dimension"/>
<attr name="stl_dividerColor" format="color"/>
<attr name="stl_dividerColors" format="reference"/>
<attr name="stl_dividerThickness" format="dimension"/>
<attr name="stl_defaultTabBackground" format="reference"/>
<attr name="stl_defaultTabTextAllCaps" format="boolean"/>
<attr name="stl_defaultTabTextColor" format="color|reference"/>
<attr name="stl_defaultTabTextSize" format="dimension"/>
<attr name="stl_defaultTabTextHorizontalPadding" format="dimension"/>
<attr name="stl_defaultTabTextMinWidth" format="dimension"/>
<!-- 自定义布局-->
<attr name="stl_customTabTextLayoutId" format="reference"/>
<attr name="stl_customTabTextViewId" format="reference"/>
<!-- 权重-->
<attr name="stl_distributeEvenly" format="boolean"/>
<attr name="stl_clickable" format="boolean"/>
<attr name="stl_titleOffset" format="dimension">
<enum name="auto_center" value="-1"/>
</attr>
<attr name="stl_drawDecorationAfterTab" format="boolean"/>
<attr name="stl_tabTextStyle" format="reference" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,434 @@
//package com.kelly.dawi.util
//
//import android.graphics.Bitmap
//import android.graphics.Paint
//import android.os.Looper
//import android.text.TextPaint
//import android.view.View
//import android.widget.ImageView
//import androidx.annotation.DrawableRes
//import androidx.lifecycle.findViewTreeLifecycleOwner
//import androidx.lifecycle.lifecycleScope
//import com.bumptech.glide.Glide
//import com.bumptech.glide.load.DataSource
//import com.bumptech.glide.load.engine.GlideException
//import com.bumptech.glide.request.FutureTarget
//import com.bumptech.glide.request.RequestFutureTarget
//import com.bumptech.glide.request.RequestListener
//import com.bumptech.glide.request.RequestOptions
//import com.bumptech.glide.request.target.Target
//import com.kelly.dawi.dp
//import com.kelly.dawi.getOrNull
//import com.kelly.dawi.simpleImpl.SimpleSvgaCallback
//import com.kelly.dawi.suspendGetOrNull
//import com.opensource.svgaplayer.SVGAImageView
//import com.opensource.svgaplayer.glideplugin.asSVGADrawable
//import com.tencent.qgame.animplayer.AnimView
//import com.tencent.qgame.animplayer.inter.IFetchResource
//import com.tencent.qgame.animplayer.mix.Resource
//import com.tencent.qgame.animplayer.util.ScaleType
//import com.kelly.dawi.simpleImpl.SimpleVapCallback
//import kotlinx.coroutines.*
//import java.io.File
//import java.lang.RuntimeException
//import java.util.concurrent.CancellationException
//
///**
// * @Author Vance
// * @Date 2022/6/17 0017 13:44
// */
//
//object AnimEffectUtil {
//
// @JvmStatic
// fun newBuilder(): ExtBuilder {
// return ExtBuilder()
// }
//
// @JvmStatic
// fun load(url: String?): ExtBuilder {
// return ExtBuilder().load(url)
// }
//
// class ExtBuilder : IFetchResource, View.OnAttachStateChangeListener {
// private val defTextPaint = TextPaint().apply { textAlign = Paint.Align.CENTER }
//
// private var job: Job? = null
// private var extMap = mutableMapOf<String, Ext>()
// private var glideRequests = mutableListOf<FutureTarget<*>?>()
//
// private var tempExtMap = mutableMapOf<String, Ext>()
// private var listener: Listener? = null
// private var repeatCount: Int? = null
// private var clearsAfterDetached: Boolean? = null
// private var scaleType: ImageView.ScaleType? = null
//
// private var url: String? = null
//
// private var skipMemoryCache = true
//
// private var scope:CoroutineScope? = null
//
// fun load(url: String?): ExtBuilder {
// this.url = url
// return this
// }
//
// fun setCoroutineScope(scope:CoroutineScope): ExtBuilder {
// this.scope = scope
// return this
// }
//
// fun skipMemoryCache(skipMemoryCache: Boolean): ExtBuilder {
// this.skipMemoryCache = skipMemoryCache
// return this
// }
//
// fun scaleType(scaleType: ImageView.ScaleType): ExtBuilder {
// this.scaleType = scaleType
// return this
// }
//
// fun clearsAfterDetached(clearsAfterDetached: Boolean): ExtBuilder {
// this.clearsAfterDetached = clearsAfterDetached
// return this
// }
//
// fun listener(listener: Listener?): ExtBuilder {
// this.listener = listener
// return this
// }
//
// fun repeatCount(repeatCount: Int): ExtBuilder {
// this.repeatCount = repeatCount
// return this
// }
//
// /**
// * textPain是SVGA用的
// */
// @JvmOverloads
// fun putText(key: String, text: String?, textPaint: TextPaint = defTextPaint): ExtBuilder {
// tempExtMap[key] = Ext(text, textPaint)
// return this
// }
//
// @JvmOverloads
// fun putImg(
// key: String,
// imgUrl: Any?,
// widthDp: Float = 0f,
// heightDp: Float = 0f,
// isCircle: Boolean = true,
// @DrawableRes default: Int = 0
// ): ExtBuilder {
// tempExtMap[key] = Ext(
// imgGetter = {
// val option = RequestOptions()
// if (isCircle) {
// option.circleCrop()
// }
// if (widthDp > 0 && heightDp > 0) {
// option.override(widthDp.dp, heightDp.dp)
// }
//
// val futureTarget = RequestFutureTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
// glideRequests.add(futureTarget)
// var bitmap: Bitmap? = null
// try {
// bitmap = Glide.with(MyUtils.application)
// .asBitmap()
// .load(imgUrl)
// .apply(option)
// .addListener(futureTarget)
// .into(futureTarget)
// .get()
// }catch (e: InterruptedException){
// glideRequests.remove(futureTarget)
// return@Ext null //取消掉的直接返回不去加载默认图了
// }catch (e: CancellationException){
// glideRequests.remove(futureTarget)
// return@Ext null //取消掉的直接返回不去加载默认图了
// }catch (e: Exception){
// glideRequests.remove(futureTarget)
// }
//
// if (bitmap == null && default != 0) {
// val defFutureTarget = RequestFutureTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
// glideRequests.add(defFutureTarget)
// bitmap = Glide.with(MyUtils.application)
// .asBitmap()
// .load(default)
// .apply(option)
// .addListener(defFutureTarget)
// .into(defFutureTarget)
// .getOrNull()
// }
// bitmap
// })
// return this
// }
//
// fun into(svgaImageView: SVGAImageView){
// setup(svgaImageView)
// val animUrl = url
// if(animUrl.isNullOrBlank()){
// listener?.onAnimError(RuntimeException("url is empty"))
// return
// }
//
// var svgaUrl = animUrl
// if(!animUrl.startsWith("http")){//没有http前缀就当成asset文件加载
// svgaUrl = "file:///android_asset/$animUrl"
// }
//
// if(scope == null){
// scope = svgaImageView.findViewTreeLifecycleOwner()?.lifecycleScope
// }
//
// job = scope?.launch(Dispatchers.IO) {
// val svgaJob = async {
// Glide.with(svgaImageView.context)
// .asSVGADrawable()
// .load(svgaUrl.trim())
// .skipMemoryCache(skipMemoryCache)
// .submit()
// .suspendGetOrNull()
// }
//
// val bitmapJobMap = mutableMapOf<String, Deferred<Bitmap?>>()
// val textMap = mutableMapOf<String, Ext>()
// val paramsMap = mutableMapOf<String, Ext>()
// try {
// paramsMap.putAll(extMap)
// paramsMap.forEach {
// ensureActive()
// if (it.value.isImg()) {
// val job = async { it.value.getBitMap() }
// bitmapJobMap[it.key] = job
// } else {
// textMap[it.key] = it.value
// }
// }
// } catch (_: Exception) { }
//
// val drawable = svgaJob.await()
// if (drawable == null) {
// bitmapJobMap.forEach {
// it.value.cancelAndJoin()
// }
// val imgRequests = glideRequests
// imgRequests.forEach {
// it?.cancel(true)
// }
// withContext(Dispatchers.Main) {
// onAnimError("svga loading error ")
// }
// } else {
// bitmapJobMap.forEach { entry ->
// ensureActive()
// entry.value.await()?.let {
// drawable.dynamicItem.setDynamicImage(it, entry.key)
// }
// }
// textMap.forEach { entry ->
// entry.value.text?.let {
// drawable.dynamicItem.setDynamicText(it, entry.value.textPaint, entry.key)
// }
// }
//
// withContext(Dispatchers.Main) {
// onAnimStart()
// svgaImageView.setImageDrawable(drawable)
// svgaImageView.startAnimation()
// extMap = mutableMapOf()
// glideRequests = mutableListOf()
// }
// }
// }
// }
//
// fun into(animView: AnimView){
// setup(animView)
// val mp4Url = url
// if(mp4Url.isNullOrBlank()){
// listener?.onAnimError(RuntimeException("url is empty"))
// return
// }
//
// animView.setFetchResource(this)
//
// if(!mp4Url.startsWith("http")){//没有http前缀就当成asset文件加载
// onAnimStart()
// animView.startPlay(animView.context.assets, mp4Url)
// return
// }
//
// if(scope == null){
// scope = animView.findViewTreeLifecycleOwner()?.lifecycleScope
// }
// job = scope?.launch(Dispatchers.IO) {
// Glide.with(animView.context)
// .asFile()
// .skipMemoryCache(skipMemoryCache)
// .load(mp4Url)
// .addListener(object : RequestListener<File> {
// override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<File>, isFirstResource: Boolean): Boolean {
// e?.logRootCauses("vap_loading_error")
// animView.post {
// onAnimError("vap loading error msg:${e?.message ?: "empty"}")
// }
// return true
// }
//
// override fun onResourceReady(resource: File, model: Any, target: Target<File>?, dataSource: DataSource, isFirstResource: Boolean): Boolean {
// return false
// }
// })
// .submit()
// .suspendGetOrNull()
// ?.let {
// withContext(Dispatchers.Main){
// onAnimStart()
// animView.startPlay(it)
// }
// }
// }
// }
//
// private fun setup(view: View){
// if(Looper.myLooper() != Looper.getMainLooper()){
// throw Exception("must run on MAIN Thread current Thread ${Thread.currentThread().name}")
// }
// cancelJob()
// extMap = mutableMapOf()
// extMap.putAll(tempExtMap)
// view.addOnAttachStateChangeListener(this)
//
// if(view is SVGAImageView){
// if(!skipMemoryCache){
// view.clearsAfterDetached = false
// } else {
// clearsAfterDetached?.let { view.clearsAfterDetached = it }
// }
// repeatCount?.let { view.loops = if(it <= 0) Int.MAX_VALUE else it }
// scaleType?.let { view.scaleType = it }
// view.callback = object: SimpleSvgaCallback(){
// override fun onStep(frame: Int, percentage: Double) {
// if (percentage == 1.0) {
// view.post { onAnimComplete() }
// }
// }
// }
// }else if (view is AnimView){
// repeatCount?.let { view.setLoop(if(it <= 0) Int.MAX_VALUE else it) }
// scaleType?.let {
// when (it) {
// ImageView.ScaleType.FIT_XY -> {
// view.setScaleType(ScaleType.FIT_XY)
// }
// ImageView.ScaleType.CENTER_CROP -> {
// view.setScaleType(ScaleType.CENTER_CROP)
// }
// else -> {
// view.setScaleType(ScaleType.FIT_CENTER)
// }
// }
// }
// view.setAnimListener(object : SimpleVapCallback(){
// override fun onFailed(errorType: Int, errorMsg: String?) {
// view.post { onAnimError("vap errorType:${errorMsg} errorMsg:${errorMsg ?: "empty"}") }
// }
//
// override fun onVideoComplete() {
// view.post { onAnimComplete() }
// }
// })
// }
// }
//
// fun clear(){
// tempExtMap = mutableMapOf()
// extMap = mutableMapOf()
// cancelJob()
// }
//
// private fun cancelJob(){
// try {
// job?.cancel()
// val imgRequests = glideRequests
// glideRequests = mutableListOf()
// imgRequests.forEach {
// it?.cancel(true)
// }
// } catch (_: Exception) { }
// }
//
// private fun onAnimStart() {
// listener?.onAnimStart()
// }
//
// private fun onAnimComplete() {
// extMap = mutableMapOf()
// glideRequests = mutableListOf()
// listener?.onAnimComplete()
// }
//
// private fun onAnimError(msg: String) {
// extMap = mutableMapOf()
// cancelJob()
// listener?.onAnimError(Exception(msg))
// }
//
// override fun fetchImage(resource: Resource, result: (Bitmap?) -> Unit) {
// val ext = extMap[resource.tag]
// result(ext?.getBitMap())
// }
//
// override fun fetchText(resource: Resource, result: (String?) -> Unit) {
// val ext = extMap[resource.tag]
// result(ext?.text)
// }
//
// override fun releaseResource(resources: List<Resource>) {
// }
//
// private inner class Ext(
// val text: String? = null,
// val textPaint: TextPaint = defTextPaint,
// val imgGetter: (() -> Bitmap?)? = null) {
// fun getBitMap(): Bitmap? {
// return try {
// val bitmap = imgGetter?.invoke()
// bitmap
// } catch (t: Throwable) {
// null
// }
// }
//
// fun isImg(): Boolean {
// return text.isNullOrBlank()
// }
//
// fun isText(): Boolean {
// return !text.isNullOrBlank()
// }
// }
//
// override fun onViewAttachedToWindow(v: View) {
// }
//
// override fun onViewDetachedFromWindow(v: View) {
// v.removeOnAttachStateChangeListener(this)
// cancelJob()
// }
// }
//
// interface Listener {
// fun onAnimStart() {}
// fun onAnimComplete()
// fun onAnimError(e: Exception?) {
// onAnimComplete()
// }
// }
//}

View File

@@ -1376,6 +1376,28 @@ class GlideUtils {
glideConfig?.downloadOnly()?.load(url)?.listener(listener)?.preload()
}
/**
* 使用Glide下载图片,返回File
*/
fun downloadFromUrl2(
context: Context?,
url: String?,
listener: RequestListener<File?>?
) {
if (context == null) {
LibLogger.error(TAG, "load context is null")
return
}
val glideConfig = getGlideConfig(context)
glideConfig
?.asFile()
?.skipMemoryCache(true)
?.load(url)
?.addListener(listener)
?.submit()
}
/**
* 加载图片并添加RequestListener ,无占位图 ,listener需使用addListener方法添加
*/
@@ -1422,6 +1444,17 @@ class GlideUtils {
.into(imageView)
}
}
//加载图片,无默认图片
fun loadAsBitmap(url: String?, imageView: ImageView?) {
if (imageView == null || TextUtils.isEmpty(url)) {
LibLogger.error(TAG, "load url is invalid or imageViw is null")
return
}
getGlideConfig(imageView.context)?.apply {
this.asDrawable().load(url)
.into(imageView)
}
}
//加载图片,无默认图片
fun loadWithError(url: String?, errorDrawable: Int, imageView: ImageView?) {

View File

@@ -8,6 +8,8 @@ import androidx.core.view.isVisible
import com.chwl.library.utils.ResUtil
import com.chwl.library.utils.SizeUtils
import com.example.lib_utils.UiUtils.isRtl
import com.example.lib_utils.ktx.getString
import com.hjq.toast.ToastUtils
fun View.setMargin(start:Int?=null,top:Int?=null,end:Int?=null,bottom:Int?=null,isDP:Boolean = true) {
@@ -70,6 +72,32 @@ fun String?.isVerify() : Boolean {
return this?.isBlank() == false
}
fun String?.isSvgaUrl() : Boolean {
if (this.isVerify()) {
return this?.endsWith(".svga") == true || this?.endsWith(".SVGA") == true
}
return false
}
fun String?.isMp4() : Boolean {
if (this.isVerify()) {
return this?.endsWith(".mp4") == true
}
return false
}
fun String?.doToast() {
if (this.isVerify()) {
ToastUtils.show(this)
}
}
fun Int.doToast() {
val string = this.getString()
if (string.isVerify()) {
ToastUtils.show(this)
}
}
fun List<Any>?.isVerify() : Boolean{
return this?.isEmpty() == false
}

View File

@@ -74,11 +74,74 @@ class SpannableTextBuilder(private val textView: TextView) {
textSize,
textStyle,
underline,
null,
clickListener
)
return this
}
fun setTextStyle(
text: String,
@ColorInt textColor: Int? = null,
@ColorInt backgroundColor: Int? = null,
textSize: Int? = null,
textStyle: Int? = null,
underline: Boolean? = null,
clickListener: ((String) -> Unit)? = null
): SpannableTextBuilder {
if (text.isEmpty()) {
return this
}
val start = spannableBuilder.indexOf(text)
if (start == -1) {
return this
}
val end = start + text.length
return setTextStyle(
text,
start,
end,
textColor,
backgroundColor,
textSize,
textStyle,
underline,
null,
clickListener
)
}
fun setTextStyle(
text: String,
@ColorInt textColor: Int? = null,
@ColorInt backgroundColor: Int? = null,
textSize: Int? = null,
textStyle: Int? = null,
underline: Boolean? = null,
delLine: Boolean? = null,
clickListener: ((String) -> Unit)? = null
): SpannableTextBuilder {
if (text.isEmpty()) {
return this
}
val start = spannableBuilder.indexOf(text)
if (start == -1) {
return this
}
val end = start + text.length
return setTextStyle(
text,
start,
end,
textColor,
backgroundColor,
textSize,
textStyle,
underline,
delLine,
clickListener
)
}
/**
* 添加图片
* @param drawable 图片
@@ -187,6 +250,7 @@ class SpannableTextBuilder(private val textView: TextView) {
textSize: Int? = null,
textStyle: Int? = null,
underline: Boolean? = null,
delLine: Boolean? = null,
clickListener: ((String) -> Unit)? = null
): SpannableTextBuilder {
if (start < 0 || end > spannableBuilder.length) {
@@ -236,6 +300,10 @@ class SpannableTextBuilder(private val textView: TextView) {
if (underline == true) {
spannableBuilder.setSpan(UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
// 删除线
if (delLine == true) {
spannableBuilder.setSpan(StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
// 点击事件
if (clickListener != null) {
@@ -251,35 +319,7 @@ class SpannableTextBuilder(private val textView: TextView) {
return this
}
fun setTextStyle(
text: String,
@ColorInt textColor: Int? = null,
@ColorInt backgroundColor: Int? = null,
textSize: Int? = null,
textStyle: Int? = null,
underline: Boolean? = null,
clickListener: ((String) -> Unit)? = null
): SpannableTextBuilder {
if (text.isEmpty()) {
return this
}
val start = spannableBuilder.indexOf(text)
if (start == -1) {
return this
}
val end = start + text.length
return setTextStyle(
text,
start,
end,
textColor,
backgroundColor,
textSize,
textStyle,
underline,
clickListener
)
}
fun build(): SpannableStringBuilder {
return spannableBuilder

279
mode.json
View File

@@ -1,98 +1,181 @@
[
{
"id": 359,
"uid": 3224,
"nameplateId": 101,
"isCustomWord": false,
"word": " ",
"remark": " ",
"expireTime": 1731998395000,
"createTime": 1731047995000,
"updateTime": 1731318342000,
"nameplateName": "schoolgirl-Advanced",
"nameplateImage": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
"expireDays": 0,
"iconPic": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
"fixedWord": " ",
"nameplateType": "1"
},
{
"id": 371,
"uid": 3224,
"nameplateId": 96,
"isCustomWord": false,
"remark": " ",
"expireTime": 1731143136000,
"createTime": 1731056736000,
"updateTime": 1731056736000,
"nameplateName": "king",
"nameplateImage": "https://image.pekolive.com/zu689(11).png",
"expireDays": 0,
"iconPic": "https://image.pekolive.com/zu689(11).png",
"nameplateType": "1"
},
{
"id": 369,
"uid": 3224,
"nameplateId": 100,
"isCustomWord": false,
"remark": " ",
"expireTime": 1731143131000,
"createTime": 1731056731000,
"updateTime": 1731056731000,
"nameplateName": "schoolgirl-Advanced",
"nameplateImage": "https://image.pekolive.com/huayunu:shen.png",
"expireDays": 0,
"iconPic": "https://image.pekolive.com/guanfangzhuli-bajisitan.png",
"nameplateType": "1"
},
{
"id": 367,
"uid": 3224,
"nameplateId": 93,
"isCustomWord": false,
"remark": " ",
"expireTime": 1731143124000,
"createTime": 1731056724000,
"updateTime": 1731056724000,
"nameplateName": "queen",
"nameplateImage": "https://image.pekolive.com/zu688(3).png",
"expireDays": 0,
"iconPic": "https://image.pekolive.com/zu688(3).png",
"nameplateType": "1"
},
{
"id": 365,
"uid": 3224,
"nameplateId": 92,
"isCustomWord": true,
"word": " العناوين",
"remark": " العناوين",
"expireTime": 1731143086000,
"createTime": 1731056686000,
"updateTime": 1731056686000,
"nameplateName": "給糖不搗蛋",
"nameplateImage": "https://image.pekolive.com/8350643695e74ec9bb78b9944fc9e842.png",
"expireDays": 0,
"iconPic": "https://image.pekolive.com/zu689(5).png",
"fixedWord": "العناوين",
"nameplateType": "1"
},
{
"id": 124,
"uid": 3224,
"nameplateId": 101,
"isCustomWord": false,
"word": " ",
"remark": " ",
"expireTime": 1729340700000,
"createTime": 1728476700000,
"updateTime": 1731318342000,
"nameplateName": "schoolgirl-Advanced",
"nameplateImage": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
"expireDays": 0,
"iconPic": "https://image.pekolive.com/gonghuizhangmingpaikaobei.png",
"fixedWord": " ",
"nameplateType": "1"
}
]
{
"success": true,
"code": 200,
"message": "success",
"data": [
{
"dressId": 195,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.pekolive.com/Vip5headdress.png",
"effectType": 2,
"effect": "https://image.pekolive.com/Vip5headdress.svga",
"name": "VIP5頭飾",
"used": true,
"expireDays": 22,
"hasExpired": false,
"expireTime": 1733976000000
},
{
"dressId": 196,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.pekolive.com/Vip6headdress.png",
"effectType": 2,
"effect": "https://image.pekolive.com/Vip6headdress.svga",
"name": "VIP6頭飾",
"used": false,
"expireDays": 25,
"hasExpired": false,
"expireTime": 1734235200000
},
{
"dressId": 193,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.pekolive.com/Vip3headdress.png",
"effectType": 2,
"effect": "https://image.pekolive.com/Vip3headdress.svga",
"name": "VIP3頭飾",
"used": false,
"expireDays": 23,
"hasExpired": false,
"expireTime": 1734062400000
},
{
"dressId": 26,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/1df2071a-610d-41be-b763-8437ef9f3524",
"effectType": 2,
"effect": "https://image.hfighting.com/6d9ff134-80c1-44d5-97b0-981817e03bd4",
"name": "幸運星人",
"used": false,
"expireDays": 22,
"hasExpired": false,
"expireTime": 1733919509000
},
{
"dressId": 31,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/2ec2f8cd-e660-4af2-bd49-b9eed8de10a2",
"effectType": 2,
"effect": "https://image.hfighting.com/34369437-e9a3-4bb8-80a2-f310bf8e90fc",
"name": "財氣沖天",
"used": false,
"expireDays": 13,
"hasExpired": false,
"expireTime": 1733173500000
},
{
"dressId": 27,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/06fe0618-cd55-4e5e-84bf-1071f821d608",
"effectType": 2,
"effect": "https://image.hfighting.com/22f0fbb1-fdb1-46f9-b037-03f0693effeb",
"name": "潮舞星迎",
"used": false,
"expireDays": 13,
"hasExpired": false,
"expireTime": 1733131248000
},
{
"dressId": 123,
"dressType": 0,
"obtainWay": 1,
"pic": "http://beta.img.pekolive.com/FklHnzcmijfk_0QGRePXuzG3LSdN?imageslim",
"effectType": 2,
"effect": "http://beta.img.pekolive.com/FmDgjyKd_p0SvpKmC5v0rwhszdH9?imageslim",
"name": "花语小兔",
"used": false,
"expireDays": 9,
"hasExpired": false,
"expireTime": 1732780728000
},
{
"dressId": 110,
"dressType": 0,
"obtainWay": 1,
"pic": "http://beta.img.pekolive.com/FrTtFcnSI88bITGonp5PJjdbGLLR?imageslim",
"effectType": 2,
"effect": "http://beta.img.pekolive.com/FrTtFcnSI88bITGonp5PJjdbGLLR?imageslim",
"name": "豪氣季軍",
"used": false,
"expireDays": 8,
"hasExpired": false,
"expireTime": 1732760886000
},
{
"dressId": 30,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/0fcea959-e82a-410e-a3f5-52f751a6c327",
"effectType": 2,
"effect": "https://image.hfighting.com/efacf269-c628-4940-984f-b817aabf2127",
"name": "拉丁之神",
"used": false,
"expireDays": 6,
"hasExpired": false,
"expireTime": 1732526621000
},
{
"dressId": 28,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/4dd02f23-e30f-4df7-9326-53a1f4ae8ebf",
"effectType": 2,
"effect": "https://image.hfighting.com/c17f08d6-1854-4d03-a760-e02ad5fdf081",
"name": "月魔法帽",
"used": false,
"expireDays": 6,
"hasExpired": false,
"expireTime": 1732526452000
},
{
"dressId": 42,
"dressType": 0,
"obtainWay": 1,
"pic": "http://beta.img.pekolive.com/Fq_EzPCxN99nV84CgO3c3z242pEh?imageslim",
"effectType": 2,
"effect": "http://beta.img.pekolive.com/Fq_EzPCxN99nV84CgO3c3z242pEh?imageslim",
"name": "海浪",
"used": false,
"expireDays": 2,
"hasExpired": false,
"expireTime": 1732175930000
},
{
"dressId": 29,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/a51c4b19-6862-41fa-83cb-2475db2320da",
"effectType": 2,
"effect": "https://image.hfighting.com/5df51843-1c4c-40c1-b1dd-5420ce093de2",
"name": "神囚魔法",
"used": false,
"expireDays": 1,
"hasExpired": false,
"expireTime": 1732097432000
},
{
"dressId": 102,
"dressType": 0,
"obtainWay": 1,
"pic": "http://beta.img.pekolive.com/FrQQrQ0yEhTCLxyKHygT76kZLHoy?imageslim",
"effectType": 2,
"effect": "http://beta.img.pekolive.com/FqJrMr8YmRr6WBR0FOMaYL05HPxy?imageslim",
"name": "星河白羽",
"used": false,
"expireDays": 0,
"hasExpired": true,
"expireTime": 1731664948000
},
{
"dressId": 44,
"dressType": 0,
"obtainWay": 1,
"pic": "https://image.hfighting.com/bb55be24-3418-4f03-bf46-1bb491b95ba2",
"effectType": 2,
"effect": "https:/

View File

@@ -31,11 +31,12 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.widget.ImageView;
import androidx.appcompat.widget.AppCompatImageView;
import com.netease.nim.uikit.R;
public class CircleImageView extends ImageView {
public class CircleImageView extends AppCompatImageView {
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;