1. 程式人生 > >android 中漸變的實現和SweepGradient 圓形漸變重點注意

android 中漸變的實現和SweepGradient 圓形漸變重點注意

Android 的自定義View神通廣大,可以實現各種複雜的樣式,漸變圓弧就是其中的一種。

1 shape 實現漸變

這個比較簡單就是定義一個漸變的shape。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="0"
        android:endColor="#FFC54E"
        android:startColor
="#FF9326" android:type="linear" />
<corners android:bottomLeftRadius="25dp" android:bottomRightRadius="25dp" android:topLeftRadius="25dp" android:topRightRadius="25dp" /> </shape>

在這裡插入圖片描述

圖片右側的黃色色塊就是漸變,使用時直接設定背景。

2 LinearGradient

2.1 第一種

public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
/**
* Create a shader that draws a linear gradient along a line.
*
* @param x0 The x-coordinate for the start of the gradient line
* @param y0 The y-coordinate for the start of the gradient line
* @param x1 The x-coordinate for the end of the gradient line
* @param y1 The y-coordinate for the end of the gradient line
* @param color0 The color at the start of the gradient line.
* @param color1 The color at the end of the gradient line.
* @param tile The Shader tiling mode
*/
x0,y0,x1,y1是起始位置和漸變的結束位置,color0,color1是漸變顏色,最後一個引數表示繪製模式:

Shader.TileMode有3種引數可供選擇,分別為CLAMP、REPEAT和MIRROR:

[1] CLAMP的作用是如果渲染器超出原始邊界範圍,則會複製邊緣顏色對超出範圍的區域進行著色
[2] REPEAT的作用是在橫向和縱向上以平鋪的形式重複渲染點陣圖
[3] MIRROR的作用是在橫向和縱向上以映象的方式重複渲染點陣圖

2.2 第二種

public LinearGradient (float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile);
/**
* Create a shader that draws a linear gradient along a line.
*
* @param x0 The x-coordinate for the start of the gradient line
* @param y0 The y-coordinate for the start of the gradient line
* @param x1 The x-coordinate for the end of the gradient line
* @param y1 The y-coordinate for the end of the gradient line
* @param colors The colors to be distributed along the gradient line
* @param positions May be null. The relative positions [0…1] of
* each corresponding color in the colors array. If this is null,
* the the colors are distributed evenly along the gradient line.
* @param tile The Shader tiling mode
*/

x0,y0,x1,y1 引數和上面一樣,tile和上面一樣。
colors表示漸變的顏色陣列;
positions指定顏色陣列的相對位置

package com.example.hpuzz.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class ViewDemo extends View {
    public ViewDemo(Context context) {
        super(context);
    }

    public ViewDemo(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        LinearGradient linearGradient = new LinearGradient(0, 0, 0, getMeasuredHeight(),new int[]{Color.RED, Color.BLUE}, null, LinearGradient.TileMode.REPEAT);
        paint.setShader(linearGradient);
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension((int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics()));
    }
}

在這裡插入圖片描述

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        float[] position = new float[3];
        position[0] = 0.0f;
        position[1] = 0.8f;
        position[2] = 1.0f;

        LinearGradient linearGradient = new LinearGradient(0, 0, 0, getMeasuredHeight(),new int[]{Color.RED,Color.GREEN, Color.BLUE}, position, LinearGradient.TileMode.REPEAT);
        paint.setShader(linearGradient);
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint);
    }

在這裡插入圖片描述

可以看到position的取值範圍[0,1],作用是指定某個位置的顏色值,如果傳null,漸變就線性變化。

3 SweepGradient

 /**
     * A Shader that draws a sweep gradient around a center point.
     *
     * @param cx       The x-coordinate of the center
     * @param cy       The y-coordinate of the center
     * @param colors   The colors to be distributed between around the center.
     *                 There must be at least 2 colors in the array.
     * @param positions May be NULL. The relative position of
     *                 each corresponding color in the colors array, beginning
     *                 with 0 and ending with 1.0. If the values are not
     *                 monotonic, the drawing may produce unexpected results.
     *                 If positions is NULL, then the colors are automatically
     *                 spaced evenly.
     */
    public SweepGradient(float cx, float cy,
            @NonNull @ColorInt int colors[], @Nullable float positions[]) {
        if (colors.length < 2) {
            throw new IllegalArgumentException("needs >= 2 number of colors");
        }
        if (positions != null && colors.length != positions.length) {
            throw new IllegalArgumentException(
                    "color and position arrays must be of equal length");
        }
        mType = TYPE_COLORS_AND_POSITIONS;
        mCx = cx;
        mCy = cy;
        mColors = colors.clone();
        mPositions = positions != null ? positions.clone() : null;
    }

    /**
     * A Shader that draws a sweep gradient around a center point.
     *
     * @param cx       The x-coordinate of the center
     * @param cy       The y-coordinate of the center
     * @param color0   The color to use at the start of the sweep
     * @param color1   The color to use at the end of the sweep
     */
    public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) {
        mType = TYPE_COLOR_START_AND_COLOR_END;
        mCx = cx;
        mCy = cy;
        mColor0 = color0;
        mColor1 = color1;
        mColors = null;
        mPositions = null;
    }

