Commit 1bbf1180 authored by 王韦's avatar 王韦

[new] 增加 bottomTab

parent d7e5749a
...@@ -42,7 +42,7 @@ repositories { ...@@ -42,7 +42,7 @@ repositories {
group 'com.qmai.android.tools' group 'com.qmai.android.tools'
version '1.1.3-SNAPSHOT' version '1.1.4-SNAPSHOT'
gradlePublish { gradlePublish {
......
package com.qimai.android.tools
import android.graphics.Bitmap
import android.graphics.Matrix
/**
* created by wangwei ON 2019-09-03 email:wangwei_5521@163.com
* @version 1.1.1
* @Description
**/
fun Bitmap.resize(w: Int, h: Int): Bitmap {
val width = width
val height = height
val scaleWight = w.toFloat() / width
val scaleHeight = h.toFloat() / height
val matrix = Matrix()
matrix.postScale(scaleWight, scaleHeight)
return Bitmap.createBitmap(
this
, 0, 0, width, height, matrix, true
)
}
\ No newline at end of file
...@@ -45,7 +45,7 @@ repositories { ...@@ -45,7 +45,7 @@ repositories {
group 'com.qmai.android.sdk' group 'com.qmai.android.sdk'
version '1.1.6-SNAPSHOT' version '1.1.7-SNAPSHOT'
gradlePublish { gradlePublish {
......
package com.qimai.android.widgetlib.bottombar
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Paint
import android.os.Parcel
import android.os.Parcelable
import android.util.AttributeSet
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import com.qimai.android.tools.dpTopx
import com.qimai.android.tools.resize
import com.qimai.android.widgetlib.R
import java.util.*
@Suppress("unused")
class BottomBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) :
LinearLayout(context, attrs, defStyleAttr) {
private val TRANSLATE_DURATION_MILLIS = 200
private val mInterpolator = AccelerateDecelerateInterpolator()
private var mVisible = true
private var mTabs: MutableList<BottomBarTab> = ArrayList()
private var mTabLayout: LinearLayout? = null
private var mTabParams: LayoutParams? = null
private var mCurrentPosition = -1
private var mListener: OnTabSelectedListener? = null
private var mShadowBitmap: Bitmap? = null
private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
init {
initBottom(context)
}
private fun initBottom(context: Context) {
clipChildren = false
setWillNotDraw(false)
orientation = VERTICAL
mPaint.color = ContextCompat.getColor(context, R.color.segment_divider_dark)
mPaint.strokeWidth = context.dpTopx(0.7F).toFloat()
mTabLayout = LinearLayout(context)
mTabLayout!!.orientation = HORIZONTAL
this.addView(
mTabLayout,
LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
)
mTabLayout!!.clipChildren = false
mTabParams = LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT)
mTabParams!!.weight = 1f
mShadowBitmap = BitmapFactory.decodeResource(resources, R.drawable.segment_bottom_shadow)
mShadowBitmap =
mShadowBitmap!!.resize(
resources.displayMetrics.widthPixels,
mShadowBitmap!!.height / 2
)
}
override fun onDraw(canvas: Canvas?) {
canvas!!.drawBitmap(mShadowBitmap!!, 0f, (-mShadowBitmap!!.height).toFloat(), mPaint)
super.onDraw(canvas)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val view = parent as View
if (view is ViewGroup) {
view.clipChildren = false
}
}
fun addItem(tab: BottomBarTab): BottomBar {
tab.setOnClickListener(OnClickListener { v ->
if (mListener == null) return@OnClickListener
val pos = mTabs.indexOf(v)
if (pos == -1) return@OnClickListener
if (mCurrentPosition == -1) {
mListener!!.onTabSelected(pos, 0)
tab.isSelected = true
mCurrentPosition = pos
} else {
if (mCurrentPosition == pos) {
mListener!!.onTabReselected(pos)
} else {
//修复可能存在的数组越界情况
if (mCurrentPosition > mTabs.size - 1) mCurrentPosition = mTabs.size - 1
mListener!!.onTabSelected(pos, mCurrentPosition)
tab.isSelected = true
mListener!!.onTabUnselected(mCurrentPosition)
mTabs[mCurrentPosition].isSelected = false
mCurrentPosition = pos
}
}
})
tab.layoutParams = mTabParams
mTabLayout!!.addView(tab)
mTabs.add(tab)
return this
}
//获取BottomBarTab 的容器
fun getTabLayout(): LinearLayout? {
return mTabLayout
}
//重置tabs 数量
fun resetTabs() {
mTabs = ArrayList()
}
fun resetCurrentPosition() {
mCurrentPosition = -1
}
/**
* 设置选择监听
*/
fun setOnTabSelectedListener(onTabSelectedListener: OnTabSelectedListener) {
mListener = onTabSelectedListener
}
/**
* 设置当前 item
*/
fun setCurrentItem(position: Int) {
mTabLayout!!.post {
mTabLayout!!.getChildAt(position).performClick()
}
}
/**
* 获取当前 选中index
*/
fun getCurrentItemPosition(): Int {
return mCurrentPosition
}
/**
* 获取 Tab
*/
fun getItem(index: Int): BottomBarTab? {
return if (mTabs.size < index) null else mTabs[index]
}
interface OnTabSelectedListener {
fun onTabSelected(position: Int, prePosition: Int)
fun onTabUnselected(position: Int)
fun onTabReselected(position: Int)
}
override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState()
return SavedState(superState!!, mCurrentPosition)
}
override fun onRestoreInstanceState(state: Parcelable) {
val ss = state as SavedState
super.onRestoreInstanceState(ss.superState)
if (mCurrentPosition != ss.position) {
if (mCurrentPosition == -1) {
val childAt = mTabLayout!!.getChildAt(ss.position)
if (childAt != null) {
childAt.isSelected = true
}
mCurrentPosition = ss.position
return
}
val currentView = mTabLayout!!.getChildAt(mCurrentPosition)
if (currentView != null) {
currentView.isSelected = false
}
val selectView = mTabLayout!!.getChildAt(ss.position)
if (selectView != null) {
selectView.isSelected = true
}
}
mCurrentPosition = ss.position
}
internal class SavedState : BaseSavedState {
var position: Int = 0
constructor(source: Parcel) : super(source) {
position = source.readInt()
}
constructor(superState: Parcelable, position: Int) : super(superState) {
this.position = position
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(position)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SavedState> {
override fun createFromParcel(parcel: Parcel): SavedState {
return SavedState(parcel)
}
override fun newArray(size: Int): Array<SavedState?> {
return arrayOfNulls(size)
}
}
}
fun hide() {
hide(true)
}
fun show() {
show(true)
}
fun hide(anim: Boolean) {
toggle(false, anim, false)
}
fun show(anim: Boolean) {
toggle(true, anim, false)
}
fun isVisible(): Boolean {
return mVisible
}
private fun toggle(visible: Boolean, animate: Boolean, force: Boolean) {
if (mVisible != visible || force) {
mVisible = visible
val height = height
if (height == 0 && !force) {
val vto = viewTreeObserver
if (vto.isAlive) {
// view树完成测量并且分配空间而绘制过程还没有开始的时候播放动画。
vto.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
val currentVto = viewTreeObserver
if (currentVto.isAlive) {
currentVto.removeOnPreDrawListener(this)
}
toggle(visible, animate, true)
return true
}
})
return
}
}
val translationY = if (visible) 0 else height
if (animate) {
animate().setInterpolator(mInterpolator)
.setDuration(TRANSLATE_DURATION_MILLIS.toLong())
.translationY(translationY.toFloat())
} else {
this.translationY = translationY.toFloat()
}
}
}
}
\ No newline at end of file
package com.qimai.android.widgetlib.bottombar
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.text.TextUtils
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.qimai.android.tools.dpTopx
import com.qimai.android.widgetlib.R
class BottomBarTab(
context: Context,
title: CharSequence,
tabTextColor: Int,
selectedTabTextColor: Int, @DrawableRes icon: Int, @DrawableRes selectedIcon: Int,
listener: OnSelectedTabListener?
) :
FrameLayout(context) {
private var mImg: ImageView? = null
private var mTvTitle: TextView? = null
private var mTvUnreadCount: TextView? = null
private var mContext: Context? = null
var mTabTextColor: Int = 0
var mSelectedTabTextColor: Int = 0
private var mIcon: Int = 0
private var mSelectedIcon: Int = 0
private var mOnSelectedTabListener: OnSelectedTabListener? = null
/**
* 获取当前未读数量
*/
/**
* 设置未读数量
*/
var unreadCount: Int
get() {
var count = 0
if (TextUtils.isEmpty(mTvUnreadCount!!.text)) {
return count
}
if (mTvUnreadCount!!.text.toString() == "99+") {
return 99
}
try {
count = Integer.valueOf(mTvUnreadCount!!.text.toString())
} catch (ignored: Exception) {
}
return count
}
set(num) = if (num <= 0) {
mTvUnreadCount!!.visibility = View.GONE
} else {
mTvUnreadCount!!.text = ""
mTvUnreadCount!!.visibility = View.VISIBLE
}
init {
init(context, title, tabTextColor, selectedTabTextColor, icon, selectedIcon, listener!!)
}
interface OnSelectedTabListener {
fun onSelected(tabImageView: ImageView?, selected: Boolean)
}
private fun init(
context: Context,
title: CharSequence,
tabTextColor: Int,
selectedTabTextColor: Int,
icon: Int,
selectedIcon: Int,
listener: OnSelectedTabListener
) {
this.mContext = context
this.mTabTextColor = tabTextColor
this.mIcon = icon
this.mSelectedIcon = selectedIcon
this.mOnSelectedTabListener = listener
this.mSelectedTabTextColor = selectedTabTextColor
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val typedArray =
context.obtainStyledAttributes(intArrayOf(android.R.attr.selectableItemBackgroundBorderless))
val drawable = typedArray.getDrawable(0)
background = drawable
typedArray.recycle()
}
val lLContainer = LinearLayout(context)
lLContainer.orientation = LinearLayout.VERTICAL
lLContainer.gravity = Gravity.CENTER
val paramsContainer =
LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
paramsContainer.gravity = Gravity.CENTER_HORIZONTAL
lLContainer.layoutParams = paramsContainer
mImg = ImageView(context)
val dp32 = mContext!!.dpTopx(32.0f)
mImg!!.layoutParams = ViewGroup.LayoutParams(dp32, dp32)
lLContainer.addView(mImg)
mTvTitle = TextView(context)
mTvTitle!!.text = title
val tvTitleParams =
LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
// tvTitleParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
mTvTitle!!.textSize = 10f
mTvTitle!!.setTextColor(
if (mTabTextColor == 0) ContextCompat.getColor(
context,
R.color.QmTopBar_color_FFFFFFF
) else mTabTextColor
)
mTvTitle!!.layoutParams = tvTitleParams
lLContainer.addView(mTvTitle)
addView(lLContainer)
val min = context.dpTopx(12F)
// int padding = SegmentUtil.dip2px(context, 5);
mTvUnreadCount = TextView(context)
mTvUnreadCount!!.setBackgroundResource(R.drawable.segment_bg_msg_bubble)
mTvUnreadCount!!.minWidth = min
mTvUnreadCount!!.minHeight = min
mTvUnreadCount!!.setTextColor(Color.WHITE)
// mTvUnreadCount.setPadding(padding, 0, padding, 0);
mTvUnreadCount!!.gravity = Gravity.CENTER
val tvUnReadParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, min)
tvUnReadParams.gravity = Gravity.CENTER
tvUnReadParams.leftMargin = context.dpTopx(17F)
tvUnReadParams.bottomMargin = context.dpTopx(14F)
mTvUnreadCount!!.layoutParams = tvUnReadParams
mTvUnreadCount!!.visibility = View.GONE
addView(mTvUnreadCount)
isSelected = false
}
override fun setSelected(selected: Boolean) {
super.setSelected(selected)
if (mSelectedTabTextColor != 0) {
mTvTitle!!.setTextColor(if (selected) mSelectedTabTextColor else mTabTextColor)
}
if (mOnSelectedTabListener != null && mSelectedIcon == 0 && mIcon == 0) {
mOnSelectedTabListener!!.onSelected(mImg, selected)
} else {
mImg!!.setImageResource(if (selected) mSelectedIcon else mIcon)
}
}
companion object {
fun newTab(
context: Context,
title: CharSequence,
tabTextColor: Int,
icon: Int,
selectedIcon: Int
): BottomBarTab {
return BottomBarTab(context, title, tabTextColor, 0, icon, selectedIcon, null)
}
fun newTab(
context: Context,
title: CharSequence,
tabTextColor: Int,
listener: OnSelectedTabListener
): BottomBarTab {
return BottomBarTab(context, title, tabTextColor, 0, 0, 0, listener)
}
fun newTab(
context: Context,
title: CharSequence,
tabTextColor: Int,
selectedTabTextColor: Int,
listener: OnSelectedTabListener
): BottomBarTab {
return BottomBarTab(context, title, tabTextColor, selectedTabTextColor, 0, 0, listener)
}
}
}
package com.qimai.android.widgetlib.popup package com.qimai.android.widgetlib.popup
import android.content.Context import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.text.TextUtils import android.text.TextUtils
import android.view.Gravity import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
...@@ -40,7 +42,6 @@ class QmAlertDialog private constructor( ...@@ -40,7 +42,6 @@ class QmAlertDialog private constructor(
rightButtonClickListener = builder.rightButtonClick, rightButtonClickListener = builder.rightButtonClick,
rootView = builder.rootView, rootView = builder.rootView,
dismissListener = builder.dismissListener dismissListener = builder.dismissListener
) )
fun show() { fun show() {
......
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="20dp" />
<solid android:color="#FF4040" />
<stroke
android:width="1dp"
android:color="@android:color/white" />
</shape>
\ No newline at end of file
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<color name="QmTopBar_color_000000">#000000</color> <color name="QmTopBar_color_000000">#000000</color>
<color name="color_777777">#777777</color> <color name="color_777777">#777777</color>
<color name="color_222222">#222222</color> <color name="color_222222">#222222</color>
<color name="segment_divider_dark">#d9d9d9</color>
</resources> </resources>
\ No newline at end of file
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