1. 程式人生 > >Android獲得線性漸變某點的顏色

Android獲得線性漸變某點的顏色

安卓官方確實提供了好多非常強大的工具給我們了,例如我們最近經常在shape中加入gradient(漸變),像我的專案中用的是線性漸變,

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dip" />
    <gradient android:startColor="#262626" android:endColor="#ffbc1c" android:angle="0" />
</shape>
轉載請保留原文連結:http://blog.csdn.net/u010593680/article/details/50987671

並且這個圖片作為SeekBar的背景,用來選擇顏色,滑到哪就選擇哪裡的顏色,如圖所示:


為此我想到了兩種可能的實現方法:
1、獲取SeekBar的背景的圖片的bitmap,獲取對應點來獲得顏色
2、直接通過線性漸變的演算法獲得某個位置上的顏色
方法1 簡單方便,對於其他的控制元件也可以使用,但是消耗的記憶體比較大
方法2 記憶體消耗非常少,但是需要了解線性漸變的演算法,並且只能對線性漸變的圖片有效,其他漸變方式都需要重新寫,但是線性漸變往往用得比較多,所以打算使用第二個方法。

線性漸變是最簡單的漸變,思想就是對應顏色A的R G B不斷的往顏色B的R G B靠近,並且認識到的是:在java中,(很多其他語言也是)用一個int來存放顏色的RGB值,但是這個只是儲存方式而已,實際上每個RGB是互不相關的,漸變時需要分別取出,分別變化。寫了一個簡易的兩個顏色漸變的顏色選擇器,程式碼如下:

/**
 * Created by chenxiaoxuan1 on 16/3/25.
 */
public class LinearGradientUtil {
    private int mStartColor;
    private int mEndColor;

    public LinearGradientUtil(int startColor, int endColor) {
        this.mStartColor = startColor;
        this.mEndColor = endColor;
    }

    public void setStartColor(int startColor) {
        this.mStartColor = startColor;
    }

    public void setEndColor(int endColor) {
        this.mEndColor = endColor;
    }
    //獲取某一個百分比間的顏色,radio取值[0,1]
    public int getColor(float radio) {
        int redStart = Color.red(mStartColor);
        int blueStart = Color.blue(mStartColor);
        int greenStart = Color.green(mStartColor);
        int redEnd = Color.red(mEndColor);
        int blueEnd = Color.blue(mEndColor);
        int greenEnd = Color.green(mEndColor);

        int red = (int) (redStart + ((redEnd - redStart) * radio + 0.5));
        int greed = (int) (greenStart + ((greenEnd - greenStart) * radio + 0.5));
        int blue = (int) (blueStart + ((blueEnd - blueStart) * radio + 0.5));
        return Color.argb(255,red, greed, blue);
    }
}

實現後並且用單元測試測試過,然後就正式的使用了,使用結果還是很滿意的~

後來,有一個需求是做一個簡單的條形顏色選擇器,也是用SeekBar實現的,也是線性漸變,只是顏色多了一些而已。如圖:


原理是一樣的,程式碼如下:

/**
 * 線性顏色取色器
 * Created by chenxiaoxuan1 on 16/3/25.
 */
public class ColorPickGradient {
    //設定的顏色
    public static final int[] PICKCOLORBAR_COLORS = new int[]{0xFFFFFFFF,0xFFFF3030, 0xFFF4A460,
            0xFFFFFF00, 0xFF66CD00,
            0xFF458B00, 0xFF0000EE,
            0xFF912CEE,0xFF000000};
    //每個顏色的位置
    public static final float[] PICKCOLORBAR_POSITIONS = new float[]{0f, 0.1f, 0.2f, 0.3f, 0.5f, 0.65f,0.8f,0.9f,1f};

    private int[] mColorArr = PICKCOLORBAR_COLORS;
    private float[] mColorPosition = PICKCOLORBAR_POSITIONS;

    public ColorPickGradient(int[] colorArr) {
        this.mColorArr = colorArr;
    }

    public ColorPickGradient() {
    }

    /**
     * 獲取某個百分比位置的顏色
     * @param radio 取值[0,1]
     * @return
     */
    public int getColor(float radio) {
        int startColor;
        int endColor;
        if (radio >= 1) {
            return mColorArr[mColorArr.length - 1];
        }
        for (int i = 0; i < mColorPosition.length; i++) {
            if (radio <= mColorPosition[i]) {
                if (i == 0) {
                    return mColorArr[0];
                }
                startColor = mColorArr[i - 1];
                endColor = mColorArr[i];
                float areaRadio = getAreaRadio(radio,mColorPosition[i-1],mColorPosition[i]);
                return getColorFrom(startColor,endColor,areaRadio);
            }
        }
        return -1;
    }

    public float getAreaRadio(float radio, float startPosition, float endPosition) {
        return (radio - startPosition) / (endPosition - startPosition);
    }

    /**
     *  取兩個顏色間的漸變區間 中的某一點的顏色
     * @param startColor
     * @param endColor
     * @param radio
     * @return
     */
    public int getColorFrom(int startColor, int endColor, float radio) {
        int redStart = Color.red(startColor);
        int blueStart = Color.blue(startColor);
        int greenStart = Color.green(startColor);
        int redEnd = Color.red(endColor);
        int blueEnd = Color.blue(endColor);
        int greenEnd = Color.green(endColor);

        int red = (int) (redStart + ((redEnd - redStart) * radio + 0.5));
        int greed = (int) (greenStart + ((greenEnd - greenStart) * radio + 0.5));
        int blue = (int) (blueStart + ((blueEnd - blueStart) * radio + 0.5));
        return Color.argb(255, red, greed, blue);
    }

}

使用程式碼如下:
private SeekBar mSbColor;

//....
//設定SeekBar的顏色
private void initColorBar(){
        ShapeDrawable.ShaderFactory shaderFactory = new ShapeDrawable.ShaderFactory() {
            @Override
            public Shader resize(int width, int height) {
                LinearGradient linearGradient = new LinearGradient(0, 0, width, height,
                        ColorPickGradient.PICKCOLORBAR_COLORS, ColorPickGradient.PICKCOLORBAR_POSITIONS, Shader.TileMode.REPEAT);
                return linearGradient;
            }
        };
        PaintDrawable paint = new PaintDrawable();
        paint.setShape(new RectShape());
        paint.setCornerRadius(10);
        paint.setShaderFactory(shaderFactory);
        mSbColor.setProgressDrawable(paint);
    }
//當SeekBar被滑動時,獲取顏色
mSbColor.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                float radio = (float)progress / mSbColor.getMax();
                mColor = mColorPickGradient.getColor(radio);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

轉載請保留原文連結:http://blog.csdn.net/u010593680/article/details/50987671