From 092bf21368ea824e9dc22467166960219165dc00 Mon Sep 17 00:00:00 2001
From: zuoxiao <470321431@qq.com>
Date: 星期五, 21 二月 2025 17:32:59 +0800
Subject: [PATCH] 1.我的界面每个item添加点击效果。 2.更新本地数据添加二次确认。

---
 expand_button/src/main/java/com/example/expand_button/ExpandButton.kt |  632 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 631 insertions(+), 1 deletions(-)

diff --git a/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt b/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt
index 841ce47..007713c 100644
--- a/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt
+++ b/expand_button/src/main/java/com/example/expand_button/ExpandButton.kt
@@ -1,14 +1,644 @@
 package com.example.expand_button
 
-class ExpandButton {
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import android.text.Spannable
+import android.text.SpannableStringBuilder
+import android.text.style.ClickableSpan
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.View
+import androidx.appcompat.widget.AppCompatTextView
+import androidx.core.content.ContextCompat
+
+/**
+ * 鍙睍寮�鐨勬寜閽帶浠�
+ * 鍒濆鐘舵�佹樉绀哄崟涓瓧绗︼紝鐐瑰嚮鍚庡睍寮�鏄剧ず瀹屾暣鏂囧瓧
+ * 灞曞紑鍚庣殑姣忎釜瀛楃閮藉彲浠ュ崟鐙偣鍑�
+ */
+class ExpandButton @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : AppCompatTextView(context, attrs, defStyleAttr) {
+
+    // 淇敼灞炴��
+    private data class LegendItem(
+        val selectedIcon: Drawable,
+        val unselectedIcon: Drawable,
+        val description: String,
+        var isSelected: Boolean = true
+    )
+    
+    private var legendItems: List<LegendItem> = listOf()
+    private var itemSpacing: Float = context.resources.displayMetrics.density * 16 // 鍥句緥椤逛箣闂寸殑姘村钩闂磋窛
+    private var iconSize: Int = (24 * context.resources.displayMetrics.density).toInt() // 鍥炬爣澶у皬
+    private var iconTextSpacing: Float = context.resources.displayMetrics.density * 4 // 鍥炬爣鍜屾枃瀛椾箣闂寸殑鍨傜洿闂磋窛
+
+    // 灞曞紑鏃舵樉绀虹殑瀹屾暣鏂囧瓧
+    private var expandedText: String = "鏍囨敞鐐�: 褰撳墠浣嶇疆\n鍖哄煙: 閰嶉�佽寖鍥�"
+    // 鏀惰捣鏃舵樉绀虹殑鍗曚釜瀛楃
+    private var collapsedText: String = "鍥句緥"
+    // 褰撳墠鏄惁澶勪簬灞曞紑鐘舵��
+    private var isExpanded: Boolean = false
+    // 鍔ㄧ敾鎸佺画鏃堕棿锛岄粯璁�300姣
+    private var animationDuration: Long = 300
+    // 瀛楃鐐瑰嚮浜嬩欢鐩戝惉鍣�
+    private var onCharClickListener: ((Char, Int) -> Unit)? = null
+    // 瀛楅棿璺濓紝榛樿涓�2dp
+    private var customLetterSpacing: Float = context.resources.displayMetrics.density * 2
+
+    // 涓夎褰㈠浘鏍�
+    private val triangleDrawable: Drawable = ContextCompat.getDrawable(
+        context,
+        R.drawable.ic_triangle
+    )!!.mutate()
+
+    // 鍥炬爣鏃嬭浆瑙掑害
+    private var triangleRotation = 0f
+
+    // 涓夎褰㈠浘鏍囦笌鏂囧瓧鐨勯棿璺濓紝榛樿涓�8dp
+    private var triangleMargin: Float = 3 * context.resources.displayMetrics.density
+
+    // 娣诲姞鏂板睘鎬�
+    private var textLines: List<String> = listOf()
+
+    // 娣诲姞鐐瑰嚮鍥炶皟鎺ュ彛
+    interface OnLegendItemClickListener {
+        fun onLegendItemClick(position: Int, isSelected: Boolean)
+    }
+    
+    private var legendItemClickListener: OnLegendItemClickListener? = null
+
+    // 淇敼鍥句緥椤圭殑鎬婚珮搴﹁绠�
+    private val legendItemHeight: Int
+        get() = iconSize + iconTextSpacing.toInt() + paint.textSize.toInt() + paint.descent().toInt() - paint.ascent().toInt()
+
+    // 娣诲姞灞曞紑鍚庣殑瀛椾綋澶у皬灞炴��
+    private var expandedTextSize: Float = textSize
+
+    // 娣诲姞涓�涓彉閲忎繚瀛橀粯璁ゅ瓧浣撳ぇ灏�
+    private var defaultTextSize: Float = 0f
+
+    // 娣诲姞涓�涓睘鎬у畾涔変笁瑙掑舰鍥炬爣鐨勭偣鍑诲尯鍩熸墿灞曡寖鍥�
+    private val triangleClickPadding: Float = 15f * context.resources.displayMetrics.density // 20dp
+
+    // 娣诲姞涓�涓爣璇嗙锛岀敤浜庡尯鍒嗕笉鍚岀殑 ExpandButton 瀹炰緥
+    private var buttonId: String = "default"
+
+    companion object {
+        private const val PREFS_NAME = "expand_button_prefs"
+        private const val KEY_LEGEND_STATES = "legend_states"
+    }
+
+    init {
+        // 淇濆瓨 XML 涓缃殑榛樿瀛椾綋澶у皬
+        defaultTextSize = textSize
+
+        // 璇诲彇鑷畾涔夊睘鎬�
+        context.theme.obtainStyledAttributes(
+            attrs,
+            R.styleable.ExpandButton,
+            defStyleAttr,
+            0
+        ).apply {
+            try {
+                customLetterSpacing = getDimension(R.styleable.ExpandButton_letterSpacing, customLetterSpacing)
+                expandedText = getString(R.styleable.ExpandButton_expandedText) ?: "鏍囨敞鐐�: 褰撳墠浣嶇疆\n鍖哄煙: 閰嶉�佽寖鍥�"
+                collapsedText = getString(R.styleable.ExpandButton_collapsedText) ?: "鍥句緥"
+                animationDuration = getInteger(R.styleable.ExpandButton_animDuration, 300).toLong()
+                triangleMargin = getDimension(R.styleable.ExpandButton_triangleMargin, triangleMargin)
+                itemSpacing = getDimension(R.styleable.ExpandButton_itemSpacing, itemSpacing)
+                iconSize = getDimension(R.styleable.ExpandButton_iconSize, iconSize.toFloat()).toInt()
+                iconTextSpacing = getDimension(R.styleable.ExpandButton_iconTextSpacing, iconTextSpacing)
+                expandedTextSize = getDimension(R.styleable.ExpandButton_expandedTextSize, defaultTextSize)
+            } finally {
+                recycle()
+            }
+        }
+
+        // 璁剧疆鍒濆鏂囨湰鍜屽搴�
+        if (collapsedText.isNotEmpty()) {
+            text = collapsedText
+            post {
+                // 纭繚鍒濆瀹藉害涓烘敹璧风姸鎬佺殑瀹藉害
+                layoutParams = layoutParams.apply {
+                    width = paint.measureText(collapsedText).toInt() + paddingLeft + paddingRight
+                }
+            }
+        }
+
+        // 淇敼瑙︽懜浜嬩欢澶勭悊
+        setOnTouchListener(null) // 绉婚櫎鍘熸湁鐨勮Е鎽哥洃鍚櫒
+        
+        // 绉婚櫎鍘熸湁鐨勭偣鍑荤洃鍚櫒
+        setOnClickListener(null)
+
+        // 璁剧疆宸﹁竟璺濓紝涓哄浘鏍囩暀鍑虹┖闂�
+        compoundDrawablePadding = triangleMargin.toInt()
+        setPadding(
+            (16 * context.resources.displayMetrics.density + triangleMargin).toInt(), // 宸﹁竟璺濆鍔狅紝涓哄浘鏍囩暀绌洪棿
+            paddingTop,
+            paddingRight,
+            paddingBottom
+        )
+
+        // 璁剧疆鍗曡鏄剧ず锛岄槻姝㈤珮搴﹀彉鍖�
+        maxLines = if (isExpanded) Int.MAX_VALUE else 1
+        isSingleLine = !isExpanded
+        
+        // 璁剧疆鏂囧瓧鍨傜洿灞呬腑
+        gravity = Gravity.CENTER_VERTICAL
+
+        // 璁剧疆榛樿鐨勫唴杈硅窛
+        val defaultPadding = (8 * context.resources.displayMetrics.density).toInt()
+        setPadding(
+            (16 * context.resources.displayMetrics.density + triangleMargin).toInt(), // 宸﹁竟璺濆鍔狅紝涓哄浘鏍囩暀绌洪棿
+            defaultPadding, // 涓婅竟璺�
+            defaultPadding, // 鍙宠竟璺�
+            defaultPadding  // 涓嬭竟璺�
+        )
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        
+        if (isExpanded) {
+            // 灞曞紑鐘舵�佷笅鐨勯珮搴﹁绠�
+            val desiredHeight = legendItemHeight + paddingTop + paddingBottom
+            setMeasuredDimension(measuredWidth, desiredHeight)
+        }
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        // 缁樺埗灞曞紑/鏀惰捣鍥炬爣
+        drawTriangle(canvas)
+        
+        if (!isExpanded) {
+            // 鏀惰捣鐘舵�佷娇鐢ㄩ粯璁ゅ瓧浣撳ぇ灏�
+            paint.textSize = defaultTextSize
+            super.onDraw(canvas)
+            return
+        }
+        
+        // 灞曞紑鐘舵�佷娇鐢ㄥ睍寮�鍚庣殑瀛椾綋澶у皬
+        paint.textSize = expandedTextSize
+        
+        // 璁$畻鎵�鏈夊浘渚嬮」涓渶瀹界殑瀹藉害
+        val maxWidth = legendItems.maxOf { item ->
+            maxOf(paint.measureText(item.description), iconSize.toFloat())
+        }
+        
+        // 璁$畻鎬诲搴︼紙娣诲姞棣栧熬鐨勮竟璺濓級
+        val totalWidth = legendItems.size * maxWidth + 
+            (legendItems.size + 1) * itemSpacing  // 淇敼杩欓噷锛屾坊鍔犱竴涓澶栫殑闂磋窛
+        
+        // 璁$畻璧峰x鍧愭爣锛屼娇鏁翠綋姘村钩灞呬腑
+        var x = (width - totalWidth) / 2 + itemSpacing  // 娣诲姞璧峰杈硅窛
+        
+        // 璁$畻鍨傜洿灞呬腑鐨剏鍧愭爣锛岃�冭檻涓婁笅杈硅窛
+        val centerY = height / 2f
+        
+        legendItems.forEachIndexed { index, item ->
+            // 璁$畻褰撳墠鍥句緥椤圭殑璧峰浣嶇疆锛堢Щ闄ndex > 0鐨勫垽鏂級
+            val itemStartX = x
+            
+            // 璁$畻鍥炬爣鐨勬按骞充綅缃紙灞呬腑浜庡浘渚嬮」锛�
+            val iconLeft = itemStartX + (maxWidth - iconSize) / 2
+            
+            // 璁$畻鏂囧瓧鐨勪綅缃�
+            val textWidth = paint.measureText(item.description)
+            val textX = itemStartX + (maxWidth - textWidth) / 2
+            
+            // 缁樺埗鍥炬爣锛屾牴鎹�変腑鐘舵�侀�夋嫨涓嶅悓鐨勫浘鏍�
+            val iconTop = paddingTop + (height - legendItemHeight) / 2
+            val currentIcon = if (item.isSelected) item.selectedIcon else item.unselectedIcon
+            currentIcon.setBounds(
+                iconLeft.toInt(),
+                iconTop.toInt(),
+                (iconLeft + iconSize).toInt(),
+                (iconTop + iconSize).toInt()
+            )
+            currentIcon.draw(canvas)
+            
+            // 缁樺埗鏂囧瓧锛屾牴鎹�変腑鐘舵�佷娇鐢ㄤ笉鍚岀殑棰滆壊
+            paint.color = if (item.isSelected) 
+                currentTextColor 
+            else 
+                0xFF999999.toInt() // 鐏拌壊
+            val textY = iconTop + iconSize + iconTextSpacing - paint.ascent()
+            canvas.drawText(item.description, textX, textY, paint)
+            
+            // 鏇存柊涓嬩竴涓浘渚嬮」鐨勮捣濮嬩綅缃�
+            x = itemStartX + maxWidth + itemSpacing
+        }
+        
+        // 鎭㈠鐢荤瑪棰滆壊
+        paint.color = currentTextColor
+    }
+
+    // 灏嗗師鏉ョ殑onDraw涓殑涓夎褰㈢粯鍒堕�昏緫鎻愬彇鍑烘潵
+    private fun drawTriangle(canvas: Canvas) {
+        canvas.save()
+        
+        val iconSize = triangleDrawable.intrinsicWidth
+        val iconLeft = paddingLeft - iconSize - compoundDrawablePadding
+        val iconTop = (height - iconSize) / 2
+        
+        triangleDrawable.setBounds(
+            iconLeft,
+            iconTop,
+            iconLeft + iconSize,
+            iconTop + iconSize
+        )
+        
+        canvas.rotate(
+            triangleRotation,
+            (iconLeft + iconSize / 2).toFloat(),
+            (iconTop + iconSize / 2).toFloat()
+        )
+        
+        triangleDrawable.draw(canvas)
+        
+        canvas.restore()
+    }
+
+    /**
+     * 璁剧疆瀛楅棿璺�
+     * @param spacing 闂磋窛鍊硷紙鍍忕礌锛�
+     */
+    fun setCustomLetterSpacing(spacing: Float) {
+        this.customLetterSpacing = spacing
+        if (isExpanded) {
+            setExpandedClickableText()
+        }
+    }
+
+    /**
+     * 璁剧疆灞曞紑鍜屾敹璧锋椂鏄剧ず鐨勬枃瀛�
+     * @param expanded 灞曞紑鏃舵樉绀虹殑瀹屾暣鏂囧瓧
+     * @param collapsed 鏀惰捣鏃舵樉绀虹殑鍗曚釜瀛楃
+     */
+    fun setExpandText(expanded: String, collapsed: String) {
+        this.expandedText = expanded
+        this.collapsedText = collapsed
+        text = collapsedText
+    }
+
+    /**
+     * 璁剧疆鍗曚釜瀛楃鐐瑰嚮鐩戝惉鍣�
+     * @param listener 鐐瑰嚮鍥炶皟锛屽弬鏁颁负琚偣鍑荤殑瀛楃鍜屼綅缃�
+     *                char: 琚偣鍑荤殑瀛楃
+     *                position: 瀛楃鍦ㄦ枃鏈腑鐨勪綅缃紙浠�0寮�濮嬶級
+     */
+    fun setOnCharClickListener(listener: (char: Char, position: Int) -> Unit) {
+        this.onCharClickListener = listener
+    }
+
+    /**
+     * 璁剧疆灞曞紑/鏀惰捣鍔ㄧ敾鐨勬寔缁椂闂�
+     * @param duration 鍔ㄧ敾鎸佺画鏃堕棿锛堟绉掞級
+     */
+    fun setAnimationDuration(duration: Long) {
+        this.animationDuration = duration
+    }
+
+    /**
+     * 鍒囨崲灞曞紑/鏀惰捣鐘舵��
+     */
+    private fun toggleExpand() {
+        isExpanded = !isExpanded
+
+        // 璁$畻鏀惰捣鍜屽睍寮�鐘舵�佺殑瀹藉害
+        val collapsedWidth = run {
+            paint.textSize = defaultTextSize
+            val width = paint.measureText(collapsedText).toInt() + paddingLeft + paddingRight
+            paint.textSize = if (isExpanded) expandedTextSize else defaultTextSize
+            width
+        }
+        
+        val expandedWidth = calculateExpandedWidth()
+
+        // 鍒涘缓瀹藉害鍔ㄧ敾
+        ValueAnimator.ofInt(
+            if (isExpanded) collapsedWidth else expandedWidth,
+            if (isExpanded) expandedWidth else collapsedWidth
+        ).apply {
+            duration = animationDuration
+            addUpdateListener { animator ->
+                layoutParams = layoutParams.apply {
+                    width = animator.animatedValue as Int
+                }
+                requestLayout()
+            }
+            start()
+        }
+
+        // 鍒涘缓鍥炬爣鏃嬭浆鍔ㄧ敾
+        ValueAnimator.ofFloat(
+            if (isExpanded) 0f else 180f,
+            if (isExpanded) 180f else 0f
+        ).apply {
+            duration = animationDuration
+            addUpdateListener { animator ->
+                triangleRotation = animator.animatedValue as Float
+                invalidate()
+            }
+            start()
+        }
+
+        // 鏇存柊鏂囨湰鍜屽瓧浣撳ぇ灏�
+        if (isExpanded) {
+            paint.textSize = expandedTextSize
+        } else {
+            text = collapsedText
+            paint.textSize = defaultTextSize
+            setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, defaultTextSize)
+        }
+
+        invalidate()
+    }
+
+    /**
+     * 璁$畻灞曞紑鍚庣殑鎬诲搴�
+     */
+    private fun calculateExpandedWidth(): Int {
+        // 涓存椂淇濆瓨褰撳墠瀛椾綋澶у皬
+        val currentTextSize = paint.textSize
+        // 璁剧疆涓哄睍寮�鐘舵�佺殑瀛椾綋澶у皬
+        paint.textSize = expandedTextSize
+        
+        try {
+            // 璁$畻鎵�鏈夊浘渚嬮」涓渶瀹界殑瀹藉害
+            val maxWidth = legendItems.maxOf { item ->
+                maxOf(paint.measureText(item.description), iconSize.toFloat())
+            }
+            
+            // 璁$畻鎬诲搴� = 鎵�鏈夊浘渚嬮」鐨勫搴� + 鎵�鏈夐棿璺濓紙鍖呮嫭棣栧熬锛� + 宸﹀彸鍐呰竟璺�
+            return (legendItems.size * maxWidth + 
+                (legendItems.size + 1) * itemSpacing +  
+                paddingLeft + paddingRight).toInt()
+        } finally {
+            // 鎭㈠鍘熸潵鐨勫瓧浣撳ぇ灏�
+            paint.textSize = currentTextSize
+        }
+    }
+
+    /**
+     * 璁剧疆灞曞紑鍚庣殑鍙偣鍑绘枃鏈�
+     */
+    private fun setExpandedClickableText() {
+        val builder = SpannableStringBuilder()
+        
+        // 璁$畻鎵�鏈夊浘渚嬮」涓渶瀹界殑瀹藉害
+        val maxWidth = legendItems.maxOf { item ->
+            maxOf(paint.measureText(item.description), iconSize.toFloat())
+        }
+        
+        // 璁$畻鎬诲搴�
+        val totalWidth = legendItems.size * maxWidth + 
+            (legendItems.size - 1) * itemSpacing
+        
+        // 璁$畻鏁翠綋姘村钩灞呬腑闇�瑕佺殑璧峰绌烘牸
+        val startPadding = ((width - totalWidth) / 2 / paint.measureText(" ")).toInt()
+        if (startPadding > 0) {
+            builder.append(" ".repeat(startPadding))
+        }
+        
+        // 娣诲姞鍨傜洿绌洪棿锛屼负鍥炬爣棰勭暀浣嶇疆
+        val verticalSpaces = ((iconSize + iconTextSpacing) / paint.textSize).toInt()
+        builder.append("\n".repeat(verticalSpaces))
+        
+        legendItems.forEachIndexed { index, item ->
+            if (index > 0) {
+                // 鍦ㄥ浘渚嬮」涔嬮棿娣诲姞姘村钩闂磋窛
+                builder.append(" ".repeat((itemSpacing / paint.measureText(" ")).toInt()))
+            }
+            
+            // 璁$畻姘村钩灞呬腑鎵�闇�鐨勭┖鏍兼暟
+            val textWidth = paint.measureText(item.description)
+            val paddingSpaces = ((maxWidth - textWidth) / 2 / paint.measureText(" ")).toInt()
+            
+            // 娣诲姞宸︿晶绌烘牸瀹炵幇灞呬腑
+            if (paddingSpaces > 0) {
+                builder.append(" ".repeat(paddingSpaces))
+            }
+            
+            // 娣诲姞鎻忚堪鏂囨湰
+            val startPosition = builder.length
+            builder.append(item.description)
+            
+            // 娣诲姞鍙充晶绌烘牸浠ョ‘淇濆搴︿竴鑷�
+            val remainingSpaces = ((maxWidth - textWidth) / paint.measureText(" ")).toInt() - paddingSpaces
+            if (remainingSpaces > 0) {
+                builder.append(" ".repeat(remainingSpaces))
+            }
+            
+            // 涓烘枃瀛楄缃偣鍑讳簨浠�
+            val clickableSpan = object : ClickableSpan() {
+                override fun onClick(view: View) {
+                    onCharClickListener?.invoke(item.description[0], index)
+                }
+
+                override fun updateDrawState(ds: android.text.TextPaint) {
+                    super.updateDrawState(ds)
+                    ds.isUnderlineText = false
+                    ds.color = currentTextColor
+                }
+            }
+            
+            builder.setSpan(
+                clickableSpan,
+                startPosition,
+                startPosition + item.description.length,
+                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+            )
+        }
+        
+        // 璁剧疆鏂囨湰瀵归綈鏂瑰紡涓哄眳涓�
+        gravity = Gravity.CENTER
+        
+        text = builder
+        movementMethod = android.text.method.LinkMovementMethod.getInstance()
+    }
+
+    /**
+     * 鍒ゆ柇鐐瑰嚮鏄惁鍦ㄤ笁瑙掑舰鍥炬爣鍖哄煙鍐�
+     */
+    private fun isClickOnTriangle(x: Float): Boolean {
+        val iconSize = triangleDrawable.intrinsicWidth
+        val iconLeft = paddingLeft - iconSize - compoundDrawablePadding
+        
+        // 鎵╁ぇ鐐瑰嚮鍖哄煙锛氬乏鍙冲悇澧炲姞 triangleClickPadding
+        return x <= (paddingLeft + triangleClickPadding) && 
+               x >= (iconLeft - triangleClickPadding)
+    }
+
+    /**
+     * 璁剧疆涓夎褰㈠浘鏍囦笌鏂囧瓧鐨勯棿璺�
+     * @param margin 闂磋窛鍊硷紙鍍忕礌锛�
+     */
+    fun setTriangleMargin(margin: Float) {
+        this.triangleMargin = margin
+        compoundDrawablePadding = margin.toInt()
+        setPadding(
+            (16 * context.resources.displayMetrics.density + margin).toInt(),
+            paddingTop,
+            paddingRight,
+            paddingBottom
+        )
+    }
+
+    /**
+     * 璁剧疆鎸夐挳鐨勫敮涓�鏍囪瘑绗�
+     * @param id 鏍囪瘑绗�
+     */
+    fun setButtonId(id: String) {
+        this.buttonId = id
+        // 鍔犺浇淇濆瓨鐨勭姸鎬�
+
+    }
 
 
+    /**
+     * 璁剧疆鍥句緥鍐呭
+     */
+    @JvmName("setLegendsList")
+    fun setLegends(items: List<Quadruple<Drawable, Drawable, String, Boolean>>) {
+        legendItems = items.map { (selectedIcon, unselectedIcon, description, isSelected) ->
+            selectedIcon.setBounds(0, 0, iconSize, iconSize)
+            unselectedIcon.setBounds(0, 0, iconSize, iconSize)
+            LegendItem(selectedIcon, unselectedIcon, description, isSelected)
+        }
+        
+        if (!isExpanded) {
+            text = collapsedText
+        } else {
+            invalidate()
+        }
+        requestLayout()
+    }
 
+    // 娣诲姞涓�涓� Java 鍙嬪ソ鐨勬柟娉�
+    @JvmName("setLegendsArray")
+    fun setLegends(vararg items: Quadruple<Drawable, Drawable, String, Boolean>) {
+        setLegends(items.toList())
+    }
 
+    // 娣诲姞涓�涓暟鎹被鏉ヨ〃绀哄洓鍏冪粍
+    data class Quadruple<A, B, C, D>(
+        val first: A,
+        val second: B,
+        val third: C,
+        val fourth: D
+    )
 
+    // 娣诲姞涓�涓究鎹风殑鎵╁睍鍑芥暟鏉ュ垱寤� Quadruple
+    fun <A, B, C, D> quadrupleOf(first: A, second: B, third: C, fourth: D): Quadruple<A, B, C, D> {
+        return Quadruple(first, second, third, fourth)
+    }
 
+    /**
+     * 娣诲姞璁剧疆鐩戝惉鍣ㄧ殑鏂规硶
+     */
+    fun setOnLegendItemClickListener(listener: OnLegendItemClickListener) {
+        legendItemClickListener = listener
+    }
 
+    /**
+     * 澶勭悊瑙︽懜浜嬩欢
+     */
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        when (event.action) {
+            MotionEvent.ACTION_DOWN -> {
+                // 妫�鏌ョ偣鍑绘槸鍚﹀湪涓夎褰㈠浘鏍囧尯鍩熷唴
+                if (isClickOnTriangle(event.x)) {
+                    toggleExpand()
+                    return true
+                }
+                
+                // 濡傛灉鏄睍寮�鐘舵�侊紝妫�鏌ユ槸鍚︾偣鍑讳簡鍥句緥椤�
+                if (isExpanded) {
+                    val clickedIndex = getClickedItemIndex(event.x, event.y)
+                    if (clickedIndex != -1) {
+                        toggleItemSelection(clickedIndex)
+                        return true
+                    }
+                } else if (!isExpanded && event.x > paddingLeft) {
+                    // 鍦ㄦ敹璧风姸鎬佷笅锛岀偣鍑婚潪涓夎褰㈠尯鍩熶篃灞曞紑
+                    toggleExpand()
+                    return true
+                }
+            }
+        }
+        return super.onTouchEvent(event)
+    }
 
