web-dev-qa-db-ja.com

角が丸いAndroidでビューを作成する方法

Androidに角の丸いビューを作成しようとしています。これまでに見つけた解決策は、角が丸い形状を定義し、そのビューの背景として使用することです。

これが私がやったことです、以下に示すようにドロウアブルを定義します

<padding
Android:top="2dp"
Android:bottom="2dp"/>
<corners Android:bottomRightRadius="20dp"
Android:bottomLeftRadius="20dp"
Android:topLeftRadius="20dp"
Android:topRightRadius="20dp"/>

今、私はこれを以下のようにレイアウトの背景として使用しました

<LinearLayout
        Android:orientation="vertical"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_marginLeft="10dp"
        Android:layout_marginRight="10dp"
        Android:layout_marginBottom="10dp"
        Android:clipChildren="true"
        Android:background="@drawable/rounded_corner">

これは完璧に機能し、ビューのエッジが丸くなっていることがわかります。

しかし、私のレイアウトには、他にも多くの子ビューがありますImageViewまたはMapViewと言います。上記のレイアウト内にImageViewを配置すると、画像の角はクリップ/トリミングされず、完全に表示されます。

私は here で説明したような動作をさせるための別の回避策を見ました。

しかし、ビューの角を丸く設定する方法はありますか?そのすべての子ビューは角の丸いメインビュー内に含まれていますか?

ありがとう。

72
Zach

別のアプローチは、以下のようなカスタムレイアウトクラスを作成することです。このレイアウトは、最初にそのコンテンツをオフスクリーンビットマップに描画し、オフスクリーンビットマップを角丸長方形でマスクしてから、実際のキャンバスにオフスクリーンビットマップを描画します。

私はそれを試しましたが、(少なくとも私の簡単なテストケースでは)うまくいくようです。もちろん、通常のレイアウトと比較してパフォーマンスに影響します。

package com.example;

import Android.content.Context;
import Android.graphics.*;
import Android.util.AttributeSet;
import Android.util.DisplayMetrics;
import Android.util.TypedValue;
import Android.widget.FrameLayout;

public class RoundedCornerLayout extends FrameLayout {
    private final static float CORNER_RADIUS = 40.0f;

    private Bitmap maskBitmap;
    private Paint paint, maskPaint;
    private float cornerRadius;

    public RoundedCornerLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

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

    public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);

        Paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

        setWillNotDraw(false);
    }

    @Override
    public void draw(Canvas canvas) {
        Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas offscreenCanvas = new Canvas(offscreenBitmap);

        super.draw(offscreenCanvas);

        if (maskBitmap == null) {
            maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
        }

        offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
        canvas.drawBitmap(offscreenBitmap, 0f, 0f, Paint);
    }

    private Bitmap createMask(int width, int height) {
        Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
        Canvas canvas = new Canvas(mask);

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Paint.setColor(Color.WHITE);

        canvas.drawRect(0, 0, width, height, Paint);

        Paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Paint);

        return mask;
    }
}

これを通常のレイアウトのように使用します。

<com.example.RoundedCornerLayout
    Android:layout_width="200dp"
    Android:layout_height="200dp">

    <ImageView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:src="@drawable/test"/>

    <View
        Android:layout_width="match_parent"
        Android:layout_height="100dp"
        Android:background="#ff0000"
        />

</com.example.RoundedCornerLayout>
111

または、次のようにAndroid.support.v7.widget.CardViewを使用できます。

<Android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    card_view:cardBackgroundColor="@color/white"
    card_view:cardCornerRadius="4dp">

    <!--YOUR CONTENT-->
</Android.support.v7.widget.CardView>
46
rocketspacer

shape.xml

<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:shape="rectangle">

    <solid Android:color="#f6eef1" />

    <stroke
        Android:width="2dp"
        Android:color="#000000" />

    <padding
        Android:bottom="5dp"
        Android:left="5dp"
        Android:right="5dp"
        Android:top="5dp" />

    <corners Android:radius="5dp" />

</shape>

そしてあなたの内側のレイアウト

<LinearLayout
        Android:orientation="vertical"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginLeft="10dp"
        Android:layout_marginRight="10dp"
        Android:layout_marginBottom="10dp"
        Android:clipChildren="true"
        Android:background="@drawable/shape">

        <ImageView
             Android:layout_width="match_parent"
             Android:layout_height="match_parent"
             Android:src="@drawable/your image"
             Android:background="@drawable/shape">

</LinearLayout>
40

タッチリスナーをレイアウトに追加するときに問題が発生した場合。このレイアウトを親レイアウトとして使用します。

import Android.content.Context;
import Android.graphics.Bitmap;
import Android.graphics.Canvas;
import Android.graphics.Paint;
import Android.graphics.Path;
import Android.graphics.RectF;
import Android.graphics.Region;
import Android.util.AttributeSet;
import Android.util.DisplayMetrics;
import Android.util.TypedValue;
import Android.view.View;
import Android.widget.FrameLayout;

public class RoundedCornerLayout extends FrameLayout {
    private final static float CORNER_RADIUS = 6.0f;
    private float cornerRadius;

    public RoundedCornerLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

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

    public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }


    @Override
    protected void dispatchDraw(Canvas canvas) {
        int count = canvas.save();

        final Path path = new Path();
        path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW);
        canvas.clipPath(path, Region.Op.REPLACE);

        canvas.clipPath(path);
        super.dispatchDraw(canvas);
        canvas.restoreToCount(count);
    }


}

なので

<?xml version="1.0" encoding="utf-8"?>
<com.example.view.RoundedCornerLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <RelativeLayout
        Android:id="@+id/patentItem"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:paddingRight="20dp">
        ... your child goes here
    </RelativeLayout>
</com.example.view.RoundedCornerLayout>
16
Sushant

Jaap van Hengstumの答え はうまく機能しますが、高価であると思います。たとえば、このメソッドをボタンに適用すると、ビューがビットマップとしてレンダリングされるため、タッチ効果が失われます。

私にとって最良の方法で最も簡単な方法は、次のようにビューにマスクを適用することです。

@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
    super.onSizeChanged(width, height, oldWidth, oldHeight);

    float cornerRadius = <whatever_you_want>;
    this.path = new Path();
    this.path.addRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Path.Direction.CW);
}

@Override
protected void dispatchDraw(Canvas canvas) {
    if (this.path != null) {
        canvas.clipPath(this.path);
    }
    super.dispatchDraw(canvas);
}
13
Donkey

drawableフォルダーにround.xmlというxmlファイルを作成し、このコンテンツを貼り付けます。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:shape="rectangle">
  <solid Android:color="#FFFFFF" />
  <stroke Android:width=".05dp" Android:color="#d2d2d2" />
  <corners Android:topLeftRadius="5dp" Android:topRightRadius="5dp" Android:bottomRightRadius="5dp" Android:bottomLeftRadius="5dp"/>
</shape>

次に、round.xmlbackgroundとして任意のアイテムに使用します。次に、角を丸くします。

9
Ajay Venugopal

Android Lでは、 View.setClipToOutline を使用してその効果を得ることができます。以前のバージョンでは、ランダムなViewGroupのコンテンツを特定の形状にクリップする方法はありません。

同様の効果が得られるものを考える必要があります。

  • ImageViewで角丸のみが必要な場合は、シェーダーを使用して、背景として使用している図形に画像を「ペイント」できます。例として this library をご覧ください。

  • すべての子供を切り抜く必要がある場合、レイアウトを別のビューで表示できますか?使用している色に関係なく背景があり、中央に丸い「穴」がありますか?実際には、onDrawメソッドをオーバーライドするすべての子にその形状を描画するカスタムViewGroupを作成できます。

8
ivagarz

CardViewは、Android St​​udio 3.0.1のAPI 27で機能しました。 colorPrimaryres/values/colors.xmlファイルで参照されており、単なる例です。 0dpのlayout_widthの場合、親の幅まで伸びます。必要に応じて、制約と幅/高さを構成する必要があります。

<Android.support.v7.widget.CardView
    Android:id="@+id/cardView"
    Android:layout_width="0dp"
    Android:layout_height="200dp"
    Android:layout_marginEnd="8dp"
    Android:layout_marginStart="8dp"
    Android:layout_marginTop="8dp"
    app:cardCornerRadius="4dp"
    app:cardBackgroundColor="@color/colorPrimary">

    <!-- put your content here -->

