Hoe maak je een weergave met afgeronde hoeken?

Ik probeer een weergave te maken in Android met afgeronde hoeken. De oplossing die ik tot nu toe heb gevonden, is om een ​​vorm met afgeronde hoeken te definiëren en deze als achtergrond voor die weergave te gebruiken.

Dit is wat ik deed, definieer een tekenbaar zoals hieronder weergegeven:

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

Nu heb ik dit als achtergrond voor mijn lay-out gebruikt, zoals hieronder:

<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">

Dit werkt prima, ik zie dat de weergave afgeronde randen heeft.

Maar mijn lay-out heeft veel andere onderliggende weergaven, bijvoorbeeld een ImageView of een MapView. Wanneer ik een ImageViewin de bovenstaande lay-out plaats, worden de hoeken van de afbeelding niet bijgesneden/bijgesneden, maar lijkt deze vol.

Ik heb andere oplossingen gezien om het te laten werken, zoals uitgelegd hier.

Maar is er een methode om afgeronde hoeken in te stellen voor een weergave en al zijn?
onderliggende weergaven zijn opgenomen in die hoofdweergave die is afgerond
hoeken?


Antwoord 1, autoriteit 100%

Een andere benadering is om een ​​aangepaste lay-outklasse te maken zoals hieronder. Deze lay-out tekent eerst de inhoud naar een offscreen bitmap, maskeert de offscreen bitmap met een afgeronde rechthoek en tekent vervolgens de offscreen bitmap op het eigenlijke canvas.

Ik heb het geprobeerd en het lijkt te werken (tenminste voor mijn eenvoudige testcase). Het heeft natuurlijk invloed op de prestaties in vergelijking met een normale lay-out.

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;
    }
}

Gebruik dit als een normale lay-out:

<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>

Antwoord 2, autoriteit 69%

Of je kunt een android.support.v7.widget.CardViewgebruiken zoals:

<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>

Antwoord 3, autoriteit 47%

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>

en binnenin je lay-out

<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>

Antwoord 4, autoriteit 18%

Het antwoord van Jaap van Hengstumwerkt prima, maar ik denk dat het duur is en als we deze methode toepassen op bijvoorbeeld een knop, gaat het aanraakeffect verloren omdat de weergave wordt weergegeven als een bitmap.

Voor mij is de beste methode en de eenvoudigste methode om een ​​masker op de weergave aan te brengen, zoals dat:

@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);
}

Antwoord 5, autoriteit 16%

Maak een xml-bestand met de naam round.xmlin de map drawableen plak deze inhoud:

<?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>

gebruik vervolgens de round.xmlals backgroundvoor elk item. Dan krijg je afgeronde hoeken.


Antwoord 6, autoriteit 13%

Als u problemen ondervindt bij het toevoegen van aanraakluisteraars aan de lay-out. Gebruik deze lay-out als bovenliggende lay-out.

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);
    }
}

als

<?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>

Antwoord 7, autoriteit 8%

Met de Material Components Library is de beste manier om een ​​Viewmet afgeronde hoeken te maken het gebruik van de MaterialShapeDrawable.

Maak een ShapeAppearanceModel met aangepaste afgeronde hoeken:

ShapeAppearanceModel shapeAppearanceModelLL1 = new ShapeAppearanceModel()
        .toBuilder()
        .setAllCorners(CornerFamily.ROUNDED,radius16)
        .build();

Maak een MaterialShapeDrawable:

MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1);

Als je ook een elevatieOverlay voor het donkere thema wilt toepassen, gebruik dan dit:

MaterialShapeDrawable shapeDrawableLL1 = MaterialShapeDrawable.createWithElevationOverlay(this, 4.0f);
shapeDrawableLL1.setShapeAppearanceModel(shapeAppearanceModelLL1);

Optioneel: pas op de shapeDrawable een achtergrondkleur en een streek toe

shapeDrawableLL1.setFillColor(
       ContextCompat.getColorStateList(this,R.color...));
 shapeDrawableLL1.setStrokeWidth(2.0f);
 shapeDrawableLL1.setStrokeColor(
       ContextCompat.getColorStateList(this,R.color...));

Pas tenslotte de shapeDrawable toe als achtergrond in uw LinearLayout(of andere weergave):

LinearLayout linearLayout1= findViewById(R.id.ll_1);
ViewCompat.setBackground(linearLayout1,shapeDrawableLL1);

voer hier de afbeeldingsbeschrijving in


Antwoord 8, autoriteit 7%

In Android L kun je gewoon View gebruiken .setClipToOutlineom dat effect te krijgen. In eerdere versies was er geen manier om de inhoud van een willekeurige ViewGroup in een bepaalde vorm te knippen.

Je zult iets moeten bedenken dat je een soortgelijk effect zou geven:

  • Als je alleen afgeronde hoeken in ImageView nodig hebt, kun je een arcering gebruiken om de afbeelding te ‘schilderen’ over de vorm die je als achtergrond gebruikt. Bekijk voor een voorbeeld deze bibliotheek.

  • Als je echt alle kinderen wilt laten knippen, kun je misschien een andere kijk op je lay-out hebben? Eentje met een achtergrond in welke kleur je ook gebruikt, en een rond ‘gat’ in het midden? Je zou zelfs een aangepaste ViewGroup kunnen maken die die vorm over elk kind tekent en de onDraw-methode overschrijft.