cx,cy,圓的中心座標。
color0,color1漸變顏色
colors漸變顏色陣列
positions 顏色位置,範圍[0,1]

package com.example.hpuzz.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class ViewDemo2 extends View {
    public ViewDemo2(Context context) {
        super(context);
    }

    public ViewDemo2(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(15);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
       /* float[] position = new float[3];
        position[0] = 0.0f;
        position[1] = 0.8f;
        position[2] = 1.0f;*/

       // SweepGradient linearGradient = new SweepGradient(getMeasuredWidth()/2,getMeasuredHeight()/2,new int[]{Color.RED,Color.GREEN, Color.BLUE}, position);
        SweepGradient linearGradient = new SweepGradient((getMeasuredWidth() - 40)/2,(getMeasuredHeight() - 40)/2,new int[]{Color.RED,Color.GREEN, Color.BLUE}, null);
        Matrix matrix = new Matrix();
        matrix.setRotate(180, getMeasuredWidth()/2, getMeasuredHeight()/2);
        linearGradient.setLocalMatrix(matrix);
        paint.setShader(linearGradient);
        RectF rect = new RectF(20, 20, getMeasuredWidth() - 20, getMeasuredHeight() - 20);
        canvas.drawArc(rect,0,360,false,paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension((int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 240, getResources().getDisplayMetrics()), (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 240, getResources().getDisplayMetrics()));
    }
}

在這裡插入圖片描述

改變開始漸變的角度:

  Matrix matrix = new Matrix();
        matrix.setRotate(180, (getMeasuredWidth()-40)/2, (getMeasuredHeight()-40)/2);
        linearGradient.setLocalMatrix(matrix);

positions為null表示線性漸變,如果不為空可以改變漸變中某些顏色的位置。

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(15);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        float[] position = new float[3];
        position[0] = 0.0f;
        position[1] = 0.8f;
        position[2] = 1.0f;

        SweepGradient linearGradient = new SweepGradient(getMeasuredWidth()/2,getMeasuredHeight()/2,new int[]{Color.RED,Color.GREEN, Color.BLUE}, position);
       // SweepGradient linearGradient = new SweepGradient((getMeasuredWidth() - 40)/2,(getMeasuredHeight() - 40)/2,new int[]{Color.RED,Color.GREEN, Color.BLUE}, null);
        Matrix matrix = new Matrix();
        matrix.setRotate(180, getMeasuredWidth()/2, getMeasuredHeight()/2);
        linearGradient.setLocalMatrix(matrix);
        paint.setShader(linearGradient);
        RectF rect = new RectF(20, 20, getMeasuredWidth() - 20, getMeasuredHeight() - 20);
        canvas.drawArc(rect,0,360,false,paint);
    }

在這裡插入圖片描述

可以看到藍色被壓縮的只剩了一點。

positions的特殊應用,SweepGradient 無法指定顏色從某個角度到某個角度,可以利用positons指定顏色位置實現相應弧度顯示相應顏色。
類似只畫半個圓,想讓顏色從0度劃過90度分佈,在90度的位置顯示綠色,如果不設定positions則顯示效果為:

在這裡插入圖片描述

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(15);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        float[] position = new float[3];
        position[0] = 0.0f;
        position[1] = 0.25f;
        position[2] = 1.0f;

        SweepGradient linearGradient = new SweepGradient(getMeasuredWidth()/2,getMeasuredHeight()/2,new int[]{Color.RED,Color.GREEN, Color.BLUE}, position);
       // SweepGradient linearGradient = new SweepGradient((getMeasuredWidth() - 40)/2,(getMeasuredHeight() - 40)/2,new int[]{Color.RED,Color.GREEN, Color.BLUE}, null);
        Matrix matrix = new Matrix();
        matrix.setRotate(180, getMeasuredWidth()/2, getMeasuredHeight()/2);
        linearGradient.setLocalMatrix(matrix);
        paint.setShader(linearGradient);
        RectF rect = new RectF(20, 20, getMeasuredWidth() - 20, getMeasuredHeight() - 20);
        canvas.drawArc(rect,180,90,false,paint);
    }

在這裡插入圖片描述

基於上面的知識,60度,30度都可以實現。

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(15);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        float[] position = new float[3];
        position[0] = 0.0f;
        position[1] = 0.17f;
        position[2] = 1.0f;

        SweepGradient linearGradient = new SweepGradient(getMeasuredWidth()/2,getMeasuredHeight()/2,new int[]{Color.RED