+    /**
+     * 鑾峰彇鐐瑰嚮浣嶇疆瀵瑰簲鐨勫浘渚嬮」绱㈠紩
+     */
+    private fun getClickedItemIndex(x: Float, y: Float): Int {
+        if (!isExpanded) return -1
 
+        val maxWidth = legendItems.maxOf { item ->
+            maxOf(paint.measureText(item.description), iconSize.toFloat())
+        }
+        
+        val totalWidth = legendItems.size * maxWidth + 
+            (legendItems.size - 1) * itemSpacing
+        
+        val startX = (width - totalWidth) / 2
+        val iconTop = paddingTop + (height - legendItemHeight) / 2
+        val iconBottom = iconTop + legendItemHeight
 
+        // 妫�鏌ュ瀭鐩存柟鍚戞槸鍚﹀湪鍥句緥椤硅寖鍥村唴
+        if (y < iconTop || y > iconBottom) return -1
+
+        // 妫�鏌ユ按骞虫柟鍚戠偣鍑荤殑鏄摢涓浘渚嬮」
+        legendItems.forEachIndexed { index, _ ->
+            val itemStartX = startX + index * (maxWidth + itemSpacing)
+            val itemEndX = itemStartX + maxWidth
+            if (x >= itemStartX && x <= itemEndX) {
+                return index
+            }
+        }
+        return -1
+    }
+
+    /**
+     * 鍒囨崲鍥句緥椤圭殑閫変腑鐘舵��
+     */
+    private fun toggleItemSelection(index: Int) {
+        if (index < 0 || index >= legendItems.size) return
+        
+        legendItems[index].isSelected = !legendItems[index].isSelected
+        legendItemClickListener?.onLegendItemClick(
+            index, 
+            legendItems[index].isSelected
+        )
+
+        invalidate()
+    }
+
+    /**
+     * 璁剧疆灞曞紑鍚庣殑瀛椾綋澶у皬
+     * @param size 瀛椾綋澶у皬锛堝儚绱狅級
+     */
+    fun setExpandedTextSize(size: Float) {
+        this.expandedTextSize = size
+        if (isExpanded) {
+            invalidate()
+        }
+    }
+
+    /**
+     * 璁剧疆灞曞紑鍚庣殑瀛椾綋澶у皬锛圫P锛�
+     * @param sp 瀛椾綋澶у皬锛圫P锛�
+     */
+    fun setExpandedTextSizeSp(sp: Float) {
+        setExpandedTextSize(sp * context.resources.displayMetrics.scaledDensity)
+    }
 }
\ No newline at end of file

--
Gitblit v1.8.0