当前位置: 首页 > 编程笔记 >

利用Android中BitmapShader制作自带边框的圆形头像

宓英哲
2023-03-14
本文向大家介绍利用Android中BitmapShader制作自带边框的圆形头像,包括了利用Android中BitmapShader制作自带边框的圆形头像的使用技巧和注意事项,需要的朋友参考一下

效果如下:

BitmapShader 的简单介绍

关于 Shader是什么,Shader的种类有哪几种以及如何使用不属于本文范畴,对这方面不是很了解的同学,建议先去学习一下 Shader 的基本使用。

BitmapShader主要的作用就是 通过Paint对象,对 画布进行指定的Bitmap填充,实现一系列效果,可以有以下三种模式进行选择

      1.CLAMP - 拉伸,这里拉伸的是图片的最后一个元素,不断地重复,这个效果,在图片比较小,而所要画的面积比较大的时候会比较明显。

      2.REPEAT - 重复,横向纵向不断地重复,不同于上一模式,这种模式在图片比较小不能满足要求是,会在横向纵向不断重复绘制图形。

      3.MIRROR - 翻转,这种模式和 REPEAT 是类似的,只不过这里的重复是翻转着重复,和折纸的效果差不多。

而我们将要使用的是 CLAMP 模式,因为只要我们对图形的大小进行控制,就可以避免图像进行拉伸。

具体实现介绍

为了自定义 图像,边框宽度和颜色,我们首先在 res/values 目录下,新建一个 attrs.xml文件,里面要书写的内容如下所示

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="MyCustomView">
  <attr name="mborder_color" format="color"></attr>
  <attr name="mborder_width" format="dimension"></attr>
  <attr name="msrc" format="reference"></attr>
 </declare-styleable>
</resources>

当然,在这里还可以添加一些其他的特性。既然定义了我们想要使用的特性,那么我们就要在自定义View里面 解析这些属性并且加以利用,解析过程如下所示

 TypedArray type = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView);
 mBorderColor = type.getColor(R.styleable.MyCustomView_mborder_color,0);
 mDrawable = type.getDrawable(R.styleable.MyCustomView_msrc);

 //将获得的 Drawable 转换成 Bitmap
 BitmapDrawable bitmapDrawable = (BitmapDrawable) mDrawable;
 mBitmap = bitmapDrawable.getBitmap();

 mBorderWidth = type.getDimensionPixelSize(R.styleable.MyCustomView_mborder_width, 2);

值得注意的是 mSrc 属性的解析,由于获得是 Drawable 对象,所以我们需要将其转换为 Bitmap 对象。

下面就利用我们获得的 Bitmap 对象进行圆形头像的绘制,对 BitmapShader 和 Paint 的初始化如下所示

  mSrcBitmap = Bitmap.createScaledBitmap(mBitmap, mWidth, mHeight, false);
  mShader = new BitmapShader(mSrcBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  mPaint = new Paint();
  mPaint.setShader(mShader);
  mRadius = (mWidth - mBorderWidth * 2 - 4) / 2;
  mCircleX = (mWidth) / 2;
  mCircleY = (mHeight) / 2;

mSrcBitmap是对获得的图像进行适当的缩小或者放大,以适应我们对图形的要求,而这里的 mWidth 和 mHeight 又是什么呢?实际上就是我们在 定义视图在 layout_width 和 layout_height中传递进来的值,不过在这里我对他们进行了处理,也就是选取最小值操作,这样的话就可以避免由于宽大于高或者高大于宽而造成图像填充不满指定区域的现象。值得注意的是,自定义视图,需要对 wrap_content 进行特殊处理,否则系统对该属性的视图不予以显示。至于如何进行处理,可以看看本例的源码,很简单,相信很多人一看就知道或者说早就了然于胸。

还有一点需要强调的是这里的 mRadius ,也就是将要绘制的圆的半径,为什么要减去边框的宽度 乘 2 呢? 要知道,我们的圆是根据 视图指定的宽度或者高度来画的,如果我们所画 的圆恰好是指定视图的内切圆,那么边框放在哪里呢?它肯定要被画在视图的外面,那样我们就看不到完整的边框了。所以,这么减去的意义在于为边框腾出空间。

经过以上操作,我们就已经将圆形头像绘制出来了,下面来绘制边框,其实非常简单,我只不过是又定义了一个  Paint 对象,并且利用它画了一个圆而已,画笔的初始化操作如下所示

  mBorderPaint = new Paint();
  mBorderPaint.setStyle(Paint.Style.STROKE);
  mBorderPaint.setStrokeWidth(mBorderWidth);
  mBorderPaint.setColor(mBorderColor);
  mBorderPaint.setStrokeCap(Paint.Cap.ROUND);

好了,下面就可以在onDraw()函数中,进行绘制了,如下所示

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawCircle(mCircleX, mCircleY, mRadius, mPaint);
  canvas.drawCircle(mCircleX, mCircleY, mRadius, mBorderPaint);
 }

这样,整个效果就算实现完毕了。下面来看看如何使用

 <com.example.hwaphon.patheffecttest.MyView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_marginBottom="16dp"
   android:layout_marginRight="8dp"
   app:mborder_color="@android:color/holo_green_light"
   app:mborder_width="4dp"
   app:msrc="@drawable/myview_test"/>

注意,一定要在容器中加上这么一句

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

具体实现的核心代码

package com.example.hwaphon.patheffecttest;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by Hwaphon on 2016/5/12.
 */
public class MyView extends View {

 private Bitmap mBitmap;
 private Drawable mDrawable;
 private Bitmap mSrcBitmap;

 private BitmapShader mShader;
 private Paint mPaint;

 private int mWidth, mHeight;

 private int mRadius;
 private int mCircleX, mCircleY;

 private int mBorderColor;
 private Paint mBorderPaint;
 private int mBorderWidth;

 public MyView(Context context) {
  this(context, null);
 }

 public MyView(Context context, AttributeSet attrs) {
  super(context, attrs);
  TypedArray type = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView);
  mBorderColor = type.getColor(R.styleable.MyCustomView_mborder_color,0);
  mDrawable = type.getDrawable(R.styleable.MyCustomView_msrc);

  //将获得的 Drawable 转换成 Bitmap
  BitmapDrawable bitmapDrawable = (BitmapDrawable) mDrawable;
  mBitmap = bitmapDrawable.getBitmap();

  mBorderWidth = type.getDimensionPixelSize(R.styleable.MyCustomView_mborder_width, 2);
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  mWidth = measureWidth(widthMeasureSpec);
  mHeight = measureHeight(heightMeasureSpec);
  int temp = mWidth > mHeight ? mHeight : mWidth;
  mWidth = mHeight = temp;
  initView();
  setMeasuredDimension(mWidth, mHeight);
 }

 private int measureHeight(int heightMeasureSpec) {
  int size = MeasureSpec.getSize(heightMeasureSpec);
  int sizeMode = MeasureSpec.getMode(heightMeasureSpec);
  int result = 0;
  if (sizeMode == MeasureSpec.EXACTLY) {
   result = size;
  } else {
   result = 200;
   if (sizeMode == MeasureSpec.AT_MOST) {
    result = Math.min(result, size);
   }
  }
  return result;
 }

 private int measureWidth(int widthMeasureSpec) {
  int size = MeasureSpec.getSize(widthMeasureSpec);
  int sizeMode = MeasureSpec.getMode(widthMeasureSpec);
  int result = 0;
  if (sizeMode == MeasureSpec.EXACTLY) {
   result = size;
  } else {
   result = 200;
   if (sizeMode == MeasureSpec.AT_MOST) {
    result = Math.min(result, size);
   }
  }
  return result;
 }

 private void initView() {

  mSrcBitmap = Bitmap.createScaledBitmap(mBitmap, mWidth, mHeight, false);
  mShader = new BitmapShader(mSrcBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
  mPaint = new Paint();
  mPaint.setShader(mShader);
  mRadius = (mWidth - mBorderWidth * 2) / 2;
  mCircleX = (mWidth) / 2;
  mCircleY = (mHeight) / 2;

  mBorderPaint = new Paint();
  mBorderPaint.setStyle(Paint.Style.STROKE);
  mBorderPaint.setStrokeWidth(mBorderWidth);
  mBorderPaint.setColor(mBorderColor);
  mBorderPaint.setStrokeJoin(Paint.Join.ROUND);
  mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawCircle(mCircleX, mCircleY, mRadius, mPaint);
  canvas.drawCircle(mCircleX, mCircleY, mRadius, mBorderPaint);
 }
}

总结

以上就是Android利用BitmapShader制作自带边框圆形头像的全部内容,希望这篇文章对大家开发Android的时候能有所帮助,如果有疑问大家可以留言交流。

 类似资料:
  • 问题内容: 我想知道如何在IE8中制作圆形边框。我在用着 适用于mozilla和safari。 问题答案: 有一个jQuery插件。http://jquery.malsup.com/corner/

  • 本文向大家介绍Android利用CircleImageView实现圆形头像的方法,包括了Android利用CircleImageView实现圆形头像的方法的使用技巧和注意事项,需要的朋友参考一下 CircleImageView实现圆形头像代码分享,供大家参考,具体内容如下 一、创建属性文件(attrs.xml) 具体操作: 1、在项目的values文件底下创建一新的属性文件,文件名为attrs:N

  • 下面的屏幕截图显示了对1的测试。我想使矩形外的组件的角完全透明 但是,当父面板上有红色背景(或任何非标准颜色)时,您可以看到这种方法的缺点。拐角默认为默认面板颜色(最容易在中看到)。 最终,我希望它能用于父容器中的非标准颜色,但它的部分灵感来自于我需要做什么才能用渐变绘制复制此组件? 有人知道如何让这些角落透明吗? 而是为JTextArea的内部填充设计的,带有背景图像(

  • 如何使三角形的边框颜色不同于其他形状?如果我改变笔画的颜色,它有点起作用,好吧,我有两个不同颜色的边,没有第三个边框。我该如何改正呢?

  • 我要做什么::我想使用我当前的实现为圆形图像添加一个黑色边框,如何在不使用第三方库的情况下实现这一点 全面转变。JAVA

  • 本文向大家介绍请使用CSS画一个带锯齿形边框圆圈相关面试题,主要包含被问及请使用CSS画一个带锯齿形边框圆圈时的应答技巧和注意事项,需要的朋友参考一下 https://stackoverflow.com/questions/51697207/zig-zag-border-for-a-circle