在相親原始碼開發中,如何實現圓角及特殊圓角的使用?

雲豹科技程式設計師發表於2021-10-21

我們開發的相親原始碼大部分控制元件已經賦予了圓角的特性,圓角實際上的視覺體驗也比較好,不像預設那麼鋒利,圓角能給人一種舒適的感覺.

以前我對控制元件使用圓角無非就三種方式.

1、xml檔案中shape的方式

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="
    xmlns:app="
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerInParent="true"
        android:background="@drawable/shape_circle"
        /></RelativeLayout>

shape_circle

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="><!--    圓-->
    <corners android:radius="8dp" /><!--    邊框-->
    <solid android:color="@color/teal_200"/><!--    漸變--><!--    <gradient />--></shape>

在這裡插入圖片描述

2、cardview

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="
    xmlns:app="
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.cardview.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        app:cardCornerRadius="10dp"
        app:cardElevation="10dp">
        
        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/ic_launcher_background"/>
        
    </androidx.cardview.widget.CardView>
        </RelativeLayout>

在這裡插入圖片描述

這種方式在相親原始碼中使用起來更為簡單,而且CardView還自帶陰影效果,直接設定屬性即可,相較於xml減少了包體大小(聊勝於無).

3、自定義View

/**
 * 自定義圓角view
 */
public class RoundImageView extends AppCompatImageView {
    private float width, height;
    // 全部角度
    private float radius, leftRadius, rightRadius;
    // 是否是半圓
    private boolean isRound = false;
    // 底部圓角
    private boolean isBottomRound = false;
    public RoundImageView(Context context) {
        this(context, null);
    }
    public RoundImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }
    /**
     * 初始化
     *
     * @param context
     * @param attrs
     */
    private void init(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
        radius = array.getDimensionPixelOffset(R.styleable.RoundImageView_radius, 0);
        leftRadius = array.getDimensionPixelOffset(R.styleable.RoundImageView_left_radius, 0);
        rightRadius = array.getDimensionPixelOffset(R.styleable.RoundImageView_right_radius, 0);
        if (radius == 0 && leftRadius == 0 && rightRadius == 0) {
            isRound = true;
        }
        if (leftRadius != 0 && rightRadius != 0) {
            isBottomRound = true;
        }
        array.recycle();
    }
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        width = getWidth();
        height = getHeight();
    }
    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        // 抗鋸齒
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        Path path = new Path();
        if (isRound) {
            radius = Math.min(width, height) / 2;
        }
        // 設定背景顏色透明
        canvas.drawColor(Color.TRANSPARENT);
        Drawable drawable = getDrawable();
        int w = this.getWidth();
        int h = this.getHeight();
        if (null != drawable && w > 0 && h > 0) {
            float[] rids;
            // 圓角的半徑,依次為左上角xy半徑,右上角,右下角,左下角
            if (isBottomRound) {
                rids = new float[]{0, 0, 0, 0,
                        rightRadius, rightRadius, leftRadius, leftRadius};
            } else {
                rids = new float[]{radius, radius, radius, radius,
                        radius, radius, radius, radius};
            }
            path.addRoundRect(new RectF(0, 0, w, h), rids, Path.Direction.CW);
            canvas.clipPath(path);
        }
        super.onDraw(canvas);
    }
    public void setRadius(int radius) {
        this.radius = radius;
        invalidate();
    }
}

attrs

<!-- RoundImageView --><declare-styleable name="RoundImageView">
    <!-- 圓角的半徑 -->
    <attr name="radius" format="dimension" />
    <attr name="left_radius" format="dimension" />
    <attr name="right_radius" format="dimension" /></declare-styleable>

使用

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="
    xmlns:app="
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.jsxr.kotlintest.RoundImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/ic_launcher_background"
        app:radius="10dp"
        android:layout_centerInParent="true"/></RelativeLayout>

效果
在這裡插入圖片描述

這種方式實用性上和第二種差不多,就是一開始麻煩點,你要麼自己寫,要麼去百度複製,但是相較於官方提供的View,這種方式自定義性比較強,你個別角圓都行.

上面三種是我以前開發相親原始碼用過的方式,最近為了簡化程式碼,降低系統複雜度,就另外尋找了一個功能強大的View.

GradientDrawable

在這裡插入圖片描述

這是官方對於它的解釋.在實際的使用上十分得勁,少了好多跟UI扯皮,自己做重複性工作的時間,下面請看程式碼

工具類

public class MyShape {
    private static final ConcurrentHashMap<String, GradientDrawable> hashMap = new ConcurrentHashMap();
    /**
     * 設定圓角
     * @param context
     * @param radius
     * @return
     */
    public static GradientDrawable setMyShape(Context context, int radius) {
        int realRadius = ImageUtil.dp2px(context, radius);
        String radiusKey = String.valueOf(radius);
        if (hashMap.contains(radiusKey)) {
            return hashMap.get(radiusKey);
        } else {
            GradientDrawable drawable = new GradientDrawable();
            if (radius != 0) {
                drawable.setCornerRadius(realRadius);
            }
            hashMap.put(radiusKey, drawable);
            return drawable;
        }
    }
    /**
     * @param context
     * @param radius
     * @param bg
     * @return 自定義圓角、背景圖形
     */
    public static GradientDrawable setMyShape(Context context, int radius, int bg) {
        int realRadius = ImageUtil.dp2px(context, radius);
        String key = String.valueOf(realRadius + bg);
        if (hashMap.contains(key)) {
            return hashMap.get(key);
        } else {
            GradientDrawable drawable = new GradientDrawable();
            if (radius != 0) {
                drawable.setCornerRadius(realRadius);
            }
            if (bg != 0) {
                drawable.setColor(bg);
            }
            hashMap.put(key, drawable);
            return drawable;
        }
    }
    /**
     * 設定圓角、背景、透明度
     *
     * @param radius
     * @param bg
     * @param alpha
     * @return
     */
    public static GradientDrawable setMyShapeWithAlpha(Context activity,int radius, int bg, int alpha) {
        int realRadius = ImageUtil.dp2px(activity, radius);
        String key = String.valueOf(realRadius + bg + alpha);
        if (hashMap.containsKey(key)) {
            return hashMap.get(key);
        } else {
            GradientDrawable drawable = new GradientDrawable();
            drawable.setCornerRadius(radius);
            drawable.setColor(bg);
            drawable.setAlpha(alpha);
            hashMap.put(key, drawable);
            return drawable;
        }
    }
    /**
     * @param activity
     * @param topLeft,topRight,bottomLeft,bottomRight
     * @param bg
     * @return 自定義圓角、背景佈局
     */
    public static GradientDrawable setMyShapeRadiusWithBg(Context activity, int topLeft, int topRight, int bottomLeft, int bottomRight, int bg) {
        topLeft = ImageUtil.dp2px(activity, topLeft);
        topRight = ImageUtil.dp2px(activity, topRight);
        bottomLeft = ImageUtil.dp2px(activity, bottomLeft);
        bottomRight = ImageUtil.dp2px(activity, bottomRight);
        String key = String.valueOf(topLeft + topRight + bottomLeft + bottomRight + bg);
        if (hashMap.containsKey(key)) {
            return hashMap.get(key);
        } else {
            GradientDrawable drawable = new GradientDrawable();
            drawable.setCornerRadii(new float[]{topLeft, topLeft,
                    topRight, topRight,
                    bottomLeft, bottomLeft,
                    bottomRight, bottomRight});
            if (bg != 0) {
                drawable.setColor(bg);
            }
            hashMap.put(key, drawable);
            return drawable;
        }
    }
    /**
     * @param activity
     * @param radius
     * @param width
     * @param bg
     * @return 設定帶邊框的橢圓+圓角+自定義邊框顏色
     */
    public static GradientDrawable setMyShapeStroke(Context activity, int radius, int width, int bg) {
        int realRadius = ImageUtil.dp2px(activity, radius);
        int realWidth = ImageUtil.dp2px(activity, width);
        String key = String.valueOf(realRadius + realWidth + bg);
        if (hashMap.containsKey(key)) {
            return hashMap.get(key);
        } else {
            GradientDrawable drawable = new GradientDrawable();
            if (radius != 0) {
                drawable.setCornerRadius(realRadius);
            }
            if (width != 0 && bg != 0) {
                drawable.setStroke(realWidth, bg);
            }
            hashMap.put(key, drawable);
            return drawable;
        }
    }
    /**
     * @param activity
     * @param radius
     * @param width
     * @param strokeBg
     * @param bg
     * @return 設定帶邊框的橢圓,自定義內部顏色+自定義邊框顏色
     */
    public static GradientDrawable setMyshapeStroke(Context activity, int radius, int width, int strokeBg, int bg) {
        int realRadius = ImageUtil.dp2px(activity, radius);
        int realWidth = ImageUtil.dp2px(activity, width);
        String key = String.valueOf(realRadius + realRadius + strokeBg);
        if (hashMap.containsKey(key)) {
            return hashMap.get(key);
        } else {
            GradientDrawable drawable = new GradientDrawable();
            if (radius != 0) {
                drawable.setCornerRadius(realRadius);
            }
            if (width != 0 && strokeBg != 0) {
                drawable.setStroke(realWidth, strokeBg);
            }
            if (bg != 0) {
                drawable.setColor(bg);
            }
            hashMap.put(key, drawable);
            return drawable;
        }
    }
    /**
     * @param activity
     * @param topLeftRadius
     * @param topRightRadius
     * @param bottomRightRadius
     * @param bottomLeftRadius
     * @return 設定橢圓,並可以自定義內部顏色
     */
    public static GradientDrawable setMyShapeRadius(Context activity, int bgColor, int topLeftRadius, int topRightRadius,
                                                    int bottomRightRadius, int bottomLeftRadius) {
        GradientDrawable drawable = new GradientDrawable();
        if (bgColor != 0) {
            drawable.setColor(bgColor);
        }
        drawable.setCornerRadii(new float[]{ImageUtil.dp2px(activity, topLeftRadius), ImageUtil.dp2px(activity, topLeftRadius),
                ImageUtil.dp2px(activity, topRightRadius), ImageUtil.dp2px(activity, topRightRadius),
                ImageUtil.dp2px(activity, bottomRightRadius), ImageUtil.dp2px(activity, bottomRightRadius),
                ImageUtil.dp2px(activity, bottomLeftRadius), ImageUtil.dp2px(activity, bottomLeftRadius)});
        return drawable;
    }
    /**
     * @param startColor
     * @param endColor
     * @param angle
     * @return 設定漸變色
     */
    @SuppressLint("WrongConstant")
    public static GradientDrawable setGradient(Context activity, int startColor, int endColor, int topLeftRadius, int topRightRadius,
                                               int bottomRightRadius, int bottomLeftRadius, int angle) {
        int[] colors = {startColor, endColor};
        topLeftRadius = ImageUtil.dp2px(activity, topLeftRadius);
        topRightRadius = ImageUtil.dp2px(activity, topRightRadius);
        bottomLeftRadius = ImageUtil.dp2px(activity, bottomLeftRadius);
        bottomRightRadius = ImageUtil.dp2px(activity, bottomRightRadius);
        String key = String.valueOf(topLeftRadius + topRightRadius + bottomLeftRadius + bottomRightRadius + angle);
        if (hashMap.containsKey(key)) {
            return hashMap.get(key);
        } else {
            GradientDrawable drawable = null;
            if (angle == 0) {
                drawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
            } else if (angle == 90) {
                drawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, colors);
            } else if (angle == 180) {
                drawable = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, colors);
            } else if (angle == 270) {
                drawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors);
            } else if (angle == 315) {
                drawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, colors);
            } else {
                drawable = new GradientDrawable();
            }
            drawable.setCornerRadii(new float[]{topLeftRadius, topLeftRadius,
                    topRightRadius, topRightRadius,
                    bottomRightRadius, bottomRightRadius,
                    bottomLeftRadius, bottomLeftRadius});
            drawable.setGradientType(GradientDrawable.RECTANGLE);
            hashMap.put(key, drawable);
            return drawable;
        }
    }
}

簡單用雜湊表存了下引數,這個應該叫享元模式,我覺得意義不是很大

介面卡

class TestAdapter(val context: Context, val list: MutableList<String>) :
    RecyclerView.Adapter<TestAdapter.ViewHolder>() {
    class ViewHolder(item: View) : RecyclerView.ViewHolder(item) {
        val layout: ConstraintLayout = item.findViewById(R.id.item_layout)
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflate = LayoutInflater.from(context).inflate(R.layout.item, parent, false)
        return ViewHolder(inflate)
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        when (position) {
            1 -> holder.layout.background = MyShape.setMyShape(context,
                10,
                ContextCompat.getColor(context, R.color.design_default_color_error)
            )
            2 -> holder.layout.background = MyShape.setMyShapeStroke(context,
                15,
                3,
                ContextCompat.getColor(context, R.color.design_default_color_primary_dark)
            )
            3 -> holder.layout.background = MyShape.setMyShapeRadius(context,
                ContextCompat.getColor(context, R.color.design_default_color_secondary_variant),
                0,
                10,
                0,
                10
            )
            4 -> holder.layout.background = MyShape.setMyShapeWithAlpha(context,
                10,
                ContextCompat.getColor(context, android.R.color.holo_green_dark),
                50
            )
            5 -> holder.layout.background = MyShape.setMyShapeRadiusWithBg(context,
                15,
                0,
                15,
                0,
                ContextCompat.getColor(context,
                    android.R.color.holo_red_light))
            6 -> holder.layout.background = MyShape.setGradient(context,
                ContextCompat.getColor(context, android.R.color.holo_purple),
                ContextCompat.getColor(context, R.color.black),
                15,
                15,
                15,
                15,
                180)
        }
    }
    override fun getItemCount(): Int {
        return list.size
    }
}

item

<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="
    android:id="@+id/item_layout"
    android:layout_width="50dp"
    android:layout_height="25dp"
    android:layout_margin="25dp"
    android:background="@color/black"
    ></androidx.constraintlayout.widget.ConstraintLayout>

最終效果
在這裡插入圖片描述

上面的工具類是相親原始碼開發中經常使用的,實際上你們可以根據官方提供的API進行更多的創作.

我這裡隨便介紹一下API

setCornerRadius 設定圓角
setColor 設定背景顏色
setAlpha 設定透明度
setCornerRadii 設定多角度圓角
setStroke 設定邊框+邊框顏色
setGradientType 設定漸變風格 有四種
GradientDrawable.RECTANGLE 矩形
GradientDrawable.LINE 線
GradientDrawable.RING 圓環
GradientDrawable.OVAL 圓

好啦!在相親原始碼開發中常用的大概就是這麼多,希望以上的分享能給大家帶來幫助。

本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理
原文連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2838599/,如需轉載,請註明出處,否則將追究法律責任。

相關文章