自定義標籤多選更改背景圖片
阿新 • • 發佈:2019-01-26
最近在做專案時候遇到了標籤佈局問題,當時我首選的是用流式佈局TagFlowLayout的控制元件,可是發現不能滿足我專案的需求,於是翻看了一下網頁寫了一個用配合ChekBox來實現多選標籤的佈局,在這寫出來,希望對其他夥伴們有些幫助!
需取效果:
首先:我們需要一個實體類TagBean,確保有id,和name(顯示的內容)
public class TagBean {
private String id;
private String name;
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public TagBean(String id, String name) {
this.id = id;
this.name = name;
}
}
然後就可以寫我們的自定義佈局了,重寫ViewGroup,採用onDraw,onMeasure,onLayout等方法類似於流式佈局,熟悉流式佈局的小夥伴應該so easy,這裡就不說太多了,直接上程式碼:
public class LabelLayout extends ViewGroup {
private int mMaxCheckCount = Integer.MAX_VALUE;
/**
* 豎直方向間距, default is 8.0dp.
*/
private int horizontalSpacing;
/**
* 水平方向間距, default is 4.0dp.
*/
private int verticalSpacing;
//whether or not to draw the divider between labels at horizon.
private boolean enableDivider = false; //是否允許顯示分割線 預設不顯示
private int dividerColor = 0xffECECEC;
private float dividerHeight;
private int checkboxLayoutId;
//nark checked labels.
private Map<String, Boolean> labelcheckMap;
//mark the first position in a row.
private Set<Integer> rowPositons = new HashSet<>();
//The paint to draw the divider.
Paint dividerPaint;
public LabelLayout(Context context) {
this(context, null);
}
public LabelLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LabelLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setWillNotDraw(false);
labelcheckMap = new HashMap<>();
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LabelLayout, defStyleAttr, R.style.LabelLayoutDefault);
try {
horizontalSpacing = (int) a.getDimension(R.styleable.LabelLayout_label_horizontalSpacing, dp2px(8.0f));
verticalSpacing = (int) a.getDimension(R.styleable.LabelLayout_label_verticalSpacing, dp2px(4.0f));
checkboxLayoutId = a.getResourceId(R.styleable.LabelLayout_label_checkboxLayout, R.layout.view_label_common);
enableDivider = a.getBoolean(R.styleable.LabelLayout_label_enableDivider, false);
dividerHeight = a.getDimension(R.styleable.LabelLayout_label_dividerHeight, dp2px(2));
dividerColor = a.getColor(R.styleable.LabelLayout_label_dividerColor, 0xffECECEC);
} finally {
a.recycle();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (enableDivider) {
if (dividerPaint == null) {
dividerPaint = new Paint();
dividerPaint.setAntiAlias(true);
dividerPaint.setColor(dividerColor);
dividerPaint.setStyle(Paint.Style.FILL);
}
for (Integer top : rowPositons) {
if (top != 0) {
//draw lines between labels.
canvas.drawRect(0, top - dividerHeight / 2, getMeasuredWidth(), top + dividerHeight / 2, dividerPaint);
}
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int width = 0;
int height = 0;
int row = 0; // The row counter.
int rowWidth = 0; // Calc the current row width.
int rowMaxHeight = 0; // Calc the max tag height, in current row.
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
if (child.getVisibility() != GONE) {
rowWidth += childWidth;
if (rowWidth > widthSize) { // Next line.
rowWidth = childWidth; // The next row width.
height += rowMaxHeight + verticalSpacing;
rowMaxHeight = childHeight; // The next row max height.
row++;
} else { // This line.
rowMaxHeight = Math.max(rowMaxHeight, childHeight);
}
rowWidth += horizontalSpacing;
}
// System.out.println("measured height:" + height);
rowPositons.add(height - verticalSpacing / 2);
}
// Account for the last row height.
height += rowMaxHeight;
// Account for the padding too.
height += getPaddingTop() + getPaddingBottom();
// If the tags grouped in one row, set the width to wrap the tags.
if (row == 0) {
width = rowWidth;
width += getPaddingLeft() + getPaddingRight();
} else {// If the tags grouped exceed one line, set the width to match the parent.
width = widthSize;
}
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width,
heightMode == MeasureSpec.EXACTLY ? heightSize : height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int parentLeft = getPaddingLeft();
final int parentRight = r - l - getPaddingRight();
final int parentTop = getPaddingTop();
final int parentBottom = b - t - getPaddingBottom();
int childLeft = parentLeft;
int childTop = parentTop;
int rowMaxHeight = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
if (child.getVisibility() != GONE) {
if (childLeft + width > parentRight) { // Next line
childLeft = parentLeft;
childTop += rowMaxHeight + verticalSpacing;
rowMaxHeight = height;
} else {
rowMaxHeight = Math.max(rowMaxHeight, height);
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
childLeft += width + horizontalSpacing;
}
}
}
/**
* set the default labels that you wanna to add into LabelLayout.
*
* @param labels A collection contains objects that implement ILabel interface.
*/
public void setLabels(List<TagBean> labels) {
labelcheckMap.clear();
removeAllViews();
if (labels == null || labels.size() == 0) return;
for (final TagBean label : labels) {
final CheckBox tagView = (CheckBox) View.inflate(getContext(), checkboxLayoutId, null);
tagView.setText(label.getName());
addView(tagView);
tagView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {//選中時新增到map
if (labelcheckMap.size() > mMaxCheckCount - 1) {
if (checkListener != null) {
checkListener.onBeyondMaxCheckCount();
}
tagView.setChecked(false);
} else {
labelcheckMap.put(label.getId(), true);
if (checkListener != null) {
checkListener.onCheckChanged(label, true);
Drawable drawable = getResources().getDrawable(R.mipmap.select_tag);
tagView.setCompoundDrawablePadding(10);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
//設定選中頭部圖片
tagView.setCompoundDrawables(drawable, null, null, null);
}
}
} else {//否則及時清理map
if (labelcheckMap.containsKey(label.getId())) {
labelcheckMap.remove(label.getId());
if (checkListener != null) {
checkListener.onCheckChanged(label, false);
//設定未選中頭部圖片
tagView.setCompoundDrawables(null, null, null, null);
}
}
}
}
});
}
}
/**
* set the maximum numbers of checked labels.
*/
public void setMaxCheckCount(int count) {
mMaxCheckCount = count;
}
/**
* Get the current selected tag number.
*/
public int getCheckedLabelsCount() {
int count = 0;
for (Map.Entry<String, Boolean> m : labelcheckMap.entrySet()) {
if (m.getValue()) {
count++;
}
}
return count;
}
public List<String> getCheckedLabelIds() {
List<String> chechedLabelIds = new ArrayList<>();
for (Map.Entry<String, Boolean> m : labelcheckMap.entrySet()) {
if (m.getValue()) {
chechedLabelIds.add(m.getKey());
}
}
return chechedLabelIds;
}
/**
* To serialize checked-label ids as json, make benefit for use.
*
* @return json string
*/
public String getCheckedIdsAsJson() {
List<String> chechedId = new ArrayList<>();
for (Map.Entry<String, Boolean> m : labelcheckMap.entrySet()) {
if (m.getValue()) {
chechedId.add(m.getKey());
}
}
return new JSONArray(chechedId).toString();
}
private float dp2px(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
getResources().getDisplayMetrics());
}
//監聽方法
private OnCheckChangeListener checkListener;
public interface OnCheckChangeListener {
void onCheckChanged(TagBean label, boolean isChecked);
void onBeyondMaxCheckCount();
}
public void setOnCheckChangedListener(OnCheckChangeListener checkListener) {
this.checkListener = checkListener;
}
上面是佈局類程式碼我全展示出來,
還有就是xml檔案的程式碼:
ChekBox的:
<?xml version="1.0" encoding="utf-8"?>
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_margin="10dp"
android:background="@drawable/label_selector"
android:button="@null"
android:paddingBottom="4dp"
android:paddingLeft="13dp"
android:paddingRight="13dp"
android:paddingTop="4dp"
android:text="hello"
android:textColor="@drawable/label_gray_selector"
android:textSize="16sp" />
背景選中效果程式碼:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<shape android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="#fff" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="6dp" />
<stroke android:width="1dp" android:color="#fff" />
</shape>
</item>
</selector>
字型選中效果:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF9400" android:state_checked="true" />
<item android:color="#434343" />
</selector>
主佈局 :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.l.tag_label.MainActivity">
<com.example.l.tag_label.LabelLayout
android:id="@+id/label_me"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
>
</com.example.l.tag_label.LabelLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="bt"
android:text="點選"/>
</LinearLayout>
然後就是activity中的程式碼了,
首先新增資料:
private ArrayList<TagBean> initList() {
ArrayList<TagBean> list = new ArrayList<>();
for (int i = 0; i < 8; i++) {
TagBean bean = new TagBean(i + "", "hello" + i);
list.add(bean);
}
return list;
}
然後再把資料傳過去,
tab.setLabels(list);// 設定資料
tab.setMaxCheckCount(4);// 設定最大選中數量
// 點選選中取消監聽
tab.setOnCheckChangedListener(new LabelLayout.OnCheckChangeListener() {
@Override
public void onCheckChanged(TagBean label, boolean isChecked) {
String name = label.getName();
Toast.makeText(MainActivity.this, isChecked + "==" + name, Toast.LENGTH_SHORT).show();
Log.d("dd", name + "");
// 在這塊可以自己寫個集合儲存一下
if (isChecked)
name_liat.add(name);
else
name_liat.remove(name);
}
@Override
public void onBeyondMaxCheckCount() {
}
});
最後執行自己的button按鈕監聽方法就可以把集合裡面的東西拿出來了。
public void bt(View view) {
for (int i = 0; i <name_liat.size() ; i++) {
Log.d("ee", name_liat.get(i).toString() + "");
}
}
寫的夠詳細,簡單了!如果感覺有幫助,請點贊!!^_^
效果圖: