用基本形状画一根香烟
Drawing a cigarette with basic shapes
我正在尝试用 "ash" 视图占 "smokeable" 视图的百分比绘制香烟。它必须是一个百分比,因为我将使用一个滑块来改变 "ash" 视图的百分比。
这是我想要的:
这是我的代码:
<LinearLayout
android:id="@+id/cigarette"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginBottom="20dp"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".25"
android:background="#ff7700" />
<LinearLayout
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".75"
android:background="#cccccc"
android:orientation="horizontal">
<View
android:id="@+id/ash"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".33"
android:background="#777777"
android:gravity="right" />
</LinearLayout>
</LinearLayout>
在这个例子中,我希望烟灰占可吸烟视图的 33%。我不明白为什么这不起作用。任何帮助将不胜感激。
鉴于所有三个元素都在一条直线上,您只需要一个 LinearLayout
父元素:
<LinearLayout
android:id="@+id/cigarette"
android:layout_width="match_parent"
android:layout_height="20dp"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="25"
android:background="#ff7700" />
<View
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="65"
android:background="#cccccc" />
<View
android:id="@+id/ash"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="10"
android:background="#777777" />
</LinearLayout>
我认为 最简单 最干净的方法是为您定制 View
"cigarette",它将由 filter/smokeable/ash 组成, 每个部分都有不同的颜色。
因此声明一些样式属性,比如 attrs.xml
<resources>
<declare-styleable name="CigaretteView">
<attr name="filterColor" format="color" />
<attr name="smokeableColor" format="color" />
<attr name="ashColor" format="color" />
<attr name="filterWidth" format="dimension" />
</declare-styleable>
</resources>
View
class本身:
class CigaretteView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
companion object {
private val DEFAULT_FILTER_COLOR = 0xffbbaa00.toInt()
private val DEFAULT_SMOKABLE_COLOR = 0xffffffff.toInt()
private val DEFAULT_ASH_COLOR = 0xff888888.toInt()
private val DEFAUALT_FILTER_WIDTH_PX = 120
}
private val filterPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val smokeablePaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val ashPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private var filterWidthPx = DEFAUALT_FILTER_WIDTH_PX
private val rect = Rect()
var smokedPercent = 0f
set(value) {
field = value
invalidate()
}
init {
val a = context.theme.obtainStyledAttributes(attrs, R.styleable.CigaretteView, 0, 0)
var filterColor = DEFAULT_FILTER_COLOR
var smokeableColor = DEFAULT_SMOKABLE_COLOR
var ashColor = DEFAULT_ASH_COLOR
try {
filterColor = a.getColor(R.styleable.CigaretteView_filterColor, filterColor)
smokeableColor = a.getColor(R.styleable.CigaretteView_smokeableColor, smokeableColor)
ashColor = a.getColor(R.styleable.CigaretteView_ashColor, ashColor)
filterWidthPx = a.getDimensionPixelSize(R.styleable.CigaretteView_filterWidth, filterWidthPx)
} finally {
a.recycle()
}
filterPaint.color = filterColor
smokeablePaint.color = smokeableColor
ashPaint.color = ashColor
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
rect.set(0, 0, filterWidthPx, height)
canvas.drawRect(rect, filterPaint)
val leftOver = (width - filterWidthPx).toFloat()
val ashStartPoint = (width - leftOver * smokedPercent).toInt()
rect.set(filterWidthPx, 0, ashStartPoint, height)
canvas.drawRect(rect, smokeablePaint)
rect.set(ashStartPoint, 0, width, height)
canvas.drawRect(rect, ashPaint)
}
}
您的 xml 布局将简化为
<com.example.CigaretteView
android:id="@+id/cigaretteView"
android:layout_width="match_parent"
android:layout_height="48dp"
app:filterWidth="48dp"
app:filterColor="#ffbbaa00"
app:smokeableColor="#ffffffff"
app:ashColor="#ff888888"/>
然后您可以简单地指定灰分百分比值
myCigaretteView.smokedPercent = percent
其中 percent
从 0(香烟完好无损)到 1(香烟完全吸完)。
里面的LinearLayout
需要另一个childView
作为香烟的not-yet-consumed部分。在您的示例中,它的 layout_weight
必须为 1 - 0.33 = 0.67(两个兄弟姐妹的权重总和必须始终为 1)。
<LinearLayout
android:id="@+id/cigarette"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_below="@+id/titleText"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".25"
android:background="#ff7700" />
<LinearLayout
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".75"
android:orientation="horizontal">
<View
android:id="@+id/rest"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#cccccc"
android:layout_weight=".67"
/>
<View
android:id="@+id/ash"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".33"
android:background="#777777"
android:gravity="right" />
</LinearLayout>
</LinearLayout>
请注意,虽然这会修复您的代码,但 "nested weighted LinearLayout" 方法并不是一个好的方法,即使现代设备不应该 运行 出现性能问题。
涉及自定义 View
的 要好得多,因为您只需要一个 View
,而不是两个 ViewGroup
加上三个 View
。您有一种方法可以轻松更改百分比,而且所有计算和绘图部分都被很好地封装了。
这是我能想到的最简单的东西,它可以满足您的需要:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#777777"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.25"
android:background="#ff7700"/>
<View
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.75"
android:background="#cccccc"
android:transformPivotX="0px"/>
</LinearLayout>
现在您可以使用任意百分比调用 smokeable.setScaleX()
以获得所需的结果。
我正在尝试用 "ash" 视图占 "smokeable" 视图的百分比绘制香烟。它必须是一个百分比,因为我将使用一个滑块来改变 "ash" 视图的百分比。
这是我想要的:
这是我的代码:
<LinearLayout
android:id="@+id/cigarette"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginBottom="20dp"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".25"
android:background="#ff7700" />
<LinearLayout
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".75"
android:background="#cccccc"
android:orientation="horizontal">
<View
android:id="@+id/ash"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".33"
android:background="#777777"
android:gravity="right" />
</LinearLayout>
</LinearLayout>
在这个例子中,我希望烟灰占可吸烟视图的 33%。我不明白为什么这不起作用。任何帮助将不胜感激。
鉴于所有三个元素都在一条直线上,您只需要一个 LinearLayout
父元素:
<LinearLayout
android:id="@+id/cigarette"
android:layout_width="match_parent"
android:layout_height="20dp"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="25"
android:background="#ff7700" />
<View
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="65"
android:background="#cccccc" />
<View
android:id="@+id/ash"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="10"
android:background="#777777" />
</LinearLayout>
我认为 最简单 最干净的方法是为您定制 View
"cigarette",它将由 filter/smokeable/ash 组成, 每个部分都有不同的颜色。
因此声明一些样式属性,比如 attrs.xml
<resources>
<declare-styleable name="CigaretteView">
<attr name="filterColor" format="color" />
<attr name="smokeableColor" format="color" />
<attr name="ashColor" format="color" />
<attr name="filterWidth" format="dimension" />
</declare-styleable>
</resources>
View
class本身:
class CigaretteView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
companion object {
private val DEFAULT_FILTER_COLOR = 0xffbbaa00.toInt()
private val DEFAULT_SMOKABLE_COLOR = 0xffffffff.toInt()
private val DEFAULT_ASH_COLOR = 0xff888888.toInt()
private val DEFAUALT_FILTER_WIDTH_PX = 120
}
private val filterPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val smokeablePaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val ashPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private var filterWidthPx = DEFAUALT_FILTER_WIDTH_PX
private val rect = Rect()
var smokedPercent = 0f
set(value) {
field = value
invalidate()
}
init {
val a = context.theme.obtainStyledAttributes(attrs, R.styleable.CigaretteView, 0, 0)
var filterColor = DEFAULT_FILTER_COLOR
var smokeableColor = DEFAULT_SMOKABLE_COLOR
var ashColor = DEFAULT_ASH_COLOR
try {
filterColor = a.getColor(R.styleable.CigaretteView_filterColor, filterColor)
smokeableColor = a.getColor(R.styleable.CigaretteView_smokeableColor, smokeableColor)
ashColor = a.getColor(R.styleable.CigaretteView_ashColor, ashColor)
filterWidthPx = a.getDimensionPixelSize(R.styleable.CigaretteView_filterWidth, filterWidthPx)
} finally {
a.recycle()
}
filterPaint.color = filterColor
smokeablePaint.color = smokeableColor
ashPaint.color = ashColor
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
rect.set(0, 0, filterWidthPx, height)
canvas.drawRect(rect, filterPaint)
val leftOver = (width - filterWidthPx).toFloat()
val ashStartPoint = (width - leftOver * smokedPercent).toInt()
rect.set(filterWidthPx, 0, ashStartPoint, height)
canvas.drawRect(rect, smokeablePaint)
rect.set(ashStartPoint, 0, width, height)
canvas.drawRect(rect, ashPaint)
}
}
您的 xml 布局将简化为
<com.example.CigaretteView
android:id="@+id/cigaretteView"
android:layout_width="match_parent"
android:layout_height="48dp"
app:filterWidth="48dp"
app:filterColor="#ffbbaa00"
app:smokeableColor="#ffffffff"
app:ashColor="#ff888888"/>
然后您可以简单地指定灰分百分比值
myCigaretteView.smokedPercent = percent
其中 percent
从 0(香烟完好无损)到 1(香烟完全吸完)。
里面的LinearLayout
需要另一个childView
作为香烟的not-yet-consumed部分。在您的示例中,它的 layout_weight
必须为 1 - 0.33 = 0.67(两个兄弟姐妹的权重总和必须始终为 1)。
<LinearLayout
android:id="@+id/cigarette"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_below="@+id/titleText"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".25"
android:background="#ff7700" />
<LinearLayout
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".75"
android:orientation="horizontal">
<View
android:id="@+id/rest"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#cccccc"
android:layout_weight=".67"
/>
<View
android:id="@+id/ash"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight=".33"
android:background="#777777"
android:gravity="right" />
</LinearLayout>
</LinearLayout>
请注意,虽然这会修复您的代码,但 "nested weighted LinearLayout" 方法并不是一个好的方法,即使现代设备不应该 运行 出现性能问题。
涉及自定义 View
的 View
,而不是两个 ViewGroup
加上三个 View
。您有一种方法可以轻松更改百分比,而且所有计算和绘图部分都被很好地封装了。
这是我能想到的最简单的东西,它可以满足您的需要:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#777777"
android:orientation="horizontal">
<View
android:id="@+id/butt"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.25"
android:background="#ff7700"/>
<View
android:id="@+id/smokeable"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.75"
android:background="#cccccc"
android:transformPivotX="0px"/>
</LinearLayout>
现在您可以使用任意百分比调用 smokeable.setScaleX()
以获得所需的结果。