Antwoord 9, autoriteit 5%

Maak een xml-bestand onder uw tekenbare map met de volgende code. (De naam van het bestand dat ik heb gemaakt is round_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>

En bewaar deze drawableals backgroundvoor de weergave waarvan je de afgeronde hoekrand wilt behouden. Laten we het houden voor een 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>

Antwoord 10, autoriteit 4%

De CardViewwerkte voor mij in API 27 in Android Studio 3.0.1. De colorPrimarywerd verwezen in het bestand res/values/colors.xmlen is slechts een voorbeeld. Voor de layout_width van 0dpwordt deze uitgerekt tot de breedte van de parent. U moet de beperkingen en breedte/hoogte naar wens configureren.

<android.support.v7.widget.CardView
    android:id="@+id/cardView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:cardCornerRadius="4dp"
    app:cardBackgroundColor="@color/colorPrimary">
    <!-- put your content here -->
</android.support.v7.widget.CardView>

Antwoord 11, autoriteit 4%

Voor het geval je een bepaalde hoek wilt ronden.

fun setCorners() {
        val mOutlineProvider = object : ViewOutlineProvider() {
            override fun getOutline(view: View, outline: Outline) {
                val left = 0
                val top = 0;
                val right = view.width
                val bottom = view.height
                val cornerRadiusDP = 16f
                val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, resources.displayMetrics).toInt()
                // all corners
                outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())
                /* top corners
                outline.setRoundRect(left, top, right, bottom+cornerRadius, cornerRadius.toFloat())*/
                /* bottom corners
                outline.setRoundRect(left, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
                /* left corners
                outline.setRoundRect(left, top, right + cornerRadius, bottom, cornerRadius.toFloat())*/
                /* right corners
                outline.setRoundRect(left - cornerRadius, top, right, bottom, cornerRadius.toFloat())*/
                /* top left corner
                outline.setRoundRect(left , top, right+ cornerRadius, bottom + cornerRadius, cornerRadius.toFloat())*/
                /* top right corner
                outline.setRoundRect(left - cornerRadius , top, right, bottom + cornerRadius, cornerRadius.toFloat())*/
                /* bottom left corner
                outline.setRoundRect(left, top - cornerRadius, right + cornerRadius, bottom, cornerRadius.toFloat())*/
                /* bottom right corner
                outline.setRoundRect(left - cornerRadius, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
            }
        }
        myView.apply {
            outlineProvider = mOutlineProvider
            clipToOutline = true
        }
    }

Antwoord 12, autoriteit 3%

Je kunt een androidx.cardview.widget.CardViewals volgt gebruiken:

<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"       
        app:cardCornerRadius="@dimen/dimen_4"
        app:cardElevation="@dimen/dimen_4"
        app:contentPadding="@dimen/dimen_10">
       ...
</androidx.cardview.widget.CardView>

OF

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>

en binnenin je lay-out

<LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/shape">
        ...
</LinearLayout>

Antwoord 13, autoriteit 3%

Een ronde hoekafbeelding maken met com.google.android.material:material:1.2.0-beta01

float radius = context.getResources().getDimension(R.dimen.border_radius_hug);
    shapeAppearanceModel = new ShapeAppearanceModel()
            .toBuilder()
            .setAllCorners(CornerFamily.ROUNDED,radius)
            .build();
imageView.setShapeAppearanceModel(shapeAppearanceModel)

of als je het in een xml-bestand wilt gebruiken:

 <com.google.android.material.imageview.ShapeableImageView
            android:id="@+id/thumb"
            android:layout_width="80dp"
            android:layout_height="60dp"
            app:shapeAppearanceOverlay="@style/circleImageView"
            />

voeg in style.xml dit toe:

<style name="circleImageView" parent="">
      <item name="cornerFamily">rounded</item>
      <item name="cornerSize">10%</item>
</style>

Antwoord 14, autoriteit 2%

volg deze tutorial en alle discussies eronder
http://www. Curious-creature.org/2012/12/11/android-recept-1-image-with-rounded-corners/

volgens dit bericht geschreven door Guy Romain, een van de toonaangevende ontwikkelaars van de volledige Android UI-toolkit, is het mogelijk om een ​​container (en al zijn kindweergaven) met afgeronde hoeken te maken, maar hij legde uit dat het te duur was ( van uitvoeringen van weergaveproblemen).

Ik raad je aan om volgens zijn post te gaan, en als je afgeronde hoeken wilt, implementeer dan afgeronde hoeken ImageViewvolgens deze post. dan zou je het in een container met elke achtergrond kunnen plaatsen, en je krijgt het effect dat je wenst.

dat is wat ik uiteindelijk ook deed.


Antwoord 15, autoriteit 2%

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);
    }
}

Antwoord 16

Verschil met het antwoord van Jaap van Hengstum:

  1. Gebruik BitmapShaderin plaats van bitmap maskeren.
  2. Maak een bitmap slechts één keer.
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);
    }
}

17

Probeer deze listing met uw lineaire lay-out het zal helpen
gereedschappen: context = “youractivity”


18

Gebruik vorm xml rectangle.set met de eigenschap onderste of bovenste radius als want.then toepassing die XML als achtergrond om ur view of …. … gebruik gradiënten om het van de code.

Other episodes