</Android.support.v7.widget.CardView>
3
Lloyd Rochester

次のコードを使用して、描画可能フォルダーの下にxmlファイルを作成します。 (作成したファイルの名前はrounded_corner.xmlです)

rounded_corner.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:shape="rectangle">

        <!-- view background color -->
        <solid
            Android:color="#a9c5ac" >
        </solid>

        <!-- view border color and width -->
        <stroke
            Android:width="3dp"
            Android:color="#1c1b20" >
        </stroke>

        <!-- If you want to add some padding -->
        <padding
            Android:left="4dp"
            Android:top="4dp"
            Android:right="4dp"
            Android:bottom="4dp"    >
        </padding>

        <!-- Here is the corner radius -->
        <corners
            Android:radius="10dp"   >
        </corners>
    </shape>

そして、丸い角の境界線を保持したいビューの背景として、このドロウアブルを保持します。 LinearLayoutのために保持しましょう

    <LinearLayout Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:background="@drawable/rounded_corner"
            Android:layout_centerInParent="true">

            <TextView Android:layout_width="fill_parent"
                Android:layout_height="wrap_content"
                Android:text="Hi, This layout has rounded corner borders ..."
                Android:gravity="center"
                Android:padding="5dp"/>

    </LinearLayout>
3
Rajneesh Shukla
public class RoundedCornerLayout extends FrameLayout {
    private double mCornerRadius;

    public RoundedCornerLayout(Context context) {
        this(context, null, 0);
    }

    public RoundedCornerLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    public double getCornerRadius() {
        return mCornerRadius;
    }

    public void setCornerRadius(double cornerRadius) {
        mCornerRadius = cornerRadius;
    }

    @Override
    public void draw(Canvas canvas) {
        int count = canvas.save();

        final Path path = new Path();
        path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), (float) mCornerRadius, (float) mCornerRadius, Path.Direction.CW);
        canvas.clipPath(path, Region.Op.REPLACE);

        canvas.clipPath(path);
        super.draw(canvas);
        canvas.restoreToCount(count);
    }
}
2
Mahmoud Shahoud

このチュートリアルとその下のすべての議論に従ってください- http://www.curious-creature.org/2012/12/11/ Android-recipe-1-image-with-rounded-corners /

Android UIツールキット全体の主要な開発者の1人であるGuy Romainが書いたこの投稿によると、角の丸いコンテナ(およびそのすべての子ビュー)を作成することは可能ですが、あまりにも高価です(レンダリングの問題のパフォーマンスから)。

彼の投稿に従って行くことをお勧めします。角を丸くしたい場合は、この投稿に従って丸い角ImageViewを実装します。その後、任意の背景を持つコンテナ内に配置することができ、希望する効果が得られます。

それも最終的に私がやったことです。

2
Tal Kanel

提供されたチュートリアルリンクは、子要素のlayout_widthおよびlayout_heightプロパティをmatch_parentに設定する必要があることを示唆しているようです。

<ImageView
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">
1
danielcooperxyz

Jaap van Hengstumの答えとの違い:

  1. マスクビットマップの代わりにBitmapShaderを使用します。
  2. ビットマップを一度だけ作成します。
public class RoundedFrameLayout extends FrameLayout {
    private Bitmap mOffscreenBitmap;
    private Canvas mOffscreenCanvas;
    private BitmapShader mBitmapShader;
    private Paint mPaint;
    private RectF mRectF;

    public RoundedFrameLayout(Context context) {
        super(context);
        init();
    }

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

    public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setWillNotDraw(false);
    }

    @Override
    public void draw(Canvas canvas) {
        if (mOffscreenBitmap == null) {
            mOffscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
            mOffscreenCanvas = new Canvas(mOffscreenBitmap);
            mBitmapShader = new BitmapShader(mOffscreenBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setShader(mBitmapShader);
            mRectF = new RectF(0f, 0f, canvas.getWidth(), canvas.getHeight());
        }
        super.draw(mOffscreenCanvas);

        canvas.drawRoundRect(mRectF, 8, 8, mPaint);
    }
}
1
Peter Zhao
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {

        Bitmap roundedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(roundedBitmap);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;

        Paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        Paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, Paint);

        Paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, Paint);

        return roundedBitmap;
    }
0


0
user4050065