【问题标题】:Drawing LinearLayout with rounded corners绘制带圆角的 LinearLayout
【发布时间】:2013-04-01 03:14:18
【问题描述】:

我正在尝试实现一个用圆角绘制自身的 LinearLayout 子类。根据我的研究,我设置setWillNotDraw(false) 并覆盖onDraw() 以在画布中绘制一个圆角矩形:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), drawPaint, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
            | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
    canvas.drawRoundRect(bounds, mCornerRadius, mCornerRadius, roundPaint);
    canvas.restoreToCount(sc);
}

地点:

drawPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
drawPaint.setColor(0xffffffff);
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
roundPaint.setColor(0xffffffff);

DST_IN 在这里似乎是正确的选择(根据 APIDemos 示例),但是应该透明的区域(圆形区域)改为黑色背景,并且孩子的角落仍然可见。这是搭载 Android 4.2.2 的 Galaxy Nexus 上的结果:

有什么提示吗?

编辑:这是我想要实现的目标,对于 photoshopping 的粗糙表示抱歉:)

编辑 2:我向 GitHub 添加了一个示例可运行项目:https://github.com/venator85/RoundClippingLayout

谢谢 ;)

【问题讨论】:

  • 已经尝试过,但不起作用,因为我不是使用 ImageView 而是使用布局。我什至不知道 onDraw() 而不是 dispatchDraw(),甚至两者都是覆盖的正确方法。
  • 该算法将起作用。您只需要获取返回的 Bitmap 并使用它创建一个 BitmapDrawable。然后将其设置为视图的背景。
  • 您能否发布或链接到更多代码。如果你已经准备好调试代码会容易得多。
  • 问题中添加的示例可运行项目。谢谢

标签: android android-canvas


【解决方案1】:

不太一样: Romain Guy 写了一篇关于使用位图着色器裁剪图像边角的博客文章。不确定您是否想要扩展相同的内容。

http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/

【讨论】:

  • 我试过没有成功。此外,第一条评论显示了一个基于 clipPath 的解决方案,它需要在布局上禁用硬件加速,我想避免这种情况。
  • 您想避免禁用硬件加速的任何特殊原因?我认为如果没有 clipPath,剪辑子视图几乎是不可能的。
【解决方案2】:

试试这个,

布局:-

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout 
        android:id="@+id/linearLayout"
        android:layout_width="300dp"
        android:gravity="center"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        android:background="@drawable/rounded_edge">
        <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="foo" />
    </LinearLayout>
</RelativeLayout>

形状(可绘制):-rounded_edge.xml

<shape 
        xmlns:android="http://schemas.android.com/apk/res/android">
            <solid 
                android:color="@android:color/darker_gray">
            </solid>
            <stroke 
                 android:width="0dp" 
                 android:color="#424242">
            </stroke>
            <corners 
                 android:topLeftRadius="100dip"
                 android:topRightRadius="100dip"
                 android:bottomLeftRadius="100dip"
                 android:bottomRightRadius="100dip">
            </corners>
        </shape>

【讨论】:

  • padding添加到与topLeftRadiustopRightRadius相同的线性布局中...
  • 线性布局的填充与形状角半径完全不同。
【解决方案3】:

我可以实现这样的圆角线性布局。

步骤

1.创建自定义布局

public class RoundedLayout extends LinearLayout {
    private RectF rect;
    private Paint paint;

    public RoundedLayout(Context context) {
        super(context);
        init();
    }
    public RoundedLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        rect = new RectF(0.0f, 0.0f, getWidth(), getHeight());
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.parseColor("#7EB5D6"));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);           
        canvas.drawRoundRect(rect, 20, 20, paint);
    }
}

2.像这样在主布局中使用它

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#336699" >

    <com.example.rounded.RoundedLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="30dp"
        android:background="@android:color/transparent" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="foo" />

    </com.example.rounded.RoundedLayout>    

</LinearLayout>

【讨论】:

  • 你在自定义布局上试过 android:clipChildren="true" 吗?
  • 据我所知,clipChildren="false" 允许子视图将自己绘制到容器布局的边界之外。我想做相反的事情,即根据给定的形状(在本例中为圆角矩形)在布局inside 中剪裁部分子项。
  • 部分问题是由于 Android 绘制视图的方式。由于在父级(例如 LinearLayout)之后绘制了一个子级(例如 Button),并且您无权访问子级用来绘制自身的画笔,所以我猜 Xfermode 无济于事。
  • @Venator85,作为一种解决方法,您可以使用RelativeLayout 来包装LinearLayout 并将形状(弧)drawables 放置在RelativeLayout 的四个角上。
  • 圆角在哪里?我测试了它,但它没有。
【解决方案4】:

试试这个!! 取自post

将以下内容添加到文件中(例如 customshape.xml),然后将其放入 (res/drawable/customshape.xml)

<?xml version="1.0" encoding="UTF-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
 android:shape="rectangle"> 
 <gradient 
     android:startColor="#SomeGradientBeginColor"
     android:endColor="#SomeGradientEndColor" 
     android:angle="270"/> 

<corners 
     android:bottomRightRadius="7dp" 
     android:bottomLeftRadius="7dp" 
     android:topLeftRadius="7dp" 
     android:topRightRadius="7dp"/> 
</shape> 

创建此文件后,只需通过以下方式之一设置背景:

通过代码:

yourObject.setBackgroundResource(R.drawable.customshape);

或通过 XML,只需将以下属性添加到容器(例如:LinearLayout 或任何字段):

android:background="@drawable/customshape"

【讨论】:

  • 这是一个很棒的解决方案,1+ 用于分享。不得不做出改变以反映我的需求,比如半径有点不重要。 :)
【解决方案5】:

怎么样...

myLayout.setBackgroundResource(R.drawable.my_rounded_drawable);

那么……

my_rounded_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#FFFFFFFF" />
            <stroke android:width="1dip" android:color="#FF000000" />
            <corners android:radius="10dp" />
        </shape>
    </item>
</selector>

【讨论】:

  • 我已经用我想要实现的模型更新了问题:将孩子剪裁为圆角矩形,因此您的答案不适用。
  • @venator85 你需要的是Shapes development-in-android.blogspot.com.es/2012/05/…
  • @logray 这就是为什么你有我的投票,并在你的答案中发表评论,并附上此问题作者的链接 xD
【解决方案6】:

与其尝试削减布局的边角,不如在其顶部放置一个 Drawable 作为一种与背景颜色相匹配的框架?

【讨论】:

  • 不是通用解决方案,不适用于我的情况:舍入布局位于非均匀背景上的 ScrollView 中。
【解决方案7】:

[编辑:看起来这将被添加到 L:https://developer.android.com/preview/material/views-shadows.html#clip,它允许您将视图剪辑为矩形、圆形或圆形矩形可绘制对象的形状。]

我自己尝试了很长时间,但发现this answer 表明这是不可能的,因为 View 类是基于 Rect 类的。我刚刚检查了来源,从 cmets 看来情况仍然如此。

摩托罗拉将于今年夏天晚些时候发布 Moto 360(圆面 Android Wear 手表),因此可能会更新框架以允许具有矩形以外形状的视图。

【讨论】: