Skip to content

Commit 732b53e

Browse files
author
杨宏伟
committed
优化标签布局
1 parent 30ed67c commit 732b53e

File tree

7 files changed

+105
-88
lines changed

7 files changed

+105
-88
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ allprojects {
1212
}
1313

1414
dependencies {
15-
implementation 'com.github.LuckyCodeer:TagLayout:1.0.4'
15+
implementation 'com.github.LuckyCodeer:TagLayout:1.0.5'
1616
}
1717
```
1818

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ dependencies {
3939
implementation 'com.google.android.material:material:1.3.0'
4040
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
4141
implementation project(path: ':library')
42+
// implementation 'com.github.LuckyCodeer:TagLayout:1.0.5'
4243
testImplementation 'junit:junit:4.+'
4344
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
4445
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

app/src/main/res/layout/activity_main.xml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,47 @@
1616
<TextView
1717
android:layout_width="wrap_content"
1818
android:layout_height="wrap_content"
19-
android:padding="10dp"
2019
android:layout_margin="10dp"
21-
android:text="正常"
22-
android:background="@drawable/tag_selector_bg"/>
20+
android:background="@drawable/tag_selector_bg"
21+
android:padding="10dp"
22+
android:text="正常" />
2323

2424
<TextView
2525
android:layout_width="wrap_content"
2626
android:layout_height="wrap_content"
27-
android:padding="10dp"
2827
android:layout_margin="10dp"
29-
android:text="单选"
30-
android:background="@drawable/tag_selector_bg"/>
28+
android:background="@drawable/tag_selector_bg"
29+
android:padding="10dp"
30+
android:text="单选" />
3131

3232
<TextView
3333
android:layout_width="wrap_content"
3434
android:layout_height="wrap_content"
35-
android:padding="10dp"
3635
android:layout_margin="10dp"
37-
android:text="多选"
38-
android:background="@drawable/tag_selector_bg"/>
36+
android:background="@drawable/tag_selector_bg"
37+
android:padding="10dp"
38+
android:text="多选" />
3939
</com.yhw.taglayout.TagLayout>
4040

4141
<com.yhw.taglayout.TagLayout
4242
android:id="@+id/tag_layout_2"
43-
android:layout_width="wrap_content"
43+
android:layout_width="match_parent"
4444
android:layout_height="wrap_content"
45-
app:defaultChoicePosition="0"
46-
app:choiceMode="none" />
45+
app:choiceMode="none"
46+
app:defaultChoicePosition="0" />
4747

4848
<LinearLayout
4949
android:layout_width="match_parent"
5050
android:layout_height="wrap_content"
51-
android:orientation="horizontal"
51+
android:layout_marginTop="20dp"
5252
android:gravity="center"
53-
android:layout_marginTop="20dp">
53+
android:orientation="horizontal">
5454

5555
<Button
5656
android:id="@+id/btn_get_index"
5757
android:layout_width="wrap_content"
5858
android:layout_height="wrap_content"
59-
android:text="获取选中项"/>
59+
android:text="获取选中项" />
6060

6161
</LinearLayout>
6262

app/src/main/res/layout/list_item_layout.xml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@
99
android:id="@+id/tv_text"
1010
android:layout_width="match_parent"
1111
android:layout_height="wrap_content"
12-
app:layout_constraintTop_toTopOf="parent"
1312
app:layout_constraintLeft_toLeftOf="parent"
14-
app:layout_constraintRight_toRightOf="parent"/>
13+
app:layout_constraintRight_toRightOf="parent"
14+
app:layout_constraintTop_toTopOf="parent" />
1515

1616
<com.yhw.taglayout.TagLayout
1717
android:id="@+id/tag_layout"
1818
android:layout_width="match_parent"
1919
android:layout_height="wrap_content"
2020
android:layout_marginTop="10dp"
21-
app:layout_constraintTop_toBottomOf="@id/tv_text"
22-
app:layout_constraintBottom_toBottomOf="parent"/>
21+
app:layout_constraintBottom_toBottomOf="parent"
22+
app:layout_constraintTop_toBottomOf="@id/tv_text" />
23+
2324

2425
<View
2526
android:layout_width="match_parent"
2627
android:layout_height="1dp"
27-
app:layout_constraintTop_toBottomOf="@id/tag_layout"
28-
android:background="#e0e0e0"/>
28+
android:background="#e0e0e0"
29+
app:layout_constraintTop_toBottomOf="@id/tag_layout" />
2930

3031
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/layout/tag_item_layout.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
android:layout_width="wrap_content"
44
android:layout_height="wrap_content"
5-
android:layout_margin="10dp"
5+
android:layout_margin="5dp"
66
android:background="@drawable/tag_selector_bg"
77
android:orientation="vertical">
88

99
<TextView
1010
android:id="@+id/tv_title"
1111
android:layout_width="wrap_content"
1212
android:layout_height="wrap_content"
13+
android:ellipsize="end"
1314
android:gravity="center"
1415
android:padding="10dp"
1516
android:textSize="15sp" />

library/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ android {
99
defaultConfig {
1010
minSdkVersion 16
1111
targetSdkVersion 30
12-
versionCode 104
13-
versionName "1.0.4"
12+
versionCode 105
13+
versionName "1.0.5"
1414

1515
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1616
consumerProguardFiles "consumer-rules.pro"

library/src/main/java/com/yhw/taglayout/TagLayout.kt

Lines changed: 77 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,30 @@ import android.annotation.SuppressLint
44
import android.content.Context
55
import android.graphics.Rect
66
import android.util.AttributeSet
7+
import android.util.DisplayMetrics
78
import android.util.Log
89
import android.view.View
910
import android.view.View.OnLongClickListener
1011
import android.view.ViewGroup
12+
import android.view.WindowManager
1113
import kotlin.math.max
1214

13-
private const val TAG = "TagLayout"
15+
private const val TAG = "TagLayout===>"
1416

1517
/**
1618
* 标签布局
1719
* @author yhw
1820
*/
1921
class TagLayout : ViewGroup {
20-
private val mViewRectList = mutableListOf<Rect>()
21-
private val mChildViewList = mutableListOf<View>()
22+
private val mViewRectMap = mutableMapOf<View, Rect>()
2223
private var choiceMode = ChoiceMode.None.choiceMode //选择模式
2324
private var defChoicePosition: Int = 0 //单选时默认选中
2425
private lateinit var mAdapter: TagAdapter
2526
var onItemClickListener: OnItemClickListener? = null
2627
var onItemLongClickListener: OnItemLongClickListener? = null
2728
var onSingleCheckedChangeListener: OnSingleCheckedChangeListener? = null
2829
var onMultipleCheckedChangeListener: OnMultipleCheckedChangeListener? = null
30+
var mScreenWidth = 0 //屏幕宽度
2931

3032
constructor(context: Context) : this(context, null)
3133
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
@@ -38,6 +40,12 @@ class TagLayout : ViewGroup {
3840
choiceMode = ta.getInt(R.styleable.TagLayout_choiceMode, ChoiceMode.None.choiceMode)
3941
defChoicePosition = ta.getInt(R.styleable.TagLayout_defaultChoicePosition, 0)
4042
ta.recycle()
43+
44+
val windowManager = context
45+
.getSystemService(Context.WINDOW_SERVICE) as WindowManager
46+
val displayMetrics = DisplayMetrics()
47+
windowManager.defaultDisplay.getMetrics(displayMetrics)
48+
this.mScreenWidth = displayMetrics.widthPixels
4149
}
4250

4351
@SuppressLint("DrawAllocation")
@@ -52,9 +60,8 @@ class TagLayout : ViewGroup {
5260
var height = 0 //最终父布局高度
5361
var lineWidth = 0 //行宽
5462
var lineHeight = 0 //行高
55-
63+
Log.i(TAG, "widthSize is $widthSize widthMode is $widthMode mScreenWidth:${mScreenWidth}")
5664
measureChildren(widthMeasureSpec, heightMeasureSpec)
57-
5865
for (i in 0 until childCount) {
5966
val childView = getChildAt(i)
6067
val marginLayoutParams: MarginLayoutParams =
@@ -83,72 +90,76 @@ class TagLayout : ViewGroup {
8390
lineHeight = max(childHeight, lineHeight)
8491
}
8592

86-
if (!mChildViewList.contains(childView)) {
87-
if (choiceMode == ChoiceMode.SingleChoice.choiceMode) {
88-
if (i in 0 until childCount && i == defChoicePosition)
89-
childView.isSelected = true
90-
}
91-
mChildViewList.add(childView)
92-
val childLeft = lineWidth - childWidth + marginLayoutParams.leftMargin
93-
val childRight =
94-
lineWidth - childWidth + childWidth - marginLayoutParams.rightMargin
95-
val childTop = height + marginLayoutParams.topMargin
96-
val childBottom = height + childHeight - marginLayoutParams.bottomMargin
97-
val rect = Rect(childLeft, childTop, childRight, childBottom)
98-
Log.i(
99-
TAG, "onMeasure left:${rect.left} top:${rect.top} ," +
100-
"right:${rect.right} ,bottom:${rect.bottom}"
101-
)
102-
mViewRectList.add(rect)
103-
104-
if (onItemClickListener != null || onSingleCheckedChangeListener != null || onMultipleCheckedChangeListener != null) {
105-
childView.isClickable = true
106-
childView.isFocusable = true
107-
childView.setOnClickListener {
108-
changedCheckedItemView(i)
109-
if (onItemClickListener != null) {
110-
onItemClickListener?.onItemClick(i, it)
111-
}
112-
if (choiceMode == ChoiceMode.SingleChoice.choiceMode) {
113-
this.defChoicePosition = i
114-
if (onSingleCheckedChangeListener != null) {
115-
onSingleCheckedChangeListener?.onCheckedChanged(defChoicePosition)
116-
}
117-
} else if (choiceMode == ChoiceMode.MultipleChoice.choiceMode) {
118-
if (onMultipleCheckedChangeListener != null) {
119-
onMultipleCheckedChangeListener?.onCheckedChanged(getCheckedList())
120-
}
121-
}
122-
}
123-
}
124-
125-
if (onItemLongClickListener != null) {
126-
childView.isClickable = true
127-
childView.isFocusable = true
128-
childView.setOnLongClickListener(OnLongClickListener { v ->
129-
onItemLongClickListener?.onItemLongClick(i, v)
130-
true
131-
})
132-
}
93+
if (choiceMode == ChoiceMode.SingleChoice.choiceMode) {
94+
if (i in 0 until childCount && i == defChoicePosition)
95+
childView.isSelected = true
13396
}
97+
val childLeft = lineWidth - childWidth + marginLayoutParams.leftMargin + paddingLeft
98+
var childRight = childView.measuredWidth + childLeft
99+
if (childRight > mScreenWidth) {
100+
childRight = mScreenWidth - marginLayoutParams.rightMargin - paddingRight
101+
// childRight = childView.measuredWidth
102+
}
103+
val childTop = height + marginLayoutParams.topMargin + paddingTop
104+
val childBottom =
105+
height + childHeight - marginLayoutParams.bottomMargin + paddingTop
106+
val rect = Rect(childLeft, childTop, childRight, childBottom)
107+
Log.i(
108+
TAG, "onMeasure left:${rect.left} top:${rect.top} ," +
109+
"right:${rect.right} ,bottom:${rect.bottom} measuredWidth:${childView.measuredWidth}"
110+
)
111+
mViewRectMap[childView] = rect
134112

135113
//最后一行处理
136114
if (i == childCount - 1) {
137115
width = max(lineWidth, width)
138116
height += lineHeight
139117
}
140118
}
141-
setMeasuredDimension(
142-
if (widthMode == MeasureSpec.EXACTLY) widthSize else width,
143-
if (heightMode == MeasureSpec.EXACTLY) heightSize else height
144-
)
119+
val measuredWidth =
120+
if (widthMode == MeasureSpec.EXACTLY) widthSize else width + paddingLeft + paddingRight
121+
val measuredHeight =
122+
if (heightMode == MeasureSpec.EXACTLY) heightSize else height + paddingTop + paddingBottom
123+
Log.i(TAG, "measuredWidth :${measuredWidth} measuredHeight:${measuredHeight} width:${width} lineWidth:${lineWidth}")
124+
setMeasuredDimension(max(measuredWidth, width), measuredHeight)
145125
}
146126

147127
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
148-
for (i in 0 until childCount) {
149-
val childView = getChildAt(i)
150-
val rect = mViewRectList[i]
128+
Log.i(TAG, "=========onLayout========== $changed $l $t $r $b")
129+
var i = 0
130+
for ((childView, rect) in mViewRectMap) {
151131
childView.layout(rect.left, rect.top, rect.right, rect.bottom)
132+
if (onItemClickListener != null || onSingleCheckedChangeListener != null || onMultipleCheckedChangeListener != null) {
133+
childView.isClickable = true
134+
childView.isFocusable = true
135+
val position = i
136+
childView.setOnClickListener {
137+
changedCheckedItemView(position)
138+
if (onItemClickListener != null) {
139+
onItemClickListener?.onItemClick(position, it)
140+
}
141+
if (choiceMode == ChoiceMode.SingleChoice.choiceMode) {
142+
this.defChoicePosition = position
143+
if (onSingleCheckedChangeListener != null) {
144+
onSingleCheckedChangeListener?.onCheckedChanged(defChoicePosition)
145+
}
146+
} else if (choiceMode == ChoiceMode.MultipleChoice.choiceMode) {
147+
if (onMultipleCheckedChangeListener != null) {
148+
onMultipleCheckedChangeListener?.onCheckedChanged(getCheckedList())
149+
}
150+
}
151+
}
152+
}
153+
154+
if (onItemLongClickListener != null) {
155+
childView.isClickable = true
156+
childView.isFocusable = true
157+
childView.setOnLongClickListener(OnLongClickListener { v ->
158+
onItemLongClickListener?.onItemLongClick(i, v)
159+
true
160+
})
161+
}
162+
i++
152163
}
153164
}
154165

@@ -157,7 +168,8 @@ class TagLayout : ViewGroup {
157168
*/
158169
private fun changedCheckedItemView(position: Int) {
159170
Log.i(TAG, "choiceMode is $choiceMode")
160-
for ((index, view) in mChildViewList.withIndex()) {
171+
var index = 0
172+
for ((view, _) in mViewRectMap) {
161173
if (position == -1) {
162174
view.isSelected = false
163175
continue
@@ -171,6 +183,7 @@ class TagLayout : ViewGroup {
171183
} else {
172184
view.isSelected = false
173185
}
186+
index++
174187
}
175188
}
176189

@@ -179,10 +192,12 @@ class TagLayout : ViewGroup {
179192
*/
180193
fun getCheckedList(): MutableList<Int> {
181194
val checkedList = mutableListOf<Int>()
182-
for ((index, view) in mChildViewList.withIndex()) {
195+
var index = 0
196+
for ((view, _) in mViewRectMap) {
183197
if (view.isSelected) {
184198
checkedList.add(index)
185199
}
200+
index++
186201
}
187202
return checkedList
188203
}
@@ -204,8 +219,7 @@ class TagLayout : ViewGroup {
204219

205220
private fun changedAdapter() {
206221
removeAllViews()
207-
mChildViewList.clear()
208-
mViewRectList.clear()
222+
mViewRectMap.clear()
209223
for (i in 0 until mAdapter.getItemCount()) {
210224
val itemView = mAdapter.onCreateView(this)
211225
mAdapter.onBindView(itemView, i)

0 commit comments

Comments
 (0)