You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:如何实现票据样式三角形布局?是否有更优方案?

Better Alternatives for Ticket-Style Triangle Strip Layout

Great question! Adding 20+ AppCompatImageViews just to create a row of triangles is far from optimal—it bloats your layout XML, adds unnecessary view hierarchy overhead, and makes future adjustments (like changing triangle count/size) a hassle. Let's break down several cleaner, more performant alternatives:

1. Custom Drawable (Top Recommendation)

Create a reusable Drawable that draws the entire strip of triangles in one pass. This lets you use a single ImageView or even set it directly as a layout background.

Kotlin Implementation:

class TriangleStripDrawable(
    private val triangleColor: Int,
    private val triangleSize: Int // Size of each triangle's base/height
) : Drawable() {

    override fun draw(canvas: Canvas) {
        val paint = Paint().apply {
            color = triangleColor
            style = Paint.Style.FILL
            isAntiAlias = true
        }

        val totalWidth = bounds.width()
        val stripHeight = bounds.height()
        val triangleCount = totalWidth / triangleSize

        // Draw each triangle in the strip
        for (i in 0 until triangleCount) {
            val leftOffset = i * triangleSize
            val path = Path().apply {
                // Adjust path coordinates to match your desired triangle orientation
                moveTo(leftOffset.toFloat(), stripHeight.toFloat())
                lineTo((leftOffset + triangleSize).toFloat(), stripHeight.toFloat())
                lineTo((leftOffset + triangleSize / 2).toFloat(), 0f)
                close()
            }
            canvas.drawPath(path, paint)
        }
    }

    override fun setAlpha(alpha: Int) {}
    override fun setColorFilter(colorFilter: ColorFilter?) {}
    override fun getOpacity(): Int = PixelFormat.OPAQUE
}

Usage in Code:

// Initialize the drawable with your desired color and size
val triangleStrip = TriangleStripDrawable(
    Color.parseColor("#c6802a"),
    resources.getDimensionPixelSize(R.dimen.dimen_20dp)
)

// Set as background for a LinearLayout or ImageView
binding.triangleStripContainer.background = triangleStrip

2. Vector Drawable + Tiled Repeat

Create a single triangle vector asset, then convert it to a tiled drawable that repeats horizontally. This avoids writing custom code if you prefer XML-first approaches.

Step 1: Create vector_triangle.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="20dp"
    android:height="20dp"
    android:viewportWidth="20"
    android:viewportHeight="20">
    <!-- Path for upward-pointing triangle (adjust pathData for orientation) -->
    <path
        android:fillColor="#c6802a"
        android:pathData="M0,20 L20,20 L10,0 Z" />
</vector>

Step 2: Apply Tiled Repeat in Code

val triangleVector = ContextCompat.getDrawable(this, R.drawable.vector_triangle) ?: return

// Convert vector to bitmap for tiling
val bitmap = Bitmap.createBitmap(
    triangleVector.intrinsicWidth,
    triangleVector.intrinsicHeight,
    Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
triangleVector.setBounds(0, 0, canvas.width, canvas.height)
triangleVector.draw(canvas)

// Create tiled drawable
val tiledDrawable = BitmapDrawable(resources, bitmap).apply {
    tileModeX = Shader.TileMode.REPEAT // Repeat horizontally
}

// Set as layout background
binding.triangleStripContainer.background = tiledDrawable

3. Custom View

If you want a self-contained UI component, create a custom View that draws the triangle strip directly. This works great if you need to add interactivity later.

Kotlin Implementation:

class TriangleStripView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val triangleColor = Color.parseColor("#c6802a")
    private val triangleSize = resources.getDimensionPixelSize(R.dimen.dimen_20dp)
    private val paint = Paint().apply {
        color = triangleColor
        style = Paint.Style.FILL
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val totalWidth = measuredWidth
        val stripHeight = measuredHeight
        val triangleCount = totalWidth / triangleSize

        for (i in 0 until triangleCount) {
            val leftOffset = i * triangleSize
            val path = Path().apply {
                moveTo(leftOffset.toFloat(), stripHeight.toFloat())
                lineTo((leftOffset + triangleSize).toFloat(), stripHeight.toFloat())
                lineTo((leftOffset + triangleSize / 2).toFloat(), 0f)
                close()
            }
            canvas.drawPath(path, paint)
        }
    }
}

Usage in XML:

<com.yourpackage.TriangleStripView
    android:layout_width="match_parent"
    android:layout_height="20dp" />

Why These Are Better

All these approaches cut your view count from 20+ down to 1, which improves layout performance (especially on older devices) and makes your code easier to maintain. You can quickly adjust triangle size, color, or orientation without editing dozens of XML entries.

内容的提问来源于stack exchange,提问作者Ankush Kapoor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:27:42