AndroidのBitmap Shaderを利用して、自分のフレームを持つ丸い顔写真を作ります。


効果は以下の通りです

Bitmap Shaderの簡単な紹介Shaderとは何ですか?Shaderの種類はどのような種類がありますか?また、どのように使用するかは本論文の範疇に属さないです。この点についてよく知らない方は、まずShader の基本的な使い方を学んでみてください。BitmapShaderの主な役割は、Paintオブジェクトを通じて、キャンバスに指定されたBitmapを充填することであり、一連の効果を実現し、次の3つのモードを選択することができる。
      1.CLAMP -引張り、ここで引張りますのはピクチャの最後の要素で、絶えず繰り返します。この効果は画像が小さいですが、描く面積が大きい場合は明らかです。
      2.REPEAT -繰り返し、横方向の縦方向の連続的な繰り返しは、前のパターンとは違って、このようなモードは画像では比較的小さいので、要求を満たすことができません。
      3.MIRROR −ロールオーバ、このようなモードはREPEAT と同様であるが、ここでの繰り返しはロールオーバの繰り返しであり、折り紙の効果と同じである。
私たちが使用するのはCLAMP モードです。画像の大きさを制御すれば、画像が引き伸ばされないからです。
具体的に紹介します
画像をカスタマイズするために、枠の幅と色を設定します。まず、res/valuesディレクトリの下で、atrs.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;
mSrcurBitmapは、得られた画像を適切に縮小または拡大し、我々の図形に対する要求に適応するものであるが、ここの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がBitmap Shaderを利用してフレームの丸い顔写真を持っているすべての内容を作っています。この文章は皆さんにAndroidを開発する時に役に立ちます。もし疑問があれば、メッセージを残して交流してください。