จะสร้างมุมมองที่มีมุมมนได้อย่างไร?


95

ฉันกำลังพยายามสร้างมุมมองใน Android ที่มีขอบมน วิธีแก้ปัญหาที่ฉันพบคือการกำหนดรูปร่างที่มีมุมโค้งมนและใช้เป็นพื้นหลังของมุมมองนั้น

นี่คือสิ่งที่ฉันทำกำหนด Drawable ตามที่ระบุด้านล่าง:

<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ภายในเลย์เอาต์ด้านบนมุมของภาพจะไม่ถูกตัด / ครอบตัด แต่จะปรากฏเต็ม

ฉันได้เห็นวิธีการแก้ปัญหาอื่น ๆ ที่จะทำให้การทำงานเช่นเดียวที่อธิบายที่นี่

แต่มีวิธีการกำหนดมุมโค้งมนสำหรับมุมมองหรือไม่และมุมมองย่อยทั้งหมดอยู่ในมุมมองหลักที่มีมุมโค้งมนหรือไม่?


จะเกิดอะไรขึ้นถ้าคุณใช้เลย์เอาต์แบบกำหนดเองที่ขยายไปยัง LinearLayout และในขณะที่สร้างอ็อบเจ็กต์ขึ้นมาให้ทำซ้ำชายด์ทั้งหมดของเลย์เอาต์นั้นและใช้พื้นหลังเส้นขอบที่โค้งมนกับพวกเขา
MysticMagicϡ

3
android.support.v7.widget.CardView ดูเหมือนจะเป็นทางออกสำหรับสิ่งนี้
rocketspacer

วิธีนี้แก้ปัญหาให้ฉันได้ แต่ต้องใช้คลาสย่อย: /programming/5574212/android-view-clipping
Aaron

สิ่งนี้ตอบคำถามของคุณหรือไม่? การเพิ่มเส้นขอบสำหรับรูปภาพโค้งมน android
user4157124

Google มีเฟรมเวิร์กใหม่เทคโนโลยีใหม่ดีกว่า [Jetpack Compose] [1] [1]: stackoverflow.com/questions/6054562/…
Ucdemir

คำตอบ:


128

อีกวิธีหนึ่งคือการสร้างคลาสเลย์เอาต์ที่กำหนดเองเช่นเดียวกับด้านล่าง เลย์เอาต์นี้จะดึงเนื้อหาไปยังบิตแมปนอกหน้าจอก่อนแล้วมาสก์บิตแมปนอกหน้าจอด้วยสี่เหลี่ยมผืนผ้าโค้งมนจากนั้นจึงวาดบิตแมปนอกหน้าจอบนผืนผ้าใบจริง

ฉันลองแล้วและดูเหมือนว่าจะได้ผล (อย่างน้อยก็สำหรับกรณีทดสอบง่ายๆของฉัน) แน่นอนว่าจะส่งผลต่อประสิทธิภาพเมื่อเทียบกับรูปแบบปกติ

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>

1
ฉันใช้เลย์เอาต์นี้สำหรับมุมมองภาพที่มีฟังก์ชั่นซูมภายใน แต่เลย์เอาต์นี้ไม่สามารถตรวจจับตัวฟังแบบสัมผัสได้เมื่อฉันพยายามซูมจะเพิ่มฟังก์ชั่นการฟังแบบสัมผัสในเลย์เอาต์นี้ได้อย่างไร
Muhammad Nafian Wildana

2
ฉันใช้วิธีนี้และได้ผลดี แต่เมื่อฉันใส่ EditText ในเค้าโครงหน้าจอจะไม่อัปเดตเมื่อฉันพิมพ์เมื่อฉันปิดหน้าต่างข้อความจะปรากฏขึ้น หน้าจอจะได้รับการอัปเดตเมื่อฉันปิดแป้นพิมพ์ แก้ไขปัญหานี้หรือไม่?
Sajib Acharya

1
ปัญหานี้เฉพาะเมื่อคุณใช้กับมุมมอง Recycler คือไม่รอให้ชุดรายการทั้งหมดถูกโหลด และปัดเศษเพียงไม่กี่รายการ มีเหตุผลที่จะเกิดขึ้นหรือไม่?
Ahmed

2
สิ่งนี้ใช้ไม่ได้กับภาพที่โหลดจากไลบรารี glide ที่ใช้ตัวยึดตำแหน่งการเปลี่ยน (หรือภาพเคลื่อนไหวอื่น ๆ ของเด็ก ๆ ) ฉันมีทางเลือกอื่น แต่ต้องใช้สีพื้นหลังของคุณเป็นสีทึบ ดูgist.github.com/grennis/da9f86870c45f3b8ae00912edb72e868
Greg Ennis

2
โซลูชันที่ดีและมีประโยชน์ แต่แพงเกินไป RecyclerView ที่มีเพียงหกองค์ประกอบซึ่งมีภาพเดียวไม่สามารถเลื่อนได้อย่างราบรื่น และไม่ได้ขึ้นอยู่กับกำลังของอุปกรณ์ (Samsung S9 หรือ Wileyfox Swift 2) stackoverflow.com/a/41098690/4399323ตอบโจทย์ดีกว่า!
Valentin Yuryev

73

หรือคุณสามารถใช้สิ่ง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>

ฉันลองมาหลายวิธีแล้วคุณคือทางออกที่ดีที่สุดสำหรับปัญหาของฉัน ขอบคุณ!
wizChen

ไม่สามารถลบระดับความสูงได้ ทำงานได้ดีหากการออกแบบต้องการการยกระดับ
Abdalrahman Shatou

1
@AbdalrahmanShatou developer.android.com/reference/android/support/v7/widget/…มีคุณสมบัติสำหรับสิ่งนั้น คุณลองตั้งค่าเป็น "0" ดูไหม
rocketspacer

5
ข้อเสียเปรียบประการหนึ่งคือไม่รองรับ <21 android api's
Itai Spector

53

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>

3
@ Zach: มันล้มเหลวในทางใด? เหมือนกับว่าแอปของคุณทำงานอย่างไรเมื่อคุณถามคำถามเดิม?
LarsH

2
clipChildren ไม่มีประโยชน์และมุมมองภาพยังขยายออกไปนอกมุมมอง
Abdalrahman Shatou

1
ฉันหวังว่าฉันจะให้รางวัลกับคุณได้ ขอบคุณ
Odys

3
ฉันไม่คิดว่าวิธีนี้จะใช้ได้ผลถ้ารูปภาพเป็นรูปสี่เหลี่ยมผืนผ้าเนื่องจากพื้นหลังจะถูกวาดไว้ด้านหลังเนื้อหาของรูปภาพ ซึ่งอาจใช้ได้เฉพาะกับรูปภาพที่มีความโปร่งใสและมีมุมโค้งมน
Harsha Vardhan

23

คำตอบของ 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);
}

วิธีการใช้งานนี้?
Maksim Kniazev

@MaksimKniazev สร้างคลาสย่อยของเลย์เอาต์ที่คุณต้องการ (เช่น FrameLayout) จากนั้นวางสองวิธีนี้ลงในคลาสย่อยนี้และแทนที่ '<whatever_you_want>' ด้วยค่ารัศมีมุมที่คุณต้องการ (จากทรัพยากรเป็นต้น) แค่นั้นแหละ. ชัดเจนเพียงพอสำหรับคุณหรือคุณต้องการตัวอย่าง?
Donkey

ขอบคุณมากมันทำงานได้ดีขึ้นสำหรับ RecyclerView!
Valentin Yuryev

18

หากคุณประสบปัญหาในขณะที่เพิ่มตัวรับฟังแบบสัมผัสลงในเค้าโครง ใช้เค้าโครงนี้เป็นเค้าโครงหลัก

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>

2
ทำงานได้ดีหากไม่มีภาพเคลื่อนไหวบนหน้าจอมากนักซึ่งทำให้การวาดหน้าจอซ้ำแล้วซ้ำอีกหลาย ๆ ครั้ง เนื่องจากจะทำให้ประสิทธิภาพช้าลงอย่างมาก ควรลองใช้ cardview ซึ่งมีวิธีการทำมุมกลมที่มีประสิทธิภาพ (ไม่ใช้ clipping path หรือ canvas.drawRoundRect - ไม่ดีในด้านล่าง API 17 แต่ใช้ porterFilterDuffColor)
Nguyen Tan Dat

18

สร้างไฟล์ xml ที่เรียกว่าround.xmlในdrawableโฟลเดอร์และวางเนื้อหานี้:

<?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.xmlเป็นbackgroundรายการใดก็ได้ จากนั้นจะทำให้คุณได้มุมโค้งมน


9

ใน Android L คุณจะสามารถใช้View.setClipToOutlineเพื่อรับเอฟเฟกต์นั้นได้ ในเวอร์ชันก่อนหน้านี้ไม่มีวิธีใดในการตัดเนื้อหาของ ViewGroup แบบสุ่มในรูปร่างที่แน่นอน

คุณจะต้องนึกถึงบางสิ่งที่จะให้ผลคล้ายกัน:

  • หากคุณต้องการเพียงมุมโค้งมนใน ImageView คุณสามารถใช้เฉดสีเพื่อ 'ระบายสี' รูปภาพบนรูปทรงที่คุณใช้เป็นพื้นหลังได้ ลองดูตัวอย่างห้องสมุดนี้

  • หากคุณต้องการให้เด็ก ๆ ทุกคนถูกตัดออกจริงๆคุณอาจจะสามารถดูเค้าโครงของคุณได้อีกหรือไม่? หนึ่งที่มีพื้นหลังเป็นสีอะไรก็ได้และมี 'รู' กลมอยู่ตรงกลาง? คุณสามารถสร้าง ViewGroup แบบกำหนดเองที่ดึงรูปร่างนั้นมาทับเด็ก ๆ ทุกคนที่แทนที่เมธอด onDraw


5

สร้างไฟล์ xml ภายใต้โฟลเดอร์ที่วาดได้ของคุณด้วยรหัสต่อไปนี้ (ชื่อไฟล์ที่ฉันสร้างคือ rounded_corner.xml)

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

และเก็บเรื่องนี้ไว้drawableเป็นbackgroundมุมมองที่คุณต้องการให้เส้นขอบมุมโค้งมน มาเก็บไว้ดู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

ทำตามบทช่วยสอนนี้และการอภิปรายทั้งหมดด้านล่าง - http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/

ตามโพสต์นี้เขียนโดย Guy Romain หนึ่งในผู้พัฒนาชั้นนำของชุดเครื่องมือ Android UI ทั้งหมดเป็นไปได้ที่จะสร้างคอนเทนเนอร์ (และมุมมองของเด็ก ๆ ) ที่มีมุมโค้งมน แต่เขาอธิบายว่ามันแพงเกินไป (จากการแสดงของ ปัญหาการแสดงผล)

ฉันจะแนะนำให้คุณทำตามโพสต์ของเขาและถ้าคุณต้องการมุมโค้งมนให้ใช้มุมโค้งมนImageViewตามโพสต์นี้ จากนั้นคุณสามารถวางไว้ในภาชนะที่มีพื้นหลังใดก็ได้และคุณจะได้รับผลกระทบที่คุณต้องการ

นั่นคือสิ่งที่ฉันทำในที่สุด


3

คุณสามารถใช้สิ่งandroidx.cardview.widget.CardViewนี้ได้:

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

หรือ

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:background="@drawable/shape">

        ...

</LinearLayout>

3

CardViewทำงานสำหรับฉันใน API 27 ในสตูดิโอของ Android 3.0.1 colorPrimaryถูกอ้างอิงในres/values/colors.xmlไฟล์และเป็นเพียงตัวอย่าง สำหรับ layout_width ของ0dpมันจะขยายไปตามความกว้างของพาเรนต์ คุณจะต้องกำหนดค่าข้อ จำกัด และความกว้าง / ความสูงตามความต้องการของคุณ

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

3

ด้วยไลบรารีส่วนประกอบวัสดุวิธีที่ดีที่สุดในการสร้างViewมุมโค้งมนคือการใช้ไฟล์MaterialShapeDrawable .

สร้าง ShapeAppearanceModel ที่มีมุมโค้งมนแบบกำหนดเอง:

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

สร้างMaterialShapeDrawable:

MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1);

หากคุณต้องการใช้ระดับความสูงภาพซ้อนสำหรับธีมสีเข้มให้ใช้สิ่งนี้

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

ทางเลือก: นำไปใช้กับรูปร่างวาดสีพื้นหลังและเส้นโครงร่าง

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

สุดท้ายใช้ shapeDrawable เป็นพื้นหลังในLinearLayout(หรือมุมมองอื่น ๆ ) ของคุณ:

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

ป้อนคำอธิบายภาพที่นี่


2

ความแตกต่างจากคำตอบของ 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);
    }
}

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

1

ลิงก์บทช่วยสอนที่คุณให้ไว้ดูเหมือนจะแนะนำว่าคุณต้องตั้งค่าคุณสมบัติ layout_width และ layout_height ขององค์ประกอบลูกของคุณเป็น match_parent

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

1

ในการสร้างภาพมุมมนโดยใช้ 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)

หรือหากคุณต้องการใช้ในไฟล์ xml:

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

ใน style.xml เพิ่มสิ่งนี้:

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

0

ลองใช้คุณสมบัตินี้กับเลย์เอาต์เชิงเส้นของคุณซึ่งจะช่วยให้
เครื่องมือ: context = ". youractivity"


0
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

ในกรณีที่คุณต้องการปัดเศษบางมุม

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

-1

ใช้ shape ใน xml กับ rectangle กำหนดคุณสมบัติของรัศมีด้านล่างหรือด้านบนตามที่ต้องการจากนั้นใช้ xml นั้นเป็นพื้นหลังในมุมมองของคุณ .... หรือ ... ใช้การไล่ระดับสีเพื่อทำจากโค้ด


ฉันได้ทำเช่นนั้นแล้ว แต่ต้องการทราบว่ามีวิธีที่ดีกว่านี้หรือไม่?
Zach

ผู้ร้องขอได้กล่าวถึงการลองใช้แนวทางนี้ในคำถามของเขาแล้ว
Michael Krause
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.