Commit cda8590c authored by mengcuiguang's avatar mengcuiguang

代码优化

parent 4e0cc1f4
...@@ -228,6 +228,7 @@ dependencies { ...@@ -228,6 +228,7 @@ dependencies {
api project(':wxpay') api project(':wxpay')
api project(':alipay') api project(':alipay')
api project(':oaid') api project(':oaid')
api project(':library_tagflow')
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4' implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
// bugly // bugly
implementation 'com.tencent.bugly:crashreport:3.3.92' implementation 'com.tencent.bugly:crashreport:3.3.92'
......
...@@ -56,8 +56,8 @@ public class MintsApplication extends MultiDexApplication { ...@@ -56,8 +56,8 @@ public class MintsApplication extends MultiDexApplication {
// 友盟SDK预初始化函数 // 友盟SDK预初始化函数
// preInit预初始化函数耗时极少,不会影响App首次冷启动用户体验 // preInit预初始化函数耗时极少,不会影响App首次冷启动用户体验
UmengManager.INSTANCE.preInit(this, // UmengManager.INSTANCE.preInit(this,
MateUtils.INSTANCE.getAppMetaData(this, "CHANNEL_NAME")); // MateUtils.INSTANCE.getAppMetaData(this, "CHANNEL_NAME"));
// 判断应用是否在前台 // 判断应用是否在前台
ForegroundOrBackground.init(this); ForegroundOrBackground.init(this);
......
package com.duben.happyplaylet.ui.adapter
import android.annotation.SuppressLint
import android.app.Activity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.duben.happyplaylet.R
import com.duben.happyplaylet.mvp.model.HotStyleTypesBean
import com.framework.tagflow.adapter.BaseTagAdapter
@SuppressLint("ViewHolder")
class MainTypeAdapter(private val mActivity: Activity) :
BaseTagAdapter<HotStyleTypesBean?>() {
var currentCheckedItemPosition = 0
override fun getView(
position: Int,
convertView: View?,
parent: ViewGroup
): View {
val view =
LayoutInflater.from(mActivity).inflate(R.layout.item_video_tab, parent, false)
val textView: TextView = view.findViewById<TextView>(R.id.item_tv)
val bean = getItem(position)
if (bean != null) {
if(position%2==0){
textView.text = bean.type
}else{
textView.text = bean.type+"testtesttesttest"
}
}
if (currentCheckedItemPosition == position) {
textView.setTextColor(ContextCompat.getColor(mActivity, R.color.red))
} else {
textView.setTextColor(ContextCompat.getColor(mActivity, R.color.color_8D8F90))
}
return view
}
fun setCheck(position: Int) {
currentCheckedItemPosition = position
notifyDataSetChanged()
}
}
\ No newline at end of file
...@@ -11,10 +11,6 @@ import androidx.core.content.ContextCompat ...@@ -11,10 +11,6 @@ import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.listener.OnRefreshListener
import com.duben.happyplaylet.R import com.duben.happyplaylet.R
import com.duben.happyplaylet.ad.AdManager import com.duben.happyplaylet.ad.AdManager
import com.duben.happyplaylet.ad.banner.BannerManager import com.duben.happyplaylet.ad.banner.BannerManager
...@@ -27,11 +23,11 @@ import com.duben.happyplaylet.mvp.model.* ...@@ -27,11 +23,11 @@ import com.duben.happyplaylet.mvp.model.*
import com.duben.happyplaylet.mvp.presenters.HomePresenter import com.duben.happyplaylet.mvp.presenters.HomePresenter
import com.duben.happyplaylet.mvp.views.HomeView import com.duben.happyplaylet.mvp.views.HomeView
import com.duben.happyplaylet.ui.activitys.NineActivity import com.duben.happyplaylet.ui.activitys.NineActivity
import com.duben.happyplaylet.ui.activitys.NinePayActivity
import com.duben.happyplaylet.ui.activitys.RecommendActivity import com.duben.happyplaylet.ui.activitys.RecommendActivity
import com.duben.happyplaylet.ui.activitys.VipActivity import com.duben.happyplaylet.ui.activitys.VipActivity
import com.duben.happyplaylet.ui.adapter.HomeVideoPageAdapter import com.duben.happyplaylet.ui.adapter.HomeVideoPageAdapter
import com.duben.happyplaylet.ui.adapter.ImageTitleAdapter import com.duben.happyplaylet.ui.adapter.ImageTitleAdapter
import com.duben.happyplaylet.ui.adapter.MainTypeAdapter
import com.duben.happyplaylet.ui.adapter.TopAdapter import com.duben.happyplaylet.ui.adapter.TopAdapter
import com.duben.happyplaylet.ui.fragment.base.LazyLoadBaseFragment import com.duben.happyplaylet.ui.fragment.base.LazyLoadBaseFragment
import com.duben.happyplaylet.utils.AppPreferencesManager import com.duben.happyplaylet.utils.AppPreferencesManager
...@@ -39,6 +35,10 @@ import com.duben.happyplaylet.utils.SpanUtils ...@@ -39,6 +35,10 @@ import com.duben.happyplaylet.utils.SpanUtils
import com.duben.library.utils.GlideUtils import com.duben.library.utils.GlideUtils
import com.duben.library.utils.json.JsonUtil import com.duben.library.utils.json.JsonUtil
import com.duben.library.utils.nodoubleclick.AntiShake import com.duben.library.utils.nodoubleclick.AntiShake
import com.framework.tagflow.interfac.OnTagClickListener
import com.google.android.material.tabs.TabLayout
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.listener.OnRefreshListener
import kotlinx.android.synthetic.main.fragment_main.* import kotlinx.android.synthetic.main.fragment_main.*
import java.lang.reflect.Field import java.lang.reflect.Field
import java.util.* import java.util.*
...@@ -52,7 +52,7 @@ import kotlin.concurrent.schedule ...@@ -52,7 +52,7 @@ import kotlin.concurrent.schedule
class MainFragment : LazyLoadBaseFragment(), HomeView, View.OnClickListener, OnRefreshListener { class MainFragment : LazyLoadBaseFragment(), HomeView, View.OnClickListener, OnRefreshListener {
companion object { companion object {
var mSelectTabIndex = -1 var mSelectTabIndex = 0
} }
private val tabsData = mutableListOf<HotStyleTypesBean>() private val tabsData = mutableListOf<HotStyleTypesBean>()
...@@ -201,45 +201,10 @@ class MainFragment : LazyLoadBaseFragment(), HomeView, View.OnClickListener, OnR ...@@ -201,45 +201,10 @@ class MainFragment : LazyLoadBaseFragment(), HomeView, View.OnClickListener, OnR
vpAdapter = HomeVideoPageAdapter(tabsData, this) vpAdapter = HomeVideoPageAdapter(tabsData, this)
vp2.adapter = vpAdapter vp2.adapter = vpAdapter
vp2.desensitization()
TabLayoutMediator(tablayout, vp2) { tab, position ->
// 初始化Tab
tab.id = position
if (tabsData.size > 0) {
tab.customView = getTabView(tabsData[position].type)
}
}.attach()
tablayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
updateTab(tab, true)
mSelectTabIndex = tab!!.id
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
updateTab(tab, false)
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
vp2.offscreenPageLimit = 100 vp2.offscreenPageLimit = 100
} vp2.isUserInputEnabled = false
private fun updateTab(tab: TabLayout.Tab?, isSelected: Boolean) {
tab?.customView?.let {
val text = it.findViewById<TextView>(R.id.item_tv)
if (isSelected) {
text.setTextColor(ContextCompat.getColor(requireContext(), R.color.red))
} else {
text.setTextColor(ContextCompat.getColor(requireContext(), R.color.color_8D8F90))
}
}
}
private fun getTabView(text: String): View {
val view = LayoutInflater.from(requireContext()).inflate(R.layout.item_video_tab, null)
view.findViewById<TextView>(R.id.item_tv).text = text
return view
} }
override fun onRefresh(refreshLayout: RefreshLayout) { override fun onRefresh(refreshLayout: RefreshLayout) {
...@@ -287,6 +252,24 @@ class MainFragment : LazyLoadBaseFragment(), HomeView, View.OnClickListener, OnR ...@@ -287,6 +252,24 @@ class MainFragment : LazyLoadBaseFragment(), HomeView, View.OnClickListener, OnR
mSelectTabIndex = 0 mSelectTabIndex = 0
vpAdapter?.notifyDataSetChanged() vpAdapter?.notifyDataSetChanged()
} }
val mainTypeAdapter = MainTypeAdapter(requireActivity())
if (tabsData.size > 0) {
for (index in 0..tabsData.size - 1) {
mainTypeAdapter.addData(tabsData.get(index))
}
}
multiFlowTagSelf.setAdapter(mainTypeAdapter)
multiFlowTagSelf.setOnTagClickListener(object : OnTagClickListener {
override fun onClick(view: View?, position: Int) {
mSelectTabIndex = position
vp2.setCurrentItem(mSelectTabIndex,false)
mainTypeAdapter.setCheck(position)
}
override fun onLongClick(view: View?, position: Int) {
}
})
} }
override fun topTabsSuc(data: BannerList?) { override fun topTabsSuc(data: BannerList?) {
......
...@@ -121,21 +121,16 @@ ...@@ -121,21 +121,16 @@
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
<com.google.android.material.tabs.TabLayout <com.framework.tagflow.MultiTagFlowLayout
android:id="@+id/tablayout" android:layout_marginLeft="16dp"
android:layout_width="wrap_content" android:layout_marginRight="16dp"
android:layout_height="38dp" android:id="@+id/multiFlowTagSelf"
android:layout_marginLeft="10dp" android:layout_width="match_parent"
android:layout_marginRight="10dp" android:layout_height="wrap_content"
android:paddingTop="-10dp" app:hasMore="true"
app:tabBackground="@null" app:layout_type="FlowLayout"
app:tabIndicatorHeight="0dp" app:tagsHorizontalSpace="@dimen/dp_5"
app:tabMaxWidth="200dp" app:tagsVerticalSpace="@dimen/dp_5"/>
app:tabMinWidth="20dp"
app:tabMode="scrollable"
app:tabPaddingEnd="6dp"
app:tabPaddingStart="6dp"
app:tabRippleColor="@null" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
...@@ -159,6 +154,7 @@ ...@@ -159,6 +154,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:visibility="gone"
android:id="@+id/ll_main_watching_root" android:id="@+id/ll_main_watching_root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/constraint_layout"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:layout_gravity="center_vertical|center_horizontal"
android:layout_margin="@dimen/dp_8"
android:background="@drawable/common_bg_radius_15_white"
android:paddingLeft="16dp"
android:paddingTop="4dp"
android:paddingRight="16dp"
android:paddingBottom="4dp">
<TextView <TextView
android:id="@+id/item_tv" android:id="@+id/item_tv"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="2dp" android:ellipsize="end"
android:paddingTop="6dp" android:text="香港"
android:paddingRight="5dp" android:textColor="@color/color_333333"
android:paddingBottom="6dp" android:textSize="@dimen/sp_13"
android:textColor="@color/color_8D8F90" app:layout_constraintBottom_toBottomOf="parent"
android:textSize="16sp" app:layout_constraintEnd_toEndOf="parent"
android:textStyle="bold" /> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
\ No newline at end of file </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -44,7 +44,7 @@ WEIXIN_APP_SECRET =9eff885315f5f74fc9d6980e2bb1714a ...@@ -44,7 +44,7 @@ WEIXIN_APP_SECRET =9eff885315f5f74fc9d6980e2bb1714a
RELEASE_UMENG_KEY=64d214b2a1a164591b65956b RELEASE_UMENG_KEY=64d214b2a1a164591b65956b
#TalkingData #TalkingData
RELEASE_TALKING_DATA_KEY="E91735A7978140A8ABD1BB32D337CCAB" RELEASE_TALKING_DATA_KEY="C4092984E50144DD802C4AC32DD40F74"
GROMORE_APP_ID="5423447" GROMORE_APP_ID="5423447"
GROMORE_SPLASH_CODE="102416580" GROMORE_SPLASH_CODE="102416580"
......
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
version = '1.0'
android {
namespace 'com.framework.tagflow'
compileSdk 31
defaultConfig {
minSdk 21
targetSdk 31
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest>
</manifest>
\ No newline at end of file
package com.framework.tagflow
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.RecyclerView
/**
* @author: xiaxueyi
* @date: 2022-10-25
* @time: 13:55
* @说明:
*/
class GridLayoutItemDecoration(
private val spanCount: Int,
private val spacing: Int,
private val includeEdge: Boolean = false
) :
RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val position = parent.getChildAdapterPosition(view) // item position
val column = position % spanCount // item column
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount // spacing - column * ((1f / spanCount) * spacing)
outRect.right = (column + 1) * spacing / spanCount // (column + 1) * ((1f / spanCount) * spacing)
if (position < spanCount) { // top edge
outRect.top = spacing
}
outRect.bottom = spacing // item bottom
} else {
outRect.left = column * spacing / spanCount // column * ((1f / spanCount) * spacing)
outRect.right = spacing - (column + 1) * spacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing)
if (position >= spanCount) {
outRect.top = spacing // item top
}
}
}
/**
* 获取分割线的高度
* @return Int
*/
fun getSpaceHeight():Int{
return spacing
}
/**
*
* @return Int
*/
fun getSpaceCount():Int{
return spanCount
}
/**
*
* @return Boolean
*/
fun getIncludeEdge():Boolean{
return includeEdge
}
}
\ No newline at end of file
package com.framework.tagflow
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.TypedArray
import android.database.DataSetObserver
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.*
import androidx.annotation.IntDef
import androidx.core.view.marginBottom
import androidx.core.view.marginTop
import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import com.framework.tagflow.adapter.BaseTagAdapter
import com.framework.tagflow.bean.BaseTagBean
import com.framework.tagflow.interfac.OnTagClickListener
import com.framework.tagflow.interfac.OnTagSelectedListener
import com.framework.tagflow.tags.MutSelectedTagView
import com.framework.tagflow.utils.DensityUtils
import com.framework.tagflow.view.ControlScrollView
import com.framework.tagflow.view.FlowLayout
import kotlin.math.ceil
/**
* @author: xiaxueyi
* @date: 2022-09-27
* @time: 09:54
* @说明:多样 可折叠和展开的标签控件 流式布局,(RecyclerView和FlowLayout)
*/
open class MultiTagFlowLayout @JvmOverloads constructor(
private val mContext: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : NestedScrollView(mContext, attrs, defStyleAttr) {
private lateinit var mControlScrollView: ControlScrollView //标签容器
private lateinit var mIvArrowMore: ImageView //箭头
private lateinit var mTvMoreHint: TextView //提示文本
private lateinit var mRlShowMore: LinearLayout //展开收起布局
private lateinit var mEmptyViewContainer: FrameLayout;
//是否折叠起来
//true:折叠起来了
//false:展开了
private var isFolded = false
private var isInit = false
private var foldHint = "" //展开后显示的提示文字
private var expandHint = "" //折叠起来后显示的提示文字
private var animationDuration = 0 //展开和折叠动画持续时间
private var mHasMore = false//是否有展开的布局,查看更多
private var mRecyclerViewAdapterDataSetObserver: RecyclerViewAdapterDataSetObserver? = null
private var mRecyclerViewAdapter: RecyclerView.Adapter<*>? = null
private lateinit var mRecyclerView: RecyclerView
private var defaultRows: Int = 2 //默认行数三行
private var defaultColumn: Int = 3;//默认列数三列
private var isNotifyData: Boolean = false //是否刷新了数据
@IntDef(ITEM_MODEL_CLICK, ITEM_MODEL_SELECT)
@Retention(AnnotationRetention.SOURCE)
annotation class ItemMode
//标签模式,点击模式(默认),选中模式
@ItemMode
private var itemModel = 0
private var mOnTagClickListener: OnTagClickListener? = null
private var mSelectedListener: OnTagSelectedListener? = null
private var mLayoutType: Int = 0 //布局类型 0:RecyclerView,1:FlowLayout
private var mAdapterDataSetObserver: AdapterDataSetObserver? = null //FlowLayout 适配器监听
private var mTagAdapter: BaseTagAdapter<*>? = null //FlowLayout 适配器
private lateinit var mFlowLayout: FlowLayout
private var tagsHorizontalSpace = 0 //标签之间的横向间距
private var tagsVerticalSpace = 0 //标签之间的纵向间距
private var mLayoutManagerMode: Int = 0
private lateinit var mEmptyView: View;
companion object {
//默认标签之间的间距
private const val DEFAULT_TAGS_SPACE = 8f
//默认展开动画执行时间(毫秒)
private const val DEFAULT_ANIMATION_DURATION = 400
const val ITEM_MODEL_CLICK = 100000
const val ITEM_MODEL_SELECT = 100001
}
/**
* 列表布局只支持垂直列表模式
* @property index Int
* @constructor
*/
enum class LayoutManagerMode(val index: Int) {
LinearLayoutManager(0),
GridLayoutManager(1),
}
/**
* 布局类型
* @property index Int
* @constructor
*/
enum class LayoutTypeMode(val index: Int) {
RecyclerView(0),
FlowLayout(1),
}
init {
val typedArray: TypedArray =
mContext.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout)
tagsHorizontalSpace = typedArray.getDimension(
R.styleable.TagFlowLayout_tagsHorizontalSpace,
DensityUtils.dp2px(mContext, DEFAULT_TAGS_SPACE).toFloat()
).toInt()
tagsVerticalSpace = typedArray.getDimension(
R.styleable.TagFlowLayout_tagsVerticalSpace,
DensityUtils.dp2px(mContext, DEFAULT_TAGS_SPACE).toFloat()
).toInt()
animationDuration = typedArray.getInt(
R.styleable.TagFlowLayout_animationDuration,
DEFAULT_ANIMATION_DURATION
)
mHasMore = typedArray.getBoolean(R.styleable.TagFlowLayout_hasMore, false)
mLayoutType = typedArray.getInt(R.styleable.TagFlowLayout_layout_type, 0)
mLayoutManagerMode = typedArray.getInt(R.styleable.TagFlowLayout_layoutManager_Mode, 0)
foldHint = formatString(
typedArray.getString(R.styleable.TagFlowLayout_foldHint),
resources.getString(R.string.foldHint)
)
expandHint = formatString(
typedArray.getString(R.styleable.TagFlowLayout_expandHint),
resources.getString(R.string.expandHint)
)
itemModel = ITEM_MODEL_CLICK
typedArray.recycle()
/**
* 实例化组件
*/
initWidget()
/**
* 实例化组件类型
*/
initLayoutType();
/**
*
*/
initLayoutManage()
}
/**
* 初始化组件
*/
private fun initWidget() {
View.inflate(mContext, R.layout.tag_flow_layout, this)
mControlScrollView = findViewById(R.id.hsv_tag_content)
mIvArrowMore = findViewById(R.id.iv_arrow_more)
mTvMoreHint = findViewById(R.id.tv_more_hint)
mRlShowMore = findViewById(R.id.rl_show_more)
mEmptyViewContainer = findViewById(R.id.fl_empty)
mEmptyView =
LayoutInflater.from(context).inflate(R.layout.layout_empty_not_data, this, false)
mControlScrollView.isFillViewport = true
this.isFillViewport = true
mRlShowMore.setOnClickListener(View.OnClickListener {
var maxLine: Double = 0.0//最大行数
//真实数量
var realCount = 0;
var finalLine: Int = 0
var animateStart: Int = 0 //记录动画开始位置
var animateEnd: Int = 0 //记录动画结束位置
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
realCount = mRecyclerViewAdapter?.itemCount ?: 0;
if (mRecyclerView.layoutManager is GridLayoutManager) {
val gridLayoutManager: GridLayoutManager =
mRecyclerView.layoutManager as GridLayoutManager
if (gridLayoutManager.orientation == GridLayoutManager.VERTICAL) {
//计算列表中有多少行
maxLine = (realCount.toDouble() / defaultColumn.toDouble()) //最大行数
}
} else {
maxLine = realCount.toDouble();
}
//最终行数,向上取整,
finalLine = ceil(maxLine).toInt()
}
LayoutTypeMode.FlowLayout.index -> {
realCount = mFlowLayout.getLineSize()
if (realCount >= 6) {
realCount = 6
}
}
else -> {
realCount = 0
}
}
//展开容器
if (!isFolded) {
ObjectAnimator.ofFloat(mIvArrowMore, "rotation", 0f, 180f).start()
if (mLayoutType == LayoutTypeMode.RecyclerView.index) {
animateStart = getLineHeight() * defaultRows
animateEnd = getLineHeight() * finalLine
} else {
animateStart = getLineHeight() * 2
animateEnd = getLineHeight() * realCount
}
animate(animateStart, animateEnd)
mTvMoreHint.text = foldHint //点击收回
mControlScrollView.setCanScroll(false) //设置不可滑动
} else {
ObjectAnimator.ofFloat(mIvArrowMore, "rotation", -180f, 0f).start()
if (mLayoutType == LayoutTypeMode.RecyclerView.index) {
animateStart = getLineHeight() * finalLine
animateEnd = getLineHeight() * defaultRows
} else {
animateStart = getLineHeight() * realCount
animateEnd = getLineHeight() * 2
}
animate(animateStart, animateEnd)
mTvMoreHint.text = expandHint //点击展开
mControlScrollView.setCanScroll(false) //设置不可滑动
}
isFolded = !isFolded
})
}
/**
*动画
* @param animateStart Int
* @param animateEnd Int
*/
private fun animate(animateStart: Int, animateEnd: Int) {
var start: Int = animateStart
var end = animateEnd
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
if (start < 0) {
start = mRecyclerView.measuredHeight
}
if (end < 0) {
end = mRecyclerView.measuredHeight
}
}
LayoutTypeMode.FlowLayout.index -> {
if (start < 0) {
start = mFlowLayout.measuredHeight
}
if (end < 0) {
end = mFlowLayout.measuredHeight
}
}
else -> {
}
}
val animator: ValueAnimator = ValueAnimator.ofInt(start, end)
animator.duration = animationDuration.toLong()
animator.addUpdateListener { animation ->
val value = animation.animatedValue as Int
val layoutParams: ViewGroup.LayoutParams = mControlScrollView.layoutParams
layoutParams.height = value
mControlScrollView.layoutParams = layoutParams
}
animator.interpolator = AccelerateDecelerateInterpolator()
animator.start()
}
/**
* 重新设置数据
*/
private fun reloadData() {
var lines: Int = 0;
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> { //RecyclerView
mRecyclerView.removeAllViews()
lines = mRecyclerViewAdapter?.itemCount ?: 0
}
LayoutTypeMode.FlowLayout.index -> { //FlowLayout
mFlowLayout.removeAllViews()
lines = mTagAdapter?.count ?: 0
}
else -> {
lines = 0;
}
}
/**
* 如果行数为0,重新渲染布局
*/
if (lines == 0) {
val params: ViewGroup.LayoutParams = this.layoutParams
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
this.layoutParams = params
val layoutParams: ViewGroup.LayoutParams = mControlScrollView.layoutParams
layoutParams.height = 0
mControlScrollView.layoutParams = layoutParams
/**
* 增加空布局
*/
mEmptyViewContainer.removeAllViews()
mEmptyViewContainer.addView(mEmptyView)
mEmptyViewContainer.visibility = View.VISIBLE
mRlShowMore.visibility = View.GONE
return
}
val childCount: Int = mEmptyViewContainer.childCount
if (childCount > 0) {
mEmptyViewContainer.removeAllViews()
mEmptyViewContainer.visibility = GONE
}
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> { //RecyclerView
// if(getAdapter() is BaseQuickAdapter<*,*>){
// (getAdapter() as BaseQuickAdapter<*,*>).setOnItemClickListener { adapter, view, position ->
// mOnItemClickListener?.onItemClick(position)
// }
// }
mRecyclerView.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
val itemCount: Int = mRecyclerViewAdapter?.itemCount ?: 0
var realCount: Int = mRecyclerViewAdapter?.itemCount ?: 0;
var maxLine = 0.0//最大行数
if (mRecyclerView.layoutManager is GridLayoutManager) {
val gridLayoutManager: GridLayoutManager =
mRecyclerView.layoutManager as GridLayoutManager
if (gridLayoutManager.orientation == GridLayoutManager.VERTICAL) {
//计算列表中有多少行
maxLine = (realCount.toDouble() / defaultColumn.toDouble()) //最大行数
}
} else {
maxLine = realCount.toDouble();
}
//最终行数,向上取整,
val finalLine = ceil(maxLine).toInt()
if (mHasMore) { //有展开更多的布局
val layoutParams: ViewGroup.LayoutParams =
mControlScrollView.layoutParams
/**
1.如果已經在爆開的情況下
update Data 的話就不用再次收起來
2.但如果是在收起的情況下
update Data 就保持收起
3. 如果在爆開的情況下 按"取消"返回上一頁
下一次進來要收起
首次进入也是收起
true 标识已经刷新数据了,特殊判断
*/
if (isNotifyData) {
if (finalLine <= 2) {
layoutParams.height = getLineHeight() * finalLine
mRlShowMore.visibility = View.GONE
} else {
mRlShowMore.visibility = View.VISIBLE
//表示已经展开了
if (isFolded) {
layoutParams.height = getLineHeight() * finalLine
} else {
//设置默认展开高度(一个item 高度*多少行)
layoutParams.height = getLineHeight() * defaultRows
}
}
mControlScrollView.layoutParams = layoutParams
} else {
if (finalLine <= 2) {
layoutParams.height = getLineHeight() * finalLine
mRlShowMore.visibility = View.GONE
} else {
//设置默认展开高度(一个item 高度*多少行)
layoutParams.height = getLineHeight() * defaultRows
mRlShowMore.visibility = View.VISIBLE
}
mControlScrollView.layoutParams = layoutParams
}
} else { //没有展开更多的布局
mRlShowMore.visibility = View.GONE
val layoutParams: ViewGroup.LayoutParams? =
mControlScrollView.layoutParams
if (layoutParams != null) {
layoutParams.height = getLineHeight() * itemCount
}
mControlScrollView.layoutParams = layoutParams
}
mRecyclerView.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
}
LayoutTypeMode.FlowLayout.index -> { //FlowLayout
mFlowLayout.clearAllView()
mFlowLayout.removeAllViews()
for (i in 0 until mTagAdapter!!.count) {
val view = mTagAdapter?.getView(i, convertView = null, mFlowLayout)
var position: Int = i;
if (itemModel == ITEM_MODEL_CLICK && mOnTagClickListener != null) {
view?.setOnClickListener { v ->
mOnTagClickListener?.onClick(v, position)
}
view?.setOnLongClickListener(object : OnLongClickListener {
override fun onLongClick(v: View): Boolean {
mOnTagClickListener?.onLongClick(v, position)
return true
}
})
} else if (itemModel == ITEM_MODEL_SELECT && mSelectedListener != null) {
view?.setOnClickListener { v ->
if (v is MutSelectedTagView) {
if (!v.isSelected) {
mTagAdapter!!.select(position)
mSelectedListener!!.selected(
v,
position,
mTagAdapter!!.getData() as List<BaseTagBean?>
)
} else {
mTagAdapter!!.unSelect(position)
mSelectedListener!!.unSelected(
v,
position,
mTagAdapter!!.getData() as List<BaseTagBean?>
)
}
v.toggle()
}
}
}
mFlowLayout.addView(view)
}
mFlowLayout.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (!isInit) {
if (mHasMore) { //有展开更多的布局
val lines: Int = mFlowLayout.getLineSize()
val layoutParams: ViewGroup.LayoutParams =
mControlScrollView.layoutParams
if (lines <= 2) {
layoutParams.height = getLineHeight() * lines
mRlShowMore.visibility = View.GONE
} else {
layoutParams.height = getLineHeight() * 2
mRlShowMore.visibility = View.VISIBLE
}
mControlScrollView.layoutParams = layoutParams
} else { //没有展开更多的布局
mRlShowMore.visibility = View.GONE
var layoutParams: ViewGroup.LayoutParams? =
mControlScrollView.layoutParams
val lines: Int = mFlowLayout.getLineSize()
if (layoutParams != null) {
layoutParams.height = getLineHeight() * lines
}
mControlScrollView.layoutParams = layoutParams
}
mFlowLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
isInit = true
}
}
})
}
else -> {
}
}
}
/**
* 初始化列表的布局管理模式
*/
private fun initLayoutManage() {
if (mLayoutType == LayoutTypeMode.RecyclerView.index) {
when (mLayoutManagerMode) {
LayoutManagerMode.LinearLayoutManager.index -> {
val linearLayoutManager: LinearLayoutManager = LinearLayoutManager(context)
linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
mRecyclerView.setHasFixedSize(true)
mRecyclerView.layoutManager = linearLayoutManager;
mRecyclerView.itemAnimator = DefaultItemAnimator()
}
LayoutManagerMode.GridLayoutManager.index -> {
val gridLayoutManager: GridLayoutManager = GridLayoutManager(context, 3)
gridLayoutManager.orientation = GridLayoutManager.VERTICAL
mRecyclerView.setHasFixedSize(true)
mRecyclerView.layoutManager = gridLayoutManager;
mRecyclerView.itemAnimator = DefaultItemAnimator()
}
else -> {
Toast.makeText(context, "un know", Toast.LENGTH_SHORT).show()
}
}
}
}
/**
* RecyclerView监听
*/
internal inner class RecyclerViewAdapterDataSetObserver : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
reloadData()
}
}
/**
* Flowlayout监听
*/
internal inner class AdapterDataSetObserver : DataSetObserver() {
override fun onChanged() {
super.onChanged()
reloadData()
}
override fun onInvalidated() {
super.onInvalidated()
}
}
/**
* 实例化布局类型
*/
private fun initLayoutType() {
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
mControlScrollView.removeAllViews()
mRecyclerView = RecyclerView(mContext)
mControlScrollView.addView(mRecyclerView)
}
LayoutTypeMode.FlowLayout.index -> {
mControlScrollView.removeAllViews()
mFlowLayout = FlowLayout(mContext)
mControlScrollView.addView(mFlowLayout)
mFlowLayout.setSpace(tagsHorizontalSpace, tagsVerticalSpace)
}
else -> {
Toast.makeText(mContext, "Un know ", Toast.LENGTH_SHORT).show()
}
}
}
/**
*
* @return Int
*/
private fun getLineHeight(): Int {
var itemHeight: Int = 0 //每一个item 的高度
var spaceHeight: Int = 0; //间隔间距
var spacing: Int = 0 //分割线高度,如果设置了分割线,计算item 的高度需要加上
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
val childCount: Int = mRecyclerView.childCount
println(childCount)
val childView = mRecyclerView.getChildAt(0)
println(childView)
val itemDecorationCount: Int = mRecyclerView.itemDecorationCount
if (itemDecorationCount > 0) {
if (mRecyclerView.layoutManager is GridLayoutManager) {
val itemDecoration: ItemDecoration = mRecyclerView.getItemDecorationAt(0)
val gridLayoutManager: GridLayoutManager =
mRecyclerView.layoutManager as GridLayoutManager
if (gridLayoutManager.orientation == GridLayoutManager.VERTICAL) {
if (itemDecoration is GridLayoutItemDecoration) {
val gridLayoutItemDecoration: GridLayoutItemDecoration =
itemDecoration as GridLayoutItemDecoration
spacing = gridLayoutItemDecoration.getSpaceHeight()
} else {
spacing = 0
}
}
}
}
if (childView != null) {
//子view 的高度
itemHeight = childView.measuredHeight
//获取设置子view 内外间距的尺寸
spaceHeight = childView.marginTop + childView.marginBottom
//计算整个item 的高度
itemHeight = (itemHeight + spaceHeight + spacing)
println(itemHeight)
}
}
LayoutTypeMode.FlowLayout.index -> {
itemHeight = mFlowLayout.getLineHeight() + tagsVerticalSpace
}
else -> {
itemHeight = 0
}
}
return itemHeight
}
/**
*
* @param adapter Any
*/
fun setAdapter(adapter: Any) {
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
if (adapter is RecyclerView.Adapter<*>) {
this.mRecyclerViewAdapter = adapter as RecyclerView.Adapter<*>
mRecyclerView.adapter = mRecyclerViewAdapter
if (mRecyclerViewAdapter != null && mRecyclerViewAdapterDataSetObserver != null) {
this.mRecyclerViewAdapter!!.unregisterAdapterDataObserver(
mRecyclerViewAdapterDataSetObserver!!
)
}
if (this.mRecyclerViewAdapter != null) {
mRecyclerViewAdapterDataSetObserver = RecyclerViewAdapterDataSetObserver()
this.mRecyclerViewAdapter!!.registerAdapterDataObserver(
mRecyclerViewAdapterDataSetObserver!!
)
reloadData()
}
}
}
LayoutTypeMode.FlowLayout.index -> {
if (adapter is BaseTagAdapter<*>) {
this.mTagAdapter = adapter as BaseTagAdapter<*>
if (mTagAdapter != null && mAdapterDataSetObserver != null) {
this.mTagAdapter?.unregisterDataSetObserver(mAdapterDataSetObserver)
}
if (this.mTagAdapter != null) {
mAdapterDataSetObserver = AdapterDataSetObserver()
this.mTagAdapter!!.registerDataSetObserver(mAdapterDataSetObserver)
reloadData()
}
}
}
else -> {
}
}
}
/**
* 获取适配器
*/
private fun getAdapter(): Any? {
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
return mRecyclerViewAdapter as Any
}
LayoutTypeMode.FlowLayout.index -> {
return mTagAdapter as Any
}
else -> {
return null
}
}
}
/**
* 刷新数据
*/
fun notifyDataSetChanged() {
when (mLayoutType) {
LayoutTypeMode.RecyclerView.index -> {
mRecyclerViewAdapter?.notifyDataSetChanged()
}
LayoutTypeMode.FlowLayout.index -> {
mTagAdapter?.notifyDataSetChanged()
}
else -> {
}
}
//标识:刷新数据 isNotifyData=true
isNotifyData = true
}
/**
* 获取列表对象
* @return RecyclerView
*/
fun getRecyclerView(): RecyclerView {
return mRecyclerView
}
/**
* 获取流逝布局对象
* @return FlowLayout
*/
fun getFlowLayout(): FlowLayout {
return mFlowLayout
}
/**
* 获取展开后显示的提示文字
* @return String
*/
fun getFoldHint(): String {
return foldHint
}
/**
* 设置展开后显示的提示文字
* @param foldHint String
*/
fun setFoldHint(foldHint: String) {
this.foldHint = foldHint
if (isFolded) {
mTvMoreHint.text = foldHint
}
}
/**
* 获取展开文字
* @return String
*/
fun getExpandHint(): String {
return expandHint
}
/**
* 设置展开后的文字
* @param expandHint String
*/
fun setExpandHint(expandHint: String) {
this.expandHint = expandHint
if (!isFolded) {
mTvMoreHint.text = expandHint
}
}
/**
* 获取动画时间
* @return Int
*/
fun getAnimationDuration(): Int {
return animationDuration
}
/**
* 设置动画时间
* @param animationDuration Int
*/
fun setAnimationDuration(animationDuration: Int) {
this.animationDuration = animationDuration
}
/**
*
* @return Boolean
*/
fun isCanScroll(): Boolean {
return mControlScrollView.isCanScroll()
}
/**
* 设置是否退出内部标签容器
* @param can Boolean
*/
fun setCanScroll(can: Boolean) {
mControlScrollView.setCanScroll(can)
}
fun setForceFixed(fixed: Boolean) {
mControlScrollView.setForceFixed(fixed)
}
/**
* 获取FlowLayout 点击模式
* @return Int
*/
fun getItemModel(): Int {
return itemModel
}
/**
* 设置FlowLayout 点击模式,作为点击的标识
* @param itemModel Int
*/
fun setItemModel(@ItemMode itemModel: Int) {
this.itemModel = itemModel
reloadData()
}
/**
* 获取水平间距
* @return Int
*/
fun getTagsHorizontalSpace(): Int {
return tagsHorizontalSpace
}
/**
* 设置水平间距
* @param tagsHorizontalSpace Int
*/
fun setTagsHorizontalSpace(tagsHorizontalSpace: Int) {
this.tagsHorizontalSpace = tagsHorizontalSpace
}
/**
* 获取垂直间距
* @return Int
*/
fun getTagsVerticalSpace(): Int {
return tagsVerticalSpace
}
/**
* 设置垂直间距
* @param tagsVerticalSpace Int
*/
fun setTagsVerticalSpace(tagsVerticalSpace: Int) {
this.tagsVerticalSpace = tagsVerticalSpace
}
/**
* 格式化字符
* @param str
* @param defaultString
* @return
*/
private fun formatString(str: String?, defaultString: String): String {
return if (str.isNullOrEmpty()) {
defaultString
} else {
str
}
}
/******************************************************* set listener *********************************************************************/
fun setOnTagClickListener(onTagClickListener: OnTagClickListener) = apply {
this.mOnTagClickListener = onTagClickListener
if (mTagAdapter != null) {
reloadData()
}
}
open fun setSelectedListener(selectedListener: OnTagSelectedListener?) {
this.mSelectedListener = selectedListener
if (mTagAdapter != null) {
reloadData()
}
}
}
\ No newline at end of file
package com.framework.tagflow.adapter
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import com.framework.tagflow.bean.BaseTagBean
abstract class BaseTagAdapter<T> : BaseAdapter() {
private var dataList: MutableList<T> = mutableListOf()
override fun getCount(): Int {
return dataList.size
}
override fun getItem(position: Int): T {
return dataList[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
abstract override fun getView(position: Int, convertView: View?, parent: ViewGroup): View
fun getData(): List<T> {
return dataList
}
/**
* 增加一条数据
* @param dataList T
*/
fun addData(dataList: T) {
this.dataList.add(dataList)
notifyDataSetChanged()
}
/**
* 增加列表
* @param dataList List<T>?
*/
fun addAllList(dataList: List<T>?) {
this.dataList.clear()
if (null != dataList) {
this.dataList.addAll(dataList)
}
notifyDataSetChanged()
}
/**
*
*/
open fun select(position: Int) {
if (position < 0 || position >= dataList.size) {
return
}
if(dataList[position] is BaseTagBean){
(dataList[position] as BaseTagBean).setIsSelected(true)
}
}
/**
*
*/
open fun unSelect(position: Int) {
if (position < 0 || position >= dataList.size) {
return
}
if(dataList[position] is BaseTagBean){
(dataList[position] as BaseTagBean).setIsSelected(false)
}
}
}
\ No newline at end of file
package com.framework.tagflow.bean
/**
* @author: xiaxueyi
* @date: 2022-09-16
* @time: 16:02
* @说明:
*/
open class BaseTagBean {
private var id = 0
private var title: String? = null
private var isSelected = false//是否选中
private var tag: Any? = null //标签额外信息
fun getId(): Int {
return id
}
fun setId(id: Int) {
this.id = id
}
fun getTitle(): String? {
return title
}
fun setTitle(title: String?) {
this.title = title
}
fun getTag(): Any? {
return tag
}
fun setTag(tag: Any?) {
this.tag = tag
}
fun isSelected(): Boolean {
return isSelected
}
fun setIsSelected(selected: Boolean) {
this.isSelected = selected
}
}
\ No newline at end of file
package com.framework.tagflow.interfac
import android.view.View
/**
* @author: xiaxueyi
* @date: 2022-09-13
* @time: 15:30
* @说明:
*/
interface OnTagClickListener {
fun onClick(view: View?, position: Int)
fun onLongClick(view: View?, position: Int)
}
\ No newline at end of file
package com.framework.tagflow.interfac
import android.view.View
import com.framework.tagflow.bean.BaseTagBean
/**
* @author: xiaxueyi
* @date: 2022-09-13
* @time: 15:30
* @说明:标签被选中或取消选中监听
*/
interface OnTagSelectedListener {
fun selected(view: View?, position: Int, selected: List<BaseTagBean?>?)
fun unSelected(view: View?, position: Int, selected: List<BaseTagBean?>?)
}
\ No newline at end of file
package com.framework.tagflow.tags
import android.content.Context
import android.util.AttributeSet
/**
* @author: xiaxueyi
* @date: 2022-09-19
* @time: 16:02
* @说明:
*/
class ColorfulStrokeTagView : ColorfulTagView {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
}
override fun isSolid(): Boolean {
return false
}
override fun getStrokeWidth(): Float {
return 1F
}
}
\ No newline at end of file
package com.framework.tagflow.tags
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import java.util.*
/**
* @author: xiaxueyi
* @date: 2022-09-16
* @time: 16:02
* @说明:
*/
open class ColorfulTagView : DefaultTagView {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
}
override fun getNormalBackgroundColor(): Int {
val random = Random()
val red = random.nextInt(200) + 50
val green = random.nextInt(200) + 50
val blue = random.nextInt(200) + 50
return Color.rgb(red, green, blue)
}
}
\ No newline at end of file
package com.framework.tagflow.tags
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.StateListDrawable
import android.util.AttributeSet
import android.view.Gravity
import androidx.annotation.ColorInt
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import com.framework.tagflow.R
import com.framework.tagflow.utils.DensityUtils
/**
* @author: xiaxueyi
* @date: 2022-09-16
* @time: 16:02
* @说明:
*/
open class DefaultTagView @JvmOverloads constructor(
protected var mContext: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatTextView(
mContext, attrs, defStyleAttr
) {
//默认标签内间距
private val DEFAULT_TAG_PADDING = 5f
//默认标签背景圆角大小
private val DEFAULT_TAG_CORNER = 3f
//默认边框宽度(仅在非实心背景有效),单位dp
private val DEFAULT_TAG_STROKE = 1f
//默认标签背景正常颜色
private val DEFAULT_TAG_BACKGROUND_COLOR = -0x1
//默认标签背景按下颜色
private val DEFAULT_TAG_BACKGROUND_PRESSED_COLOR = -0x68bba4
private fun init() {
val padding: Int = DensityUtils.dp2px(mContext, getTagPadding())
setPadding(padding, padding, padding, padding)
gravity = Gravity.CENTER
setBackgroundDrawable(getBackgroundDrawable())
}//设置字体颜色的选择器
//完全自定义tag的样式请重写此方法
//返回一个Drawable背景样式
protected open fun getBackgroundDrawable(): Drawable? {
//设置字体颜色的选择器
val colorSateList =ContextCompat.getColorStateList(context,R.color.secondary_text)
setTextColor(colorSateList)
val normal = GradientDrawable()
normal.shape = GradientDrawable.RECTANGLE
normal.cornerRadius = DensityUtils.dp2px(mContext, getTagRadius()).toFloat()
if (isSolid()) {
normal.setColor(getNormalBackgroundColor())
} else {
normal.setStroke(
DensityUtils.dp2px(mContext, getStrokeWidth()),
getNormalBackgroundColor()
)
normal.setColor(getBackgroundColor())
}
val pressed = GradientDrawable()
pressed.shape = GradientDrawable.RECTANGLE
pressed.cornerRadius = DensityUtils.dp2px(mContext, getTagRadius()).toFloat()
if (isSolid()) {
pressed.setColor(getPressedBackgroundColor())
} else {
pressed.setStroke(
DensityUtils.dp2px(mContext, getStrokeWidth()),
getPressedBackgroundColor()
)
pressed.setColor(getPressedBackgroundColor())
}
val selector = StateListDrawable()
selector.addState(intArrayOf(android.R.attr.state_pressed), pressed)
selector.addState(intArrayOf(), normal)
return selector
}
//默认tag背景颜色
@ColorInt
protected open fun getNormalBackgroundColor(): Int {
return DEFAULT_TAG_BACKGROUND_COLOR
}
//按下tag时背景颜色
@ColorInt
protected open fun getPressedBackgroundColor(): Int {
return DEFAULT_TAG_BACKGROUND_PRESSED_COLOR
}
//tag的圆角角度
protected open fun getTagRadius(): Float {
return DEFAULT_TAG_CORNER
}
//tag内间距
protected open fun getTagPadding(): Float {
return DEFAULT_TAG_PADDING
}
/***
* 是否为实心背景
*
* @return true:实心的,false:空心,可通过[.getStrokeWidth]设置边框宽度
*/
protected open fun isSolid(): Boolean {
return true
}
//设置边框的宽度,单位dp
protected open fun getStrokeWidth(): Float {
return DEFAULT_TAG_STROKE
}
//当设置了空心加边框的tag时给tag加一个背景,
//防止在透明背景上无法显示点击颜色
@ColorInt
protected open fun getBackgroundColor(): Int {
return DEFAULT_TAG_BACKGROUND_COLOR
}
init {
init()
}
}
\ No newline at end of file
package com.framework.tagflow.tags
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.StateListDrawable
import android.util.AttributeSet
import androidx.core.content.ContextCompat
import com.framework.tagflow.R
import com.framework.tagflow.utils.DensityUtils
/**
* @author: xiaxueyi
* @date: 2022-09-16
* @time: 15:02
* @说明:
*/
class MutSelectedTagView : DefaultTagView {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
}
override fun getBackgroundDrawable(): Drawable? {
//设置字体颜色的选择器
val colorSateList = ContextCompat.getColorStateList(context,R.color.secondary_text)
setTextColor(colorSateList)
val normal = GradientDrawable()
normal.shape = GradientDrawable.RECTANGLE
normal.cornerRadius = DensityUtils.dp2px(mContext, getTagRadius()).toFloat()
if (isSolid()) {
normal.setColor(getNormalBackgroundColor())
} else {
normal.setStroke(
DensityUtils.dp2px(mContext, getStrokeWidth()),
getNormalBackgroundColor()
)
normal.setColor(getBackgroundColor())
}
val pressed = GradientDrawable()
pressed.shape = GradientDrawable.RECTANGLE
pressed.cornerRadius = DensityUtils.dp2px(mContext, getTagRadius()).toFloat()
if (isSolid()) {
pressed.setColor(getPressedBackgroundColor())
} else {
pressed.setStroke(
DensityUtils.dp2px(mContext, getStrokeWidth()),
getPressedBackgroundColor()
)
pressed.setColor(getPressedBackgroundColor())
}
val selector = StateListDrawable()
selector.addState(intArrayOf(android.R.attr.state_pressed), pressed)
selector.addState(intArrayOf(android.R.attr.state_selected), pressed)
selector.addState(intArrayOf(), normal)
return selector
}
fun toggle() {
this.isSelected = !isSelected
}
}
\ No newline at end of file
package com.aa.cat.ui.view.tagFlow.tags
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import com.framework.tagflow.tags.DefaultTagView
/**
* @author: xiaxueyi
* @date: 2022-09-16
* @time: 11:02
* @说明:
*/
class StrokeTagView : DefaultTagView {
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
}
override fun isSolid(): Boolean {
return false
}
override fun getStrokeWidth(): Float {
return 1F
}
override fun getNormalBackgroundColor(): Int {
return Color.parseColor("#000000")
}
override fun getPressedBackgroundColor(): Int {
return Color.parseColor("#aa666666")
}
}
\ No newline at end of file
package com.framework.tagflow.utils
import android.content.Context
import android.util.TypedValue
/**
* @author: xiaxueyi
* @date: 2022-09-19
* @time: 13:02
* @说明:
*/
class DensityUtils private constructor() {
companion object {
/**
* dp转px
*
* @param context 上下文
* @param dpVal dp值
* @return result in px
*/
fun dp2px(context: Context, dpVal: Float): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dpVal, context.resources.displayMetrics
).toInt()
}
/**
* sp转px
*
* @param context 上下文
* @param spVal sp值
* @return result in px
*/
fun sp2px(context: Context, spVal: Float): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
spVal, context.resources.displayMetrics
).toInt()
}
/**
* px转dp
*
* @param context 上下文
* @param pxVal px值
* @return result in dp
*/
fun px2dp(context: Context, pxVal: Float): Float {
val scale = context.resources.displayMetrics.density
return pxVal / scale
}
/**
* px转sp
*
* @param context 上下文
* @param pxVal px值
* @return result in sp
*/
fun px2sp(context: Context, pxVal: Float): Float {
return pxVal / context.resources.displayMetrics.scaledDensity
}
}
init {
/* cannot be instantiated */
throw UnsupportedOperationException("cannot be instantiated")
}
}
\ No newline at end of file
package com.framework.tagflow.view
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ScrollView
/**
* 可控制滑动,可控制固定
*/
class ControlScrollView : ScrollView {
private var forceFixed = false//强制固定
private var canScroll = false
constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
/**
* 是否可以滑动
* @return
*/
fun isCanScroll(): Boolean {
return canScroll
}
/**
* 设置是否可以滑动
* @param isCan
*/
fun setCanScroll(isCan: Boolean) {
canScroll = isCan
}
/**
* 是否强制固定
* @return
*/
fun isForceFixed(): Boolean {
return forceFixed
}
/**
* 设置是否强制固定
* @param forceFixed
*/
fun setForceFixed(forceFixed: Boolean) {
this.forceFixed = forceFixed
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
if (!forceFixed && canScroll) {
parent.requestDisallowInterceptTouchEvent(true)
}
return super.dispatchTouchEvent(event)
}
}
\ No newline at end of file
package com.framework.tagflow.view
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import com.framework.tagflow.utils.DensityUtils
open class FlowLayout : ViewGroup {
private var mContext: Context? = null
private var mLines: MutableList<Line> = ArrayList() // 记录当前有多少行
private var horizontalSpace = 0
private var verticalSpace = 0
private var mDefaultViewMaxWidth:Int=100 //子view默认宽度的最大值
private var mDefaultColumn:Int=3;//默认列数三列
private var mAverageWidth:Int=0 // 存储屏幕的1/3宽度
private var isNeedMinimumWidth:Boolean=true //是否需要最小宽度值
/**
*
* @param context Context?
* @constructor
*/
constructor(context: Context?) : super(context) {
mContext = context
}
/**
*
* @param context Context?
* @param attrs AttributeSet?
* @constructor
*/
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
/**
*
* @param horizontalSpace Int
* @param verticalSpace Int
*/
fun setSpace(horizontalSpace: Int, verticalSpace: Int) {
this.horizontalSpace = horizontalSpace
this.verticalSpace = verticalSpace
}
/**
* 获取单行的高度
* @return
*/
fun getLineHeight(): Int {
return if (mLines.size > 0) {
mLines[0].height
} else{
0
}
}
/**
* 获取行数
* @return
*/
fun getLineSize(): Int {
return if (mLines.size > 0) {
mLines.size
} else {
0
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var top = this.paddingTop
for (i in mLines.indices) {
val line = mLines[i]
// 自己布局
line.layout(top, this.paddingStart)
top += line.height
if (i != mLines.size - 1) {
top += verticalSpace
}
}
}
@SuppressLint("DrawAllocation")
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
// 清空
mLines.clear()
var mCurrentLine: Line? = null
// 获得容器的宽度
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
//获取最大的宽
val maxWidth = widthSize - this.paddingStart - this.paddingEnd
//子类的数量
val childCount = this.childCount
//计算屏幕的三分之一宽度
mAverageWidth=maxWidth/mDefaultColumn
for (i in 0 until childCount) {
val view = getChildAt(i)
if (view.visibility == GONE) {
continue
}
if(isNeedMinimumWidth){
val min = widthSize.coerceAtMost(DensityUtils.dp2px(context, mDefaultViewMaxWidth.toFloat()))
view.minimumWidth=min
}
// 测量孩子
measureChild(view, widthMeasureSpec, heightMeasureSpec)
// 将孩子记录到行中
if (mCurrentLine == null) {
// 新建行
mCurrentLine = Line(maxWidth, horizontalSpace)
// 记录行
mLines.add(mCurrentLine)
// 给行添加孩子
mCurrentLine.addView(view)
} else {
// 判断是否可以添加
if (mCurrentLine.canAdd(view)) {
// 可以添加
mCurrentLine.addView(view)
} else {
// 不可以添加
// 新建一行
mCurrentLine = Line(maxWidth, horizontalSpace)
// 记录行
mLines.add(mCurrentLine)
// 给行添加孩子
mCurrentLine.addView(view)
}
}
}
// 设置自己的宽度和高度
var measuredHeight = this.paddingTop + this.paddingBottom
// 添加行的高度
for (i in mLines.indices) {
measuredHeight += mLines[i].height
}
// 间距
measuredHeight += (mLines.size - 1) * verticalSpace
// 设置自己的宽度和高度
setMeasuredDimension(widthSize, measuredHeight)
}
private inner class Line(
private var maxWidth: Int,// 行最大宽度
private var space: Int // view和view之间的间隔
) {
// 属性,方法,构造
// 行中的控件
private val mViews: MutableList<View> = ArrayList()
private var usedWidth = 0// 已经使用的宽度
var height = 0 // 行的高度
/**
*
* @param top Int
* @param left Int
*/
fun layout(top: Int, left: Int) {
// 给view布局
var mleft = left
for (i in mViews.indices) {
val view = mViews[i]
var viewWidth = view.measuredWidth
var viewHeight = view.measuredHeight
view.measure(MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY))
viewWidth = view.measuredWidth
viewHeight = view.measuredHeight
val avgHeight = ((height - viewHeight) / 2f + 0.5f).toInt()
val vLeft = mleft
val vTop = top + avgHeight
val vRight = vLeft + viewWidth
val vBottom = vTop + viewHeight
view.layout(vLeft, vTop, vRight, vBottom)
mleft += space + viewWidth
}
}
/**
* 添加view的方法
*
* @param view
*/
fun addView(view: View) {
val viewWidth = view.measuredWidth
val viewHeight = view.measuredHeight
if (mViews.size == 0) {
if (viewWidth > maxWidth) {
usedWidth = maxWidth
height = viewHeight
} else {
usedWidth = viewWidth
height = viewHeight
}
} else {
usedWidth += space + viewWidth
height = if (height > viewHeight) height else viewHeight // 选择大的高度
}
mViews.add(view)
}
/**
* 判断是否可以往行中添加控件
*
* @param view
*/
fun canAdd(view: View): Boolean {
if (mViews.size == 0) {
return true
}
// 已经使用的 + 间距+ 要加的view的宽度 > maxWidth ,添加不进来
// return usedWidth + space + view.measuredWidth <= maxWidth
return usedWidth+ view.measuredWidth <= maxWidth
}
}
fun clearAllView() {
mLines = ArrayList()
this.invalidate()
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_F5F3F0" />
<stroke android:width="@dimen/dp_1"
android:color="@color/color_CCC8C2"/>
<corners android:radius="@dimen/dp_30" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_8"/>
<solid android:color="#80000000"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="@dimen/dp_15" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white" />
<corners android:radius="@dimen/dp_0" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_F5F3F0" />
<stroke android:width="@dimen/dp_1"
android:color="@color/color_CCC8C2"/>
<corners android:radius="@dimen/dp_30" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp_8"/>
<solid android:color="#80000000"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--toast Textview-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ad_hoc_toast_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_15"
android:paddingEnd="@dimen/dp_15"
android:paddingTop="@dimen/dp_12"
android:paddingBottom="@dimen/dp_12"
android:layout_margin="@dimen/dp_20"
android:background="@drawable/toast_background"
android:textColor="#1e1e1e"
android:gravity="center"
android:visibility="visible"
android:layout_alignParentBottom="true"
tools:text="message ..." />
\ No newline at end of file
<?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:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@color/color_transparent"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:textColor="@color/color_333333"
android:textSize="@dimen/sp_15"
android:textStyle="normal"
android:text="暂无数据"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll_tag_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fl_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:visibility="gone"/>
<com.framework.tagflow.view.ControlScrollView
android:id="@+id/hsv_tag_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
<LinearLayout
android:id="@+id/rl_show_more"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="@dimen/dp_3">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="auto"
android:gravity="center"
android:layout_margin="@dimen/dp_2"
android:paddingStart="@dimen/dp_5"
android:paddingEnd="@dimen/dp_5">
<TextView
android:id="@+id/tv_more_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/expandHint"
android:textStyle="bold"
android:textColor="#262626"
android:textSize="@dimen/sp_14"
android:layout_gravity="center"
android:layout_marginStart="@dimen/dp_5"
android:layout_marginEnd="@dimen/dp_5"
android:gravity="center"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_arrow_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/common_icon_down_arrow" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</merge>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--流布局-->
<declare-styleable name="TagFlowLayout">
<attr name="tagsHorizontalSpace" format="dimension" />
<attr name="tagsVerticalSpace" format="dimension" />
<attr name="animationDuration" format="integer" />
<attr name="hasMore" format="boolean" />
<attr name="foldHint" format="reference|string" />
<attr name="expandHint" format="reference|string" />
<!--布局类型,列表或者-->
<attr name="layout_type" format="reference">
<enum name="RecyclerView" value="0" />
<enum name="FlowLayout" value="1" />
</attr>
<!--LayoutManager 模式-->
<attr name="layoutManager_Mode" format="reference">
<enum name="LinearLayoutManager" value="0"/>
<enum name="GridLayoutManager" value="1"/>
</attr>
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- text color -->
<color name="color_4D4D4D">#4D4D4D</color>
<color name="color_333333">#333333</color>
<color name="color_FCFCFC">#FCFCFC</color>
<color name="color_808080">#808080</color>
<!-- image color -->
<color name="color_D6D0C7">#D6D0C7</color>
<color name="color_E8E4DF">#E8E4DF</color>
<color name="color_F5B95F">#F5B95F</color>
<color name="color_F8E49E">#F8E49E</color>
<color name="color_959595">#959595</color>
<!-- bg color -->
<color name="color_F2FFFFFF">#F2FFFFFF</color>
<color name="color_11AB9B">#11AB9B</color>
<color name="color_EF6A39">#EF6A39</color>
<color name="color_F0E4D3">#F0E4D3</color>
<color name="color_F0EDE9">#F0EDE9</color>
<color name="color_F0E8DE">#F0E8DE</color>
<color name="color_f6Ce7e">#f6Ce7e</color>
<color name="color_FFFDFA">#FFFDFA</color>
<color name="color_FFFFFF">#FFFFFF</color>
<color name="color_FAF9F7">#FAF9F7</color>
<color name="color_F5A05F">#f5a05f</color>
<!-- shadow color-->
<color name="color_F5F3F0">#F5F3F0</color>
<color name="white">#FFFFFF</color>
<color name="color_8C8B89">#8C8B89</color>
<!--Line-->
<color name="color_CCC8C2">#33CCC8C2</color>
<color name="color_8A8A8A">#8a8a8a</color>
<color name="color_EAEAEA">#EAEAEA</color>
<!--tagflow-->
<color name="secondary_text">#8a000000</color>
<color name="tag_layout_bg">#def2f2f2</color>
<color name="dividers">#1f000000</color>
<!--标题搜索框背景颜色-->
<color name="common_toolbar_search_bg_color">#208C8B89</color>
<!--标题搜索框说明性文字颜色-->
<color name="common_toolbar_search_title_hint_text_color">#7f7f7f</color>
<color name="color_transparent">#00000000</color>
<!-- 彈窗 -->
<color name="list_line_color">#ccc8c2</color>
<color name="color_8a8894">#8a8894</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="text_size_15_sp">15sp</dimen>
<dimen name="dp_0">0dp</dimen>
<dimen name="dp_0_1">0.1dp</dimen>
<dimen name="dp_0_5">0.5dp</dimen>
<dimen name="dp_1">1dp</dimen>
<dimen name="dp_1_5">1.5dp</dimen>
<dimen name="dp_2">2dp</dimen>
<dimen name="dp_2_5">2.5dp</dimen>
<dimen name="dp_3">3dp</dimen>
<dimen name="dp_3_5">3.5dp</dimen>
<dimen name="dp_4">4dp</dimen>
<dimen name="dp_4_5">4.5dp</dimen>
<dimen name="dp_5">5dp</dimen>
<dimen name="dp_6">6dp</dimen>
<dimen name="dp_7">7dp</dimen>
<dimen name="dp_7_5">7.5dp</dimen>
<dimen name="dp_8">8dp</dimen>
<dimen name="dp_9">9dp</dimen>
<dimen name="dp_10">10dp</dimen>
<dimen name="dp_11">11dp</dimen>
<dimen name="dp_12">12dp</dimen>
<dimen name="dp_13">13dp</dimen>
<dimen name="dp_14">14dp</dimen>
<dimen name="dp_15">15dp</dimen>
<dimen name="dp_16">16dp</dimen>
<dimen name="dp_17">17dp</dimen>
<dimen name="dp_18">18dp</dimen>
<dimen name="dp_19">19dp</dimen>
<dimen name="dp_20">20dp</dimen>
<dimen name="dp_21">21dp</dimen>
<dimen name="dp_22">22dp</dimen>
<dimen name="dp_23">23dp</dimen>
<dimen name="dp_24">24dp</dimen>
<dimen name="dp_25">25dp</dimen>
<dimen name="dp_26">26dp</dimen>
<dimen name="dp_27">27dp</dimen>
<dimen name="dp_28">28dp</dimen>
<dimen name="dp_29">29dp</dimen>
<dimen name="dp_30">30dp</dimen>
<dimen name="dp_31">31dp</dimen>
<dimen name="dp_32">32dp</dimen>
<dimen name="dp_33">33dp</dimen>
<dimen name="dp_34">34dp</dimen>
<dimen name="dp_35">35dp</dimen>
<dimen name="dp_36">36dp</dimen>
<dimen name="dp_37">37dp</dimen>
<dimen name="dp_38">38dp</dimen>
<dimen name="dp_39">39dp</dimen>
<dimen name="dp_40">40dp</dimen>
<dimen name="dp_41">41dp</dimen>
<dimen name="dp_42">42dp</dimen>
<dimen name="dp_43">43dp</dimen>
<dimen name="dp_44">44dp</dimen>
<dimen name="dp_45">45dp</dimen>
<dimen name="dp_46">46dp</dimen>
<dimen name="dp_47">47dp</dimen>
<dimen name="dp_48">48dp</dimen>
<dimen name="dp_49">49dp</dimen>
<dimen name="dp_50">50dp</dimen>
<dimen name="dp_51">51dp</dimen>
<dimen name="dp_52">52dp</dimen>
<dimen name="dp_53">53dp</dimen>
<dimen name="dp_54">54dp</dimen>
<dimen name="dp_55">55dp</dimen>
<dimen name="dp_56">56dp</dimen>
<dimen name="dp_57">57dp</dimen>
<dimen name="dp_58">58dp</dimen>
<dimen name="dp_59">59dp</dimen>
<dimen name="dp_60">60dp</dimen>
<dimen name="dp_61">61dp</dimen>
<dimen name="dp_62">62dp</dimen>
<dimen name="dp_63">63dp</dimen>
<dimen name="dp_64">64dp</dimen>
<dimen name="dp_65">65dp</dimen>
<dimen name="dp_66">66dp</dimen>
<dimen name="dp_67">67dp</dimen>
<dimen name="dp_68">68dp</dimen>
<dimen name="dp_69">69dp</dimen>
<dimen name="dp_70">70dp</dimen>
<dimen name="dp_71">71dp</dimen>
<dimen name="dp_72">72dp</dimen>
<dimen name="dp_73">73dp</dimen>
<dimen name="dp_74">74dp</dimen>
<dimen name="dp_75">75dp</dimen>
<dimen name="dp_76">76dp</dimen>
<dimen name="dp_77">77dp</dimen>
<dimen name="dp_78">78dp</dimen>
<dimen name="dp_79">79dp</dimen>
<dimen name="dp_80">80dp</dimen>
<dimen name="dp_81">81dp</dimen>
<dimen name="dp_82">82dp</dimen>
<dimen name="dp_83">83dp</dimen>
<dimen name="dp_84">84dp</dimen>
<dimen name="dp_85">85dp</dimen>
<dimen name="dp_86">86dp</dimen>
<dimen name="dp_87">87dp</dimen>
<dimen name="dp_88">88dp</dimen>
<dimen name="dp_89">89dp</dimen>
<dimen name="dp_90">90dp</dimen>
<dimen name="dp_91">91dp</dimen>
<dimen name="dp_92">92dp</dimen>
<dimen name="dp_93">93dp</dimen>
<dimen name="dp_94">94dp</dimen>
<dimen name="dp_95">95dp</dimen>
<dimen name="dp_96">96dp</dimen>
<dimen name="dp_97">97dp</dimen>
<dimen name="dp_98">98dp</dimen>
<dimen name="dp_99">99dp</dimen>
<dimen name="dp_100">100dp</dimen>
<dimen name="dp_101">101dp</dimen>
<dimen name="dp_102">102dp</dimen>
<dimen name="dp_103">103dp</dimen>
<dimen name="dp_104">104dp</dimen>
<dimen name="dp_104_5">104.5dp</dimen>
<dimen name="dp_105">105dp</dimen>
<dimen name="dp_106">106dp</dimen>
<dimen name="dp_107">107dp</dimen>
<dimen name="dp_108">108dp</dimen>
<dimen name="dp_109">109dp</dimen>
<dimen name="dp_110">110dp</dimen>
<dimen name="dp_111">111dp</dimen>
<dimen name="dp_112">112dp</dimen>
<dimen name="dp_113">113dp</dimen>
<dimen name="dp_114">114dp</dimen>
<dimen name="dp_115">115dp</dimen>
<dimen name="dp_116">116dp</dimen>
<dimen name="dp_117">117dp</dimen>
<dimen name="dp_118">118dp</dimen>
<dimen name="dp_119">119dp</dimen>
<dimen name="dp_120">120dp</dimen>
<dimen name="dp_121">121dp</dimen>
<dimen name="dp_122">122dp</dimen>
<dimen name="dp_123">123dp</dimen>
<dimen name="dp_124">124dp</dimen>
<dimen name="dp_125">125dp</dimen>
<dimen name="dp_126">126dp</dimen>
<dimen name="dp_127">127dp</dimen>
<dimen name="dp_128">128dp</dimen>
<dimen name="dp_129">129dp</dimen>
<dimen name="dp_130">130dp</dimen>
<dimen name="dp_131">131dp</dimen>
<dimen name="dp_132">132dp</dimen>
<dimen name="dp_133">133dp</dimen>
<dimen name="dp_134">134dp</dimen>
<dimen name="dp_134_5">134.5dp</dimen>
<dimen name="dp_135">135dp</dimen>
<dimen name="dp_136">136dp</dimen>
<dimen name="dp_137">137dp</dimen>
<dimen name="dp_138">138dp</dimen>
<dimen name="dp_139">139dp</dimen>
<dimen name="dp_140">140dp</dimen>
<dimen name="dp_141">141dp</dimen>
<dimen name="dp_142">142dp</dimen>
<dimen name="dp_143">143dp</dimen>
<dimen name="dp_144">144dp</dimen>
<dimen name="dp_145">145dp</dimen>
<dimen name="dp_146">146dp</dimen>
<dimen name="dp_147">147dp</dimen>
<dimen name="dp_148">148dp</dimen>
<dimen name="dp_149">149dp</dimen>
<dimen name="dp_150">150dp</dimen>
<dimen name="dp_151">151dp</dimen>
<dimen name="dp_152">152dp</dimen>
<dimen name="dp_153">153dp</dimen>
<dimen name="dp_154">154dp</dimen>
<dimen name="dp_155">155dp</dimen>
<dimen name="dp_156">156dp</dimen>
<dimen name="dp_157">157dp</dimen>
<dimen name="dp_158">158dp</dimen>
<dimen name="dp_159">159dp</dimen>
<dimen name="dp_160">160dp</dimen>
<dimen name="dp_161">161dp</dimen>
<dimen name="dp_162">162dp</dimen>
<dimen name="dp_163">163dp</dimen>
<dimen name="dp_164">164dp</dimen>
<dimen name="dp_165">165dp</dimen>
<dimen name="dp_166">166dp</dimen>
<dimen name="dp_167">167dp</dimen>
<dimen name="dp_168">168dp</dimen>
<dimen name="dp_169">169dp</dimen>
<dimen name="dp_170">170dp</dimen>
<dimen name="dp_171">171dp</dimen>
<dimen name="dp_172">172dp</dimen>
<dimen name="dp_173">173dp</dimen>
<dimen name="dp_174">174dp</dimen>
<dimen name="dp_175">175dp</dimen>
<dimen name="dp_176">176dp</dimen>
<dimen name="dp_177">177dp</dimen>
<dimen name="dp_178">178dp</dimen>
<dimen name="dp_179">179dp</dimen>
<dimen name="dp_180">180dp</dimen>
<dimen name="dp_181">181dp</dimen>
<dimen name="dp_182">182dp</dimen>
<dimen name="dp_183">183dp</dimen>
<dimen name="dp_184">184dp</dimen>
<dimen name="dp_185">185dp</dimen>
<dimen name="dp_186">186dp</dimen>
<dimen name="dp_187">187dp</dimen>
<dimen name="dp_188">188dp</dimen>
<dimen name="dp_189">189dp</dimen>
<dimen name="dp_190">190dp</dimen>
<dimen name="dp_191">191dp</dimen>
<dimen name="dp_191_25">191.25dp</dimen>
<dimen name="dp_192">192dp</dimen>
<dimen name="dp_193">193dp</dimen>
<dimen name="dp_194">194dp</dimen>
<dimen name="dp_195">195dp</dimen>
<dimen name="dp_196">196dp</dimen>
<dimen name="dp_197">197dp</dimen>
<dimen name="dp_198">198dp</dimen>
<dimen name="dp_199">199dp</dimen>
<dimen name="dp_200">200dp</dimen>
<dimen name="dp_201">201dp</dimen>
<dimen name="dp_202">202dp</dimen>
<dimen name="dp_203">203dp</dimen>
<dimen name="dp_204">204dp</dimen>
<dimen name="dp_205">205dp</dimen>
<dimen name="dp_206">206dp</dimen>
<dimen name="dp_207">207dp</dimen>
<dimen name="dp_208">208dp</dimen>
<dimen name="dp_209">209dp</dimen>
<dimen name="dp_210">210dp</dimen>
<dimen name="dp_211">211dp</dimen>
<dimen name="dp_212">212dp</dimen>
<dimen name="dp_213">213dp</dimen>
<dimen name="dp_214">214dp</dimen>
<dimen name="dp_215">215dp</dimen>
<dimen name="dp_216">216dp</dimen>
<dimen name="dp_217">217dp</dimen>
<dimen name="dp_218">218dp</dimen>
<dimen name="dp_219">219dp</dimen>
<dimen name="dp_220">220dp</dimen>
<dimen name="dp_221">221dp</dimen>
<dimen name="dp_222">222dp</dimen>
<dimen name="dp_223">223dp</dimen>
<dimen name="dp_224">224dp</dimen>
<dimen name="dp_225">225dp</dimen>
<dimen name="dp_226">226dp</dimen>
<dimen name="dp_227">227dp</dimen>
<dimen name="dp_228">228dp</dimen>
<dimen name="dp_229">229dp</dimen>
<dimen name="dp_230">230dp</dimen>
<dimen name="dp_231">231dp</dimen>
<dimen name="dp_232">232dp</dimen>
<dimen name="dp_233">233dp</dimen>
<dimen name="dp_234">234dp</dimen>
<dimen name="dp_235">235dp</dimen>
<dimen name="dp_236">236dp</dimen>
<dimen name="dp_237">237dp</dimen>
<dimen name="dp_238">238dp</dimen>
<dimen name="dp_239">239dp</dimen>
<dimen name="dp_240">240dp</dimen>
<dimen name="dp_241">241dp</dimen>
<dimen name="dp_242">242dp</dimen>
<dimen name="dp_243">243dp</dimen>
<dimen name="dp_244">244dp</dimen>
<dimen name="dp_245">245dp</dimen>
<dimen name="dp_246">246dp</dimen>
<dimen name="dp_247">247dp</dimen>
<dimen name="dp_248">248dp</dimen>
<dimen name="dp_249">249dp</dimen>
<dimen name="dp_250">250dp</dimen>
<dimen name="dp_251">251dp</dimen>
<dimen name="dp_252">252dp</dimen>
<dimen name="dp_253">253dp</dimen>
<dimen name="dp_254">254dp</dimen>
<dimen name="dp_255">255dp</dimen>
<dimen name="dp_256">256dp</dimen>
<dimen name="dp_257">257dp</dimen>
<dimen name="dp_258">258dp</dimen>
<dimen name="dp_259">259dp</dimen>
<dimen name="dp_260">260dp</dimen>
<dimen name="dp_261">261dp</dimen>
<dimen name="dp_262">262dp</dimen>
<dimen name="dp_263">263dp</dimen>
<dimen name="dp_264">264dp</dimen>
<dimen name="dp_265">265dp</dimen>
<dimen name="dp_266">266dp</dimen>
<dimen name="dp_267">267dp</dimen>
<dimen name="dp_268">268dp</dimen>
<dimen name="dp_269">269dp</dimen>
<dimen name="dp_270">270dp</dimen>
<dimen name="dp_271">271dp</dimen>
<dimen name="dp_272">272dp</dimen>
<dimen name="dp_273">273dp</dimen>
<dimen name="dp_274">274dp</dimen>
<dimen name="dp_275">275dp</dimen>
<dimen name="dp_276">276dp</dimen>
<dimen name="dp_277">277dp</dimen>
<dimen name="dp_278">278dp</dimen>
<dimen name="dp_279">279dp</dimen>
<dimen name="dp_280">280dp</dimen>
<dimen name="dp_281">281dp</dimen>
<dimen name="dp_282">282dp</dimen>
<dimen name="dp_283">283dp</dimen>
<dimen name="dp_284">284dp</dimen>
<dimen name="dp_285">285dp</dimen>
<dimen name="dp_286">286dp</dimen>
<dimen name="dp_287">287dp</dimen>
<dimen name="dp_288">288dp</dimen>
<dimen name="dp_289">289dp</dimen>
<dimen name="dp_290">290dp</dimen>
<dimen name="dp_291">291dp</dimen>
<dimen name="dp_292">292dp</dimen>
<dimen name="dp_293">293dp</dimen>
<dimen name="dp_294">294dp</dimen>
<dimen name="dp_295">295dp</dimen>
<dimen name="dp_296">296dp</dimen>
<dimen name="dp_297">297dp</dimen>
<dimen name="dp_298">298dp</dimen>
<dimen name="dp_299">299dp</dimen>
<dimen name="dp_300">300dp</dimen>
<dimen name="dp_301">301dp</dimen>
<dimen name="dp_302">302dp</dimen>
<dimen name="dp_303">303dp</dimen>
<dimen name="dp_304">304dp</dimen>
<dimen name="dp_305">305dp</dimen>
<dimen name="dp_306">306dp</dimen>
<dimen name="dp_307">307dp</dimen>
<dimen name="dp_308">308dp</dimen>
<dimen name="dp_309">309dp</dimen>
<dimen name="dp_310">310dp</dimen>
<dimen name="dp_311">311dp</dimen>
<dimen name="dp_312">312dp</dimen>
<dimen name="dp_313">313dp</dimen>
<dimen name="dp_314">314dp</dimen>
<dimen name="dp_315">315dp</dimen>
<dimen name="dp_316">316dp</dimen>
<dimen name="dp_317">317dp</dimen>
<dimen name="dp_318">318dp</dimen>
<dimen name="dp_319">319dp</dimen>
<dimen name="dp_320">320dp</dimen>
<dimen name="dp_321">321dp</dimen>
<dimen name="dp_322">322dp</dimen>
<dimen name="dp_323">323dp</dimen>
<dimen name="dp_324">324dp</dimen>
<dimen name="dp_325">325dp</dimen>
<dimen name="dp_326">326dp</dimen>
<dimen name="dp_327">327dp</dimen>
<dimen name="dp_328">328dp</dimen>
<dimen name="dp_329">329dp</dimen>
<dimen name="dp_330">330dp</dimen>
<dimen name="dp_331">331dp</dimen>
<dimen name="dp_332">332dp</dimen>
<dimen name="dp_333">333dp</dimen>
<dimen name="dp_334">334dp</dimen>
<dimen name="dp_335">335dp</dimen>
<dimen name="dp_336">336dp</dimen>
<dimen name="dp_337">337dp</dimen>
<dimen name="dp_338">338dp</dimen>
<dimen name="dp_339">339dp</dimen>
<dimen name="dp_340">340dp</dimen>
<dimen name="dp_341">341dp</dimen>
<dimen name="dp_342">342dp</dimen>
<dimen name="dp_343">343dp</dimen>
<dimen name="dp_344">344dp</dimen>
<dimen name="dp_345">345dp</dimen>
<dimen name="dp_346">346dp</dimen>
<dimen name="dp_347">347dp</dimen>
<dimen name="dp_348">348dp</dimen>
<dimen name="dp_349">349dp</dimen>
<dimen name="dp_350">350dp</dimen>
<dimen name="dp_351">351dp</dimen>
<dimen name="dp_352">352dp</dimen>
<dimen name="dp_353">353dp</dimen>
<dimen name="dp_354">354dp</dimen>
<dimen name="dp_355">355dp</dimen>
<dimen name="dp_356">356dp</dimen>
<dimen name="dp_357">357dp</dimen>
<dimen name="dp_358">358dp</dimen>
<dimen name="dp_359">359dp</dimen>
<dimen name="dp_360">360dp</dimen>
<dimen name="dp_365">365dp</dimen>
<dimen name="dp_370">370dp</dimen>
<dimen name="dp_400">400dp</dimen>
<dimen name="dp_410">410dp</dimen>
<dimen name="dp_422">422dp</dimen>
<dimen name="dp_472">472dp</dimen>
<dimen name="dp_500">500dp</dimen>
<dimen name="dp_600">600dp</dimen>
<dimen name="dp_640">640dp</dimen>
<dimen name="dp_720">720dp</dimen>
<!-- font size,you can add if there is no one -->
<dimen name="sp_6">6sp</dimen>
<dimen name="sp_7">7sp</dimen>
<dimen name="sp_8">8sp</dimen>
<dimen name="sp_9">9sp</dimen>
<dimen name="sp_10">10sp</dimen>
<dimen name="sp_11">11sp</dimen>
<dimen name="sp_12">12sp</dimen>
<dimen name="sp_13">13sp</dimen>
<dimen name="sp_14">14sp</dimen>
<dimen name="sp_15">15sp</dimen>
<dimen name="sp_16">16sp</dimen>
<dimen name="sp_17">17sp</dimen>
<dimen name="sp_18">18sp</dimen>
<dimen name="sp_19">19sp</dimen>
<dimen name="sp_20">20sp</dimen>
<dimen name="sp_21">21sp</dimen>
<dimen name="sp_22">22sp</dimen>
<dimen name="sp_23">23sp</dimen>
<dimen name="sp_24">24sp</dimen>
<dimen name="sp_25">25sp</dimen>
<dimen name="sp_28">28sp</dimen>
<dimen name="sp_30">30sp</dimen>
<dimen name="sp_32">32sp</dimen>
<dimen name="sp_34">34sp</dimen>
<dimen name="sp_36">36sp</dimen>
<dimen name="sp_38">38sp</dimen>
<dimen name="sp_40">40sp</dimen>
<dimen name="sp_42">42sp</dimen>
<dimen name="sp_48">48sp</dimen>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="more">更多</string>
<string name="cancel">取消</string>
<string name="foldHint">收起</string>
<string name="expandHint">展开</string>
</resources>
\ No newline at end of file
...@@ -3,3 +3,4 @@ include ':oaid' ...@@ -3,3 +3,4 @@ include ':oaid'
include ':rxpay' include ':rxpay'
include ':alipay' include ':alipay'
include ':wxpay' include ':wxpay'
include ':library_tagflow'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment