Android Notes(View)

Android 绘图机制处理

  • 系统屏幕密度,密度值,分辨率对应关系

    1
    ldpi=120(240*320),mdpi=160(320*480),hdpi=240(480*800),xhdpi=320(720*1280),xxhdpi=480(1080*1980)
  • 独立像素密度(密度无关像素 (dp)在定义 UI 布局时应使用的虚拟像素单位,用于以密度无关方式表示布局维度 或位置)

    1
    ldpi:mdpi:hdpi:xhdpi:xxhdpi=120:160:240:320:480=0.75px:1px:1.5px:2px:3px=3:4:6:8:12
  • 单位转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    scale=getResources().getDisplayMetrics().density;
    px2dp: pxValue/scale+0.5f;
    dp2px: dpValue*scale+0.5f;

    fontScale=getResources().getDisplayMetrics().scaledDensity;
    px2sp: pxValue/fontScale+0.5f;
    sp2px: pxValue*fontScale+0.5f;

    TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,
    getResource().getDisplayMetrics());
  • 2D绘图

    • setAntiAlias()//画笔锯齿
    • setColor()//画笔颜色
    • setARGB()
    • setAlpha()
    • setTextSize()
    • setStyle()//空心,实心
    • setStrokerWidth()//边框宽度
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      drawPoint
      drawLine
      drawLines
      drawRect
      drawRoundRect
      drawCircle
      drawArc 绘制弧形,使用中心或实心,空心
      drawOval 绘制椭圆
      drawText 绘制文本
      drawPosText 指定位置绘制文本
      drawPath 绘制路径
  • XML

    • Bitmap

      1
      2
      <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
      android:src="@mipmap/car1" />
    • Shape

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      <shape
      android:shape="rectangle|oval|line|ring">
      <!--配合ImageView scaleType-->
      <size
      android:width="12dp"
      android:height="12dp" />

      <!--虚线宽度,间隔-->
      <stroke
      android:width="20dp"
      android:color="@color/colorAccent"
      android:dashGap="2dp"
      android:dashWidth="6dp" />

      </shape>
    • Layer

      1
      2
      3
      4
      <layer-list
      <item android:drawable="@mipmap/car1"/>
      <item android:drawable="@mipmap/car2"/>
      </layer-list>
    • Selector

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <item android:drawable="@android:drawable/btn_default" />
      <!--没有焦点时-->
      <item android:state_window_focused="false" />
      <!--非触摸单击时-->
      <item android:state_focused="true" android:state_pressed="true" />
      <!--触摸模式下单击时-->
      <item android:state_focused="false" android:state_pressed="true" />
      <!--选中时-->
      <item android:state_selected="true" />
      <!--获得焦点时-->
      <item android:state_focused="true" />
  • 绘图技巧

    • Canvas

      1
      2
      3
      4
      5
      6
      7
      8
      9
      //保存之前绘制图像,后续绘制在新的图层
      canvas.save()
      //save之前的图像和之后的图像合并
      canvas.restore()

      //坐标系平移,原点(0,0)移动到(x,y)
      canvas.translate()
      //坐标系旋转
      canvas.rotate()
    • Board

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      private void init() {
      mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      mPaint.setStyle(Paint.Style.STROKE);
      mPaint.setColor(Color.RED);
      mPaint.setStrokeWidth(2);
      }

      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh) {
      super.onSizeChanged(w, h, oldw, oldh);
      mWidth = getWidth();
      mHeight = getHeight();
      }

      @Override
      protected void onDraw(Canvas canvas) {
      super.onDraw(canvas);
      canvas.drawCircle(mWidth / 2, mHeight / 2,
      mWidth / 2, mPaint);

      for (int i = 0; i < 24; i++) {
      if (i == 0 || i == 6 || i == 12 | i == 18) {
      mPaint.setStrokeWidth(5);
      mPaint.setTextSize(30);
      canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,
      mWidth / 2, mHeight / 2 - mWidth / 2 + 60, mPaint);
      canvas.drawText(String.valueOf(i), mWidth / 2, mHeight / 2 - mWidth / 2 + 90, mPaint);
      } else {
      mPaint.setStrokeWidth(3);
      mPaint.setTextSize(16);
      canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,
      mWidth / 2, mHeight / 2 - mWidth / 2 + 30, mPaint);
      canvas.drawText(String.valueOf(i), mWidth / 2, mHeight / 2 - mWidth / 2 + 60, mPaint);
      }
      //旋转画布简化角度,坐标运算
      canvas.rotate(15, mWidth / 2, mHeight / 2);
      }

      canvas.save();

      mPaint.setColor(Color.CYAN);
      mPaint.setStrokeWidth(10);
      canvas.translate(mWidth / 2, mHeight / 2);
      canvas.drawLine(0, 0, 100, 100, mPaint);
      canvas.drawLine(0, 0, 100, 200, mPaint);

      canvas.restore();
      }
  • layer图层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setColor(Color.BLUE);
    canvas.drawCircle(mWidth / 2, mHeight / 2, 50, mPaint);

    canvas.saveLayerAlpha(0, 0, mWidth, mHeight, 127, ALL_SAVE_FLAG);
    mPaint.setColor(Color.RED);
    canvas.drawCircle(mWidth / 2 + 50, mHeight / 2 + 50, 50, mPaint);
    canvas.restore();
    }
  • 色彩特效

    • 图片的数据结构常使用位图Bitmap,由点阵(像素点矩阵)和颜色值(ARGB)组成
    • 色彩处理中包含色调,饱和度,亮度,使用ColorMatrix(4*5颜色矩阵)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    [a, b, c, d, e,
    f, g, h, i, j,
    k, l, m, n, o,
    p, q, r, s, t ]
    在Android中以一维数组存储 float[] mArray = new float[20]
    R = a*R + b*G + c*B + d*A + e;
    G = f*R + g*G + h*B + i*A + j;
    B = k*R + l*G + m*B + n*A + o;
    A = p*R + q*G + r*B + s*A + t;

    初始矩阵不会对颜色改变
    A=[
    1,0,0,0,0
    0,1,0,0,0
    0,0,1,0,0
    0,0,0,1,0]

    色调
    setRotate(int axis,floate degrees)
    axis=0 the RED color
    axis=1 the GREEN color
    axis=2 the BLUE color

    饱和度,为0时是灰度图像
    setSaturation(float sat)

    亮度
    setScale(float rScale, float gScale, float bScale,float aScale)

    矩阵乘法运算
    postConcat(ColorMatrix postmatrix)
    setConcat(postmatrix, this)
    imageMatrix.postContact(hueMatrix)
    imageMatrix.postContact(saturationMatrix)
    imageMatrix.postContact(lumMatrix)
    • 滑动seekbar,改变颜色混合效果

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      public static Bitmap handleImageEffect(Bitmap bm, float hue, float saturation, float lum) {
      Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
      Canvas canvas = new Canvas(bmp);
      Paint paint = new Paint();

      ColorMatrix hueMatrix = new ColorMatrix();
      hueMatrix.setRotate(0, hue);
      hueMatrix.setRotate(1, hue);
      hueMatrix.setRotate(2, hue);

      ColorMatrix saturationMatrix = new ColorMatrix();
      saturationMatrix.setSaturation(saturation);

      ColorMatrix lumMatrix = new ColorMatrix();
      lumMatrix.setScale(lum, lum, lum, 1);

      ColorMatrix imageMatrix = new ColorMatrix();
      imageMatrix.postConcat(hueMatrix);
      imageMatrix.postConcat(saturationMatrix);
      imageMatrix.postConcat(lumMatrix);

      paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
      canvas.drawBitmap(bm, 0, 0, paint);
      return bmp;
      }

      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
      switch (seekBar.getId()) {
      case R.id.hueSeekBar:
      mHue = (progress - 50) * 1.0f / 50 * 180;
      break;
      case R.id.saturationSeekBar:
      mSaturation = progress * 1.0f / 50;
      break;
      case R.id.lumSeekBar:
      mLum = progress * 1.0f / 50;
      break;
      }
      filterImage.setImageBitmap(ColorMatrixUtil.handleImageEffect(bm,
      mHue, mSaturation, mLum));
      }
    • Android不允许直接修改原图,创建同大小的位图,并将原图绘制到该Bitmap

      1
      2
      3
      4
      Bitmap bmp=Bitmap.createBitmap(bm.getWidth(),bm.getHeight(),Bitmap.Config.ARGB_8888);
      Canvas canvas=new Canvas(bmp);
      paint.setColorFilter(new ColorMatrixColorFilter(matrix));
      canvas.drawBitmap(bm,0,0,paint);
  • ColorMatrix

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    private void addEts() {
    gridLayout.post(new Runnable() {
    int mEtHeight;
    int mEtWidth;

    @Override
    public void run() {
    mEtHeight = gridLayout.getWidth() / 4;
    mEtWidth = gridLayout.getWidth() / 5;
    for (int i = 0; i < 20; i++) {
    EditText editText = new EditText(getBaseContext());
    gridLayout.addView(editText, mEtWidth, mEtHeight);
    mEts[i] = editText;
    }
    initMatrix();
    }
    });
    }

    private void initMatrix() {
    for (int i = 0; i < mEts.length; i++) {
    if (i % 6 == 0) {
    mEts[i].setText("1");
    } else {
    mEts[i].setText("0");
    }
    }
    }

    private void getMatrix() {
    for (int i = 0; i < mEts.length; i++) {
    mColorMatrix[i] = Float.valueOf(mEts[i].getText().toString());
    }
    }

    private void setImageMatrix() {
    Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bmp);
    Paint paint = new Paint();
    ColorMatrix colorMatrix = new ColorMatrix(mColorMatrix);
    paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
    canvas.drawBitmap(bm, 0, 0, paint);
    filterImage.setImageBitmap(bmp);
    }
    • 图像反转
  • 获取图像像素值,三种像素点处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    private void getPixels() {
    ImageView pixelImage1 = findViewById(R.id.pixelImage1);
    ImageView pixelImage2 = findViewById(R.id.pixelImage2);
    ImageView pixelImage3 = findViewById(R.id.pixelImage3);

    bm = BitmapFactory.decodeResource(getResources(), R.mipmap.car3);
    int[] pixels = new int[bm.getWidth() * bm.getHeight()];
    int[] newPixels1 = new int[bm.getWidth() * bm.getHeight()];
    int[] newPixels2 = new int[bm.getWidth() * bm.getHeight()];
    int[] newPixels3 = new int[bm.getWidth() * bm.getHeight()];

    bm.getPixels(pixels, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
    Bitmap bmp1 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
    Bitmap bmp2 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
    Bitmap bmp3 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);
    for (int i = 0; i < pixels.length; i++) {
    int color = pixels[i];
    int r = Color.red(color);
    int g = Color.green(color);
    int b = Color.blue(color);
    int a = Color.alpha(color);

    //老照片
    int r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);
    int g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);
    int b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);
    newPixels1[i] = Color.rgb(r1, g1, b1);

    //底片处理
    int r2 = 255 - r;
    int g2 = 255 - g;
    int b2 = 255 - b;
    if (r > 255) {
    r = 255;
    } else if (r < 0) {
    r = 0;
    }
    if (g > 255) {
    g = 255;
    } else if (g < 0) {
    g = 0;
    }
    if (b > 255) {
    b = 255;
    } else if (b < 0) {
    b = 0;
    }
    newPixels2[i] = Color.argb(a, r2, g2, b2);

    //浮雕
    int rB = 0;
    int gB = 0;
    int bB = 0;
    if (i + 1 < pixels.length) {
    int colorB = pixels[i + 1];
    rB = Color.red(colorB);
    gB = Color.green(colorB);
    bB = Color.blue(colorB);

    rB = r - rB + 127;
    gB = g - gB + 127;
    bB = b - bB + 127;
    if (rB > 255) {
    rB = 255;
    }
    if (gB > 255) {
    gB = 255;
    }
    if (bB > 255) {
    bB = 255;
    }
    }
    newPixels3[i] = Color.rgb(rB, gB, bB);
    }
    bmp1.setPixels(newPixels1, 0, bm.getWidth(),
    0, 0, bm.getWidth(), bm.getHeight());
    bmp2.setPixels(newPixels2, 0, bm.getWidth(),
    0, 0, bm.getWidth(), bm.getHeight());
    bmp3.setPixels(newPixels3, 0, bm.getWidth(),
    0, 0, bm.getWidth(), bm.getHeight());

    pixelImage1.setImageBitmap(bmp1);
    pixelImage2.setImageBitmap(bmp2);
    pixelImage3.setImageBitmap(bmp3);
    }
  • 图像变换矩阵初始矩阵

    1
    2
    3
    [1 0 0
    0 1 0
    0 0 1]
  • 图像处理基本变换

    • Translate
    1
    2
    3
    4
    5
    6
    7
    p(x0,y0)->p(x,y)
    x=Δx+x0
    y=Δy+y0
    变换矩阵
    [1 0 Δx
    0 1 Δy
    0 0 1 ]
    • Rotate 以坐标原点为中心旋转
    • Scale 每个点的坐标等比例缩放
    • Skew 保持所有点的x或y轴坐标不变,对应的y或x坐标等比例平移,有水平错切和垂直错切
    1
    2
    3
    4
    5
    6
    matrix.setRotate()
    matrix.setTranslate()
    matrix.setScale()
    matrix.setSkew()
    set()会重置
    pre().post()前乘后乘对矩阵混合使用
  • drawBitmapMesh()像素块

    1
    2
    改变图像坐标值重新定位每一个图像块
    drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,@NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,@Nullable Paint paint)
  • 旗帜FlagView

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     public class FlagView extends View {

    private float[] orig, verts;
    int HEIGHT = 100, WIDTH = 100;
    //振幅
    private float A = 20;
    private Bitmap bitmap;
    private float k;

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

    public FlagView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
    }

    public FlagView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
    }

    private void init() {

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.car3);
    int bitmapWidth = bitmap.getWidth();
    int bitmapHeight = bitmap.getHeight();
    int index = 0;

    orig = new float[bitmapHeight * bitmapWidth];
    verts = new float[bitmapHeight * bitmapWidth];
    for (int y = 0; y <= HEIGHT; y++) {
    float fy = bitmapHeight * y / HEIGHT;
    for (int x = 0; x <= WIDTH; x++) {
    float fx = bitmapWidth * x / WIDTH;
    orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
    //+100 避免被遮挡
    orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 100;
    index += 1;
    }
    }
    }

    @Override
    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    flagWave();
    k += 0.1f;
    canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts,
    0, null, 0, null);
    invalidate();
    }

    private void flagWave() {
    for (int j = 0; j <= HEIGHT; j++) {
    for (int i = 0; i <= WIDTH; i++) {
    verts[(j * (WIDTH + 1) + i) * 2 + 0] += 0;
    //图像动起来,纵坐标周期性变化
    float offsetY = (float) Math.sin((float) i / WIDTH * 2 * Math.PI + Math.PI * k);
    verts[(j * (WIDTH + 1) + i) * 2 + 1] = orig[(j * WIDTH + i) * 2 + 1] + offsetY * A;
    }
    }
    }
    }
willkernel wechat
关注微信公众号
帅哥美女们,请赐予我力量吧!