我有一个自定义视图,通过使用路径显示星形。此视图按预期工作,但现在我想将其实施转移到新的Google Material建议。
不幸的是elevation
取决于凸起的轮廓,我还没有找到解决方案。
您是否知道任何已知的变通方法或任何其他创造性解决方案?
这是我的凹路:
double outerSize = w / 2;
double innerSize = w / 5;
double delta = 2.0*Math.PI/5.0;
double rotation = Math.toRadians(-90);
double xpos = w/2.0;
double ypos = h/2.0;
mPath = new Path();
mPath.moveTo((float)(outerSize * Math.cos(delta + rotation) + xpos),
(float)(outerSize * Math.sin(delta + rotation) + ypos));
for(int point= 0;point<6;point++)
{
mPath.lineTo((float) (innerSize * Math.cos(delta * (point + 0.5) + rotation) + xpos),
(float) (innerSize * Math.sin(delta * (point + 0.5) + rotation) + ypos));
mPath.lineTo((float) (outerSize * Math.cos(delta * (point + 1.0) + rotation) + xpos),
(float) (outerSize * Math.sin(delta * (point + 1.0) + rotation) + ypos));
}
mPath.close();
我已经尝试过这段代码但没有成功,这在凸视图上运行良好。
@TargetApi(21)
private class StarOutline extends ViewOutlineProvider {
@Override
public void getOutline(View view, Outline outline) {
StartView r = (StartView) view;
// i know here say setConvexPath not setConcavePath
outline.setConvexPath(r.mPath);
}
}
但正如预期的那样,我得到了例外:
java.lang.IllegalArgumentException: path must be convex
at android.graphics.Outline.setConvexPath(Outline.java:216)
知道如何实现这个目标吗?
答案 0 :(得分:5)
正如一些评论和答案所指出的那样,原生android阴影仅适用于凸轮廓。
因此,您可以自己手动绘制假阴影(通过画布,位图等),也可以依靠别人的库为您绘制假阴影(Google的Material Components库等)。
您是否知道任何已知的解决方法或任何其他创造性的解决方案?
如果必须依靠本机android阴影,则可以尝试将形状分解为多个凸形并分别绘制。
这里是一个例子:
我将星形分解为1个五边形和5个三角形多边形(都具有凸轮廓线)并分别绘制。
TriangleView:
public class TriangleView extends View {
private final Path path = new Path();
private final Paint paint = new Paint();
public TriangleView(Context context) {
super(context);
init(context, null, 0,0);
}
public TriangleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0,0);
}
public TriangleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
public TriangleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, defStyleRes);
}
private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes){
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.argb(255, 100, 100, 255));
setOutlineProvider(new OutlineProvider());
}
public void setPoints(float x1, float y1, float x2, float y2, float x3, float y3){
path.reset();
path.moveTo(x1, y1);
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.close();
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
private static class OutlineProvider extends ViewOutlineProvider{
@Override
public void getOutline(View view, Outline outline) {
Path path = ((TriangleView)view).path;
outline.setConvexPath(path);
}
}
}
PentagonView:
public class PentagonView extends View {
private final Path path = new Path();
private final Paint paint = new Paint();
public PentagonView(Context context) {
super(context);
init(context, null, 0,0);
}
public PentagonView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0,0);
}
public PentagonView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
public PentagonView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, defStyleRes);
}
private void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes){
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.argb(255, 150, 150, 255));
setOutlineProvider(new OutlineProvider());
}
public void setPoints(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float x5, float y5){
path.reset();
path.moveTo(x1, y1);
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.lineTo(x4, y4);
path.lineTo(x5, y5);
path.close();
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
private static class OutlineProvider extends ViewOutlineProvider {
@Override
public void getOutline(View view, Outline outline) {
Path path = ((PentagonView)view).path;
outline.setConvexPath(path);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".MainActivity">
<app.eccweizhi.concaveshadow.PentagonView
android:id="@+id/pentagonView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp" />
<app.eccweizhi.concaveshadow.TriangleView
android:id="@+id/triangle1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp" />
<app.eccweizhi.concaveshadow.TriangleView
android:id="@+id/triangle2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp" />
<app.eccweizhi.concaveshadow.TriangleView
android:id="@+id/triangle3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp" />
<app.eccweizhi.concaveshadow.TriangleView
android:id="@+id/triangle4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp" />
<app.eccweizhi.concaveshadow.TriangleView
android:id="@+id/triangle5"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="4dp" />
</FrameLayout>
然后我像这样使用它们
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
pentagonView.setPoints(
520f,
520f,
640f,
520f,
677.0818f,
634.1266f,
580f,
704.6608f,
482.9182f,
634.1266f
)
triangle1.setPoints(520f, 520f, 640f, 520f, 580f, 400f)
triangle2.setPoints(640f, 520f, 677.0818f, 634.1266f, 777f, 520f)
triangle3.setPoints(677.0818f, 634.1266f, 580f, 704.6608f, 697f, 750f)
triangle4.setPoints(580f, 704.6608f, 482.9182f, 634.1266f, 440f, 750f)
triangle5.setPoints(482.9182f, 634.1266f, 520f, 520f, 400f, 520f)
}
}
答案 1 :(得分:0)
AndroidX包中有一个名为MaterialShapeDrawable的新可绘制对象。给定路径,它可以将阴影渲染为凹凸形状。
https://developer.android.com/reference/com/google/android/material/shape/MaterialShapeDrawable
这是如何在没有MaterialShapeDrawable的情况下为凹形提供阴影的方法: