Android 正 N 边形圆角头像的实现,android移动开发基础答案

  • 第二种: 使用 BitmapShader 实现

今天,让我们一起来看一下怎样实现正 N 变形圆角头像的实现。

在讲解之前,让我们先来看一下怎样使用我们的控件


老规矩,在讲解怎样实现以前,我们先一起来看一下怎样使用我们的自定义控件。

自定义属性说明

| 参数 | 说明 |

| — | — |

| type | 相应的值有 circle,round,polygAndroid 正 N 边形圆角头像的实现,android移动开发基础答案
on |

| miv_border_width | 表示边界 Path 的宽度 (默认值是 0 ) |

| miv_border_color | 表示边界 Path 的 Color |

| miv_border_overlay | 表示边界 Path 是否要覆盖在图片上面 |

| miv_fill_color | 表示填充圆的颜色,默认是 Translate,即不可见 |

| miv_corner_radius | 只有当 type round 或者 polygon 的时候才生效,表示边界 Path 圆角半径的大小, |

| miv_sides | 正 N 边形的变数,只有 type 为 polygon 的时候,该属性才生效 |

| miv_rotate_angle | 旋转的角度,只有 type 为 polygon 的时候,该属性才生效 |

指定圆形头像

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:type=“circle”

/>

Android 正 N 边形圆角头像的实现,android移动开发基础答案

指定圆角矩形

<com.xj.shapeview.MultiImageView

android:layout_marginLeft=“15dp”

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:type=“round”

app:miv_corner_radius=“15dp”/>

Android 正 N 边形圆角头像的实现,android移动开发基础答案

指定正 N 边形

正五边形

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:type=“polygon”

app:miv_sides=“5”

app:miv_corner_radius=“25dp”/>

Android 正 N 边形圆角头像的实现,android移动开发基础答案

如果需要其旋转相应的角度,我们只需指定 app:miv_rotate_angle=“180” 即可,这里以 180 度为列子讲解说明

Android 正 N 边形圆角头像的实现,android移动开发基础答案

如果需要正六边形,只需要更改为 app:miv_sides=“6”

Android 正 N 边形圆角头像的实现,android移动开发基础答案

效果图

Android 正 N 边形圆角头像的实现,android移动开发基础答案

相应的布局文件实现

<?xml version="1.0" encoding="utf-8"?>

<ScrollView xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<GridLayout

android:columnCount=“3”

android:rowCount=“3”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:orientation=“vertical”

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:type=“circle”

app:miv_sides=“6”

app:miv_corner_radius=“15dp”/>

<com.xj.shapeview.MultiImageView

android:layout_marginLeft=“15dp”

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:miv_sides=“5”

app:type=“round”

app:miv_corner_radius=“15dp”/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:type=“polygon”

app:miv_sides=“5”

app:miv_corner_radius=“25dp”/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:type=“polygon”

app:miv_sides=“5”

app:miv_corner_radius=“25dp”

app:miv_rotate_angle=“180”/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:miv_sides=“7”

app:type=“polygon”

app:miv_corner_radius=“0dp”

app:miv_rotate_angle=“0”/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:miv_sides=“6”

app:type=“polygon”

app:miv_corner_radius=“0dp”

app:miv_border_overlay=“true”

app:miv_fill_color="@color/colorAccent"/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:miv_sides=“6”

app:type=“polygon”

app:miv_corner_radius=“0dp”

app:miv_rotate_angle=“0”

app:miv_border_overlay=“true”

app:miv_border_width=“1dp”

app:miv_border_color="@android:color/darker_gray"

/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:miv_sides=“6”

app:type=“polygon”

app:miv_corner_radius=“0dp”

app:miv_rotate_angle=“0”

app:miv_border_overlay=“false”

app:miv_border_width=“1dp”

app:miv_border_color="@android:color/black"

/>

<com.xj.shapeview.MultiImageView

android:layout_width=“100dp”

android:layout_height=“100dp”

android:src="@mipmap/tanyan"

app:miv_sides=“7”

app:type=“polygon”

app:miv_corner_radius=“10dp”

app:miv_rotate_angle=“0”

/>


正 N 边形圆角头像的实现原理分析


要实现正 N 变形主要有几个难点

  • 怎样让我们的头像变成正 N 边形

  • 怎样绘制正 N 边形

  • 怎样绘制带圆角的正 N 边形


怎样让我们的头像变成正 N 边形?


其实这个问题在上篇博客已经讲到,有两种实现方式。

  • 第一种: 使用 Paint 的 Xfermode 实战

  • 第二种: 使用 BitmapShader 实现

今天,这边博客主要以 BitmapShader 为例子实现。

核心代码实现

mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

mBitmapPaint.setAntiAlias(true);

mBitmapPaint.setShader(mBitmapShader);

@Override

protected void onDraw(Canvas canvas) {


Path path = getPath(canvas,mType,(int)mDrawableRadius2,(int)mDrawableRadius2,mDrawableRadius,mSides,mCornerRadius);

canvas.drawPath(path,mBitmapPaint);

}

核心思路分析:

  • 拿到 Bitmap,并使用 BitmapShader 进行包装

  • 将 mBitmapShader 设置给画笔 Paint

  • 第三步,在 onDraw 方法,将其绘制出来


怎样绘制正 N 边形


这里的思想主要来自该博客 如何用Canvas画一个正多边形

数学原理分析

首先,我们先来看一张图片

Android 正 N 边形圆角头像的实现,android移动开发基础答案

从图中可以看一看到,我们若想绘制出一个正 N 边形,那么我们只需要计算出各个点的坐标,然后使用 Path 连接起来即可。

那我们要怎样计算出各个点的坐标呢

  • 从图中不难得出,圆心角 a 的度数为 360/n,弧度计算为 2π/n

  • 如果把圆心的坐标为(0,0),那么顶点P1的坐标为[X1=cos(a),Y1=sin(a)]。

  • 以此类推,顶点Pn坐标为[Xn=cos(a_n),Yn=sin(a_n)]。

圆心的实际坐标是外接矩形的中心:[Ox=(rect.right+rect.left)/2 , Oy=(rect.top+rect.bottom)/2]。

所以Pn的实际坐标是[Xn+Ox,Yn+Oy]。

最后我们把把 P0-P1…Pn 连起来,就是我们要的结果了。

核心伪代码实现

float a = 2π / n ; // 角度

Path path = new Path();

for( int i = 0; i < = n; i++ ){

float x = R * cos(a * i);

float y = R * sin(a * i);

if (i = 0){

path.moveTo(x,y); // 移动到第一个顶点

,我们若想绘制出一个正 N 边形,那么我们只需要计算出各个点的坐标,然后使用 Path 连接起来即可。

那我们要怎样计算出各个点的坐标呢

  • 从图中不难得出,圆心角 a 的度数为 360/n,弧度计算为 2π/n

  • 如果把圆心的坐标为(0,0),那么顶点P1的坐标为[X1=cos(a),Y1=sin(a)]。

  • 以此类推,顶点Pn坐标为[Xn=cos(a_n),Yn=sin(a_n)]。

圆心的实际坐标是外接矩形的中心:[Ox=(rect.right+rect.left)/2 , Oy=(rect.top+rect.bottom)/2]。

所以Pn的实际坐标是[Xn+Ox,Yn+Oy]。

最后我们把把 P0-P1…Pn 连起来,就是我们要的结果了。

核心伪代码实现

float a = 2π / n ; // 角度

Path path = new Path();

for( int i = 0; i < = n; i++ ){

float x = R * cos(a * i);

float y = R * sin(a * i);

if (i = 0){

path.moveTo(x,y); // 移动到第一个顶点

上一篇:CSS的浮动、清除浮动、布局方式


下一篇:Software Testing - 代码覆盖率基础知识