要求
如何创建如下所示的视图。
我想在屏幕上绘制一个视图,该视图被分成几段,显示整个视图的值百分比。我的要求是
我尝试过的想法/事情
(1)自定义视图并排呈现3个矩形
我尝试了一个自定义视图,该视图可以并排渲染3个矩形。但是这些显然有角。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int viewHeight = 50;
canvas.drawrect(0, 0, 60, viewHeight, paint); // A
canvas.drawrect(60, 0, 120, viewHeight, paint); // B
canvas.drawrect(120,0, 180, viewHeight, paint); // C
}
(2)具有圆角的形状
我知道我可以使用Shape通过以下方法定义带有圆角的矩形,但这只是一种颜色。
<shape xmlns:android="http://schemas.android.com/apk/res/android">
...
<corners
android:radius="4dp" />
....
</shape>
(3)层列表
从Android rectangle shape with two different color中,我看到可以使用图层列表将形状中的每个项目指定为具有不同的颜色。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<size
android:width="40dp"
android:height="40dp" />
<solid android:color="#F86F05" />
</shape>
</item>
<item android:top="10dp">
<shape android:shape="rectangle">
<size
android:width="30dp"
android:height="30dp" />
<solid android:color="#B31F19" />
</shape>
</item>
</layer-list>
(4)带角的图层列表?
我可以在整个图层列表中添加“ corners”标签以获得圆角的主角吗?我认为不是,并且角落部分必须位于“商品”的形状标签中。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:radius="4dp" />
<item>
<shape android:shape="rectangle">
<size
android:width="40dp"
android:height="40dp" />
<solid android:color="#F86F05" />
</shape>
</item>
<item android:top="10dp">
<shape android:shape="rectangle">
<size
android:width="30dp"
android:height="30dp" />
<solid android:color="#B31F19" />
</shape>
</item>
</layer-list>
摘要
这最后一个离我的要求越来越近
更新:如何添加海拔/灰色边界
感谢您使用“ @ 0X0nosugar”作为解决方案。我现在想添加一个高程或略微的灰色边框,因为其中一种颜色是光线不足且接近于背景色。当我添加以下内容时,我得到一个矩形阴影,它的弯角看起来很可怕。
android:elevation="2dp"
android:outlineProvider="bounds"
我希望它显示如下
答案 0 :(得分:3)
您可以创建自定义View
,它将在Canvas
的裁剪部分上绘制矩形:
public class RoundedCornersSegmentedView extends View {
private Paint paintA, paintB, paintC;
private float cornerRadius;
private float measuredWidth, measuredHeight;
private RectF rect = new RectF(0, 0, 0,0);
private Path rectPath = new Path();
public RoundedCornersSegmentedView(Context context) {
super(context);
init();
}
public RoundedCornersSegmentedView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundedCornersSegmentedView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setWillNotDraw(false);
// add this so Canvas.clipPath() will give the desired result also for devices running Api level lower than 17,
// see https://stackoverflow.com/a/30354461/5015207
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
paintA = new Paint(Paint.ANTI_ALIAS_FLAG);
paintA.setColor(Color.GREEN);
paintA.setStyle(Paint.Style.FILL);
paintB = new Paint(Paint.ANTI_ALIAS_FLAG);
paintB.setColor(Color.YELLOW);
paintB.setStyle(Paint.Style.FILL);
paintC = new Paint(Paint.ANTI_ALIAS_FLAG);
paintC.setColor(Color.MAGENTA);
paintC.setStyle(Paint.Style.FILL);
// with <dimen name="corner_radius">60dp</dimen> in res/values/dimens.xml
cornerRadius = getResources().getDimensionPixelSize(R.dimen.corner_radius);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
measuredWidth = right - left;
measuredHeight = bottom - top;
rect.set(0, 0, measuredWidth, measuredHeight);
rectPath.reset();
rectPath.addRoundRect(rect, cornerRadius, cornerRadius, Path.Direction.CW);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.clipPath(rectPath);
canvas.drawRect(0,0,measuredWidth/3f, measuredHeight, paintA);
canvas.drawRect(measuredWidth/3f,0,2 * measuredWidth/3f, measuredHeight, paintB);
canvas.drawRect(2 * measuredWidth/3f,0,measuredWidth, measuredHeight, paintC);
}
}
如果要添加某种半透明边缘,则可以使用具有透明颜色的Paint
并填充类型Paint.Style.STROKE
并绘制一个圆角矩形。
Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// material color "Blue Gray 400",
// see https://material.io/design/color/the-color-system.html
shadowPaint.setColor(Color.argb(30, 120, 144, 156));
shadowPaint.setStyle(Paint.Style.STROKE);
shadowPaint.setStrokeWidth(30);
矩形(在onLayout()
外部实例化以提高性能)
private RectF shadowRect = new RectF(0,0,0,0);
在onLayout()
中:
int inset = 20;
shadowRect.set(inset, inset, measuredWidth - inset, measuredHeight - inset);
您应该切换阴影Paint
的颜色/ alpha值以及笔划宽度和插图的值,直到您认为它看起来不错为止。
在绘制彩色段之后,在onDraw()
中应用:
canvas.drawRoundRect(shadowRect, cornerRadius, cornerRadius, shadowPaint);
如果您堆叠具有减小的笔触宽度和增加的inset的半透明Paint
,例如构建自己的颜色渐变,它也可能看起来不错(更多3D)。
感谢@wblaschko在ViewOutlineProvider
上共享代码段!
我将其添加到示例中,并获得了以下效果:
更改我的代码(注意:仅适用于21级以上的Api)
自定义视图的内部类:
@TargetApi(21)
static class ScalingOutlineProvider extends ViewOutlineProvider {
private int cornerRadius;
ScalingOutlineProvider(int cornerRadius){
this.cornerRadius = cornerRadius;
}
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight (), cornerRadius);
}
}
在init()
的末尾:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
// elevation of 4dp (cornerRadius was 60dp)
setElevation(cornerRadius/15);
setOutlineProvider(new ScalingOutlineProvider(cornerRadius));
}
答案 1 :(得分:2)
对于影子跟踪问题,您有两个选择。使用内置方法或绘制自己的方法(取决于需要)。前者可能是正确的方法,除非您需要自定义阴影。
内置方法
请参阅此博客文章中“概述”部分: https://android.jlelse.eu/mastering-shadows-in-android-e883ad2c9d5b
帖子中的示例代码:
创建OutlineProvider
#on master branch, with no unstaged or uncommited changes:
git branch backup
git reset --hard F
git checkout yellow
git reset --hard E
git cherry-pick C
git cherry-pick B
#merge yellow branch into master, however you usually do that
git checkout master
git cherry-pick D
将大纲提供程序添加到视图中
C
自己绘制
对于边框,可以使用View.getElevation()获得所需的高度:https://developer.android.com/reference/android/view/View#getElevation(),然后在阴影的条形后面绘制另一个形状。
答案 2 :(得分:0)
您应该使用CardView
看一下这个示例:
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_margin="@dimen/activity_vertical_margin"
app:cardPreventCornerOverlap="false"
app:cardCornerRadius="@dimen/activity_vertical_margin"
android:foreground="?android:attr/selectableItemBackground">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/view1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#0c21a9"
app:layout_constraintWidth_percent="0.33"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<View
android:id="@+id/view2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#51c914"
app:layout_constraintWidth_percent="0.33"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/view1" />
<View
android:id="@+id/view3"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#a90c0c"
app:layout_constraintWidth_percent="0.33"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/view2" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
此属性可防止在圆角app:cardPreventCornerOverlap="false"
上重叠
请注意,我使用的是Google AndroidX推荐的库androidx
。如果愿意,可以使用旧版支持库。
答案 3 :(得分:0)
例如(将颜色调整为所需的颜色,边距,高度等):
您可以使用LinearLayout
作为具有horizontal
方向的根布局并分配一些weights
,创建子布局并向其添加自定义背景来创建此布局。简单,没有太多的嵌套布局。
例如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="20dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/statsLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="true"
android:background="@drawable/left_background">
<TextView
android:id="@+id/stats"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="A%"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@android:color/black" />
</LinearLayout>
<LinearLayout
android:id="@+id/ncaaInfoLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="true"
android:background="@drawable/middle_background">
<TextView
android:id="@+id/ncaaInfo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="B%"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@android:color/black" />
</LinearLayout>
<LinearLayout
android:id="@+id/accountLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="true"
android:background="@drawable/right_background">
<TextView
android:id="@+id/account"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="C%"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:textColor="@android:color/black" />
</LinearLayout>
</LinearLayout>
比为每个孩子LinearLayout
为剩下的left_bacground.xml
创建背景:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="30dp"
android:topLeftRadius="30dp" />
<solid android:color="@android:color/holo_green_dark" />
比LinearLayout in middle
middle_background.xml`:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/holo_orange_dark" />
最后一个LinearLayout
代表右边的right_bacgkround.xml
:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomRightRadius="30dp"
android:topRightRadius="30dp" />
<solid android:color="@android:color/holo_blue_dark" />