引子
颜色渐变一般两种方式(好像是废话额,因为凡是涉及到特效或者动画,基本都是两种方式··)
一种是写XML配置,一种是写纯代码;下面分别就两个种方式给出demo;
方式1
在drawable/目录下创建一个文件gradient.xml,内容如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="0"
android:endColor="@android:color/holo_red_light"
android:startColor="@android:color/holo_green_light" />
</shape>
然后给某个view指定background:
<View
android:layout_width="@dimen/shape_width"
android:layout_height="@dimen/shape_width"
android:background="@drawable/gradient" />
实际效果如下:
上面的gradient,我们用了3个属性:angle角度,startColor,endColor起始和结束的颜色;
起始结束颜色好理解,这里的这个angle,其实我们还可以指定为其他值,上面指定0 ,我们得到了一个从左到右的渐变;
此外还可以指定,
0 是从左到右渐变;45是从左下角向右上角渐变;90是从下到上,135是从右下角到左上角;180则是从右到左;(当然也可以是 -45,-90....)
优点:简单有效。足以应付大部分的渐变需求;
缺点: 不够灵活,不能满足高级需求。而且不支持任意角度(很诡异,只支持45的倍数);
方式二
利用LinearGradient + Paint + 自定义View;
由于是纯代码实现,我就直接帖代码了;重点看红色文字部分;
1 package com.example.colorstudy;
2
3 import android.content.Context;
4 import android.content.res.TypedArray;
5 import android.graphics.Canvas;
6 import android.graphics.Color;
7 import android.graphics.LinearGradient;
8 import android.graphics.Paint;
9 import android.graphics.Shader;
10 import android.support.annotation.Nullable;
11 import android.util.AttributeSet;
12 import android.view.View;
13
14 public class GradientDemoView extends View {
15
16 public GradientDemoView(Context context) {
17 this(context, null);
18 }
19
20 public GradientDemoView(Context context, @Nullable AttributeSet attrs) {
21 this(context, attrs, 0);
22 }
23
24 public GradientDemoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
25 super(context, attrs, defStyleAttr);
26 initAttrs(context, attrs);
27 }
28
29 private int mode;
30
31 private void initAttrs(Context context, AttributeSet attrs) {
32 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.GradientDemoView);
33 if (null != ta) {
34 mode = ta.getInteger(R.styleable.GradientDemoView_mode, 0);
35 }
36 }
37
38 @Override
39 protected void onDraw(Canvas canvas) {
40 super.onDraw(canvas);
41
42 int width = getWidth();
43 int height = getHeight();
44
45 int colorStart = Color.RED;
46 int color1 = Color.GREEN;
47 int colorEnd = Color.BLUE;
48
49 Paint paint = new Paint();
50
51 //重点解析这里的渐变配置
52 /**
53 * Create a shader that draws a linear gradient along a line. 创建一个沿着"一条线"绘制线性渐变的着色器?
54 *
55 * @param x0 "一条线"开始位置的X - 这个坐标是以 左上角为原点,对哦,android里面所有的绘制都是以控件左上角为原点(0,0)
56 * @param y0 "一条线"开始位置的Y
57 * @param x1 "一条线"结束为止的X
58 * @param y1 "一条线"结束为止的Y
59 * @param colors 颜色数组,可以是3个以上
60 * @param positions 颜色分段权重:比如说,有3种颜色,红绿蓝渐变,这里的positions的值是new float[]{0, 0.75f, 1f};
61 * 则,0到0.75这一段,是红色渐变为绿色,0.75到1这一段是 绿色渐变为蓝色;
62 * @param tile 填充模式?
63 * 详解:
64 * CLAMP : 重复最后一种颜色直到View结束(当你的起始结束的坐标并没有覆盖整个View,那么这种模式将会用最后一种颜色填充剩余的部分)
65 * REPEAT: 当你的起始结束的坐标并没有覆盖整个View,这种模式将会进行颜色的重新渐变;
66 * MIRROR: 镜像模式绘制,当你的起始结束的坐标并没有覆盖整个View,剩余的部分将会尽量和已经绘制的部分颜色对称;
67 */
68 LinearGradient backGradient = null;
69 if (mode == 0) {
70 backGradient = new LinearGradient(0, 0, 0, height / 2,
71 new int[]{colorStart, color1, colorEnd}, new float[]{0, 0.75f, 1f}, Shader.TileMode.CLAMP);
72 } else if (mode == 1) {
73 backGradient = new LinearGradient(0, 0, 0, height / 2,
74 new int[]{colorStart, color1, colorEnd}, new float[]{0, 0.75f, 1f}, Shader.TileMode.REPEAT);
75 } else if (mode == 2) {
76 backGradient = new LinearGradient(0, 0, 0, height / 2,
77 new int[]{colorStart, color1, colorEnd}, new float[]{0, 0.75f, 1f}, Shader.TileMode.MIRROR);
78 }
79
80
81 paint.setShader(backGradient);
82 canvas.drawRect(0, 0, width, height, paint);
83
84 }
85
86
87 }
其他文件:res/values/attr.xml
<resources>
<declare-styleable name="GradientDemoView">
<attr name="mode" format="integer" />
</declare-styleable>
</resources>
res/values/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="shape_width">30dp</dimen>
</resources>
使用此控件的xml:
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:rowCount="2">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:orientation="horizontal">
<com.example.colorstudy.GradientDemoView
android:layout_width="@dimen/shape_width"
android:layout_height="@dimen/shape_width"
app:mode="0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="CLAMP模式" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:orientation="horizontal">
<com.example.colorstudy.GradientDemoView
android:layout_width="@dimen/shape_width"
android:layout_height="@dimen/shape_width"
app:mode="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="REPEAT模式" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:gravity="center"
android:orientation="horizontal">
<com.example.colorstudy.GradientDemoView
android:layout_width="@dimen/shape_width"
android:layout_height="@dimen/shape_width"
app:mode="2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:text="MIRROR模式 " />
</LinearLayout>
</GridLayout>
实际效果:
优点:几乎能够满足你能想到的所有渐变需求,处理起来很灵活;渐变色可以是3个以上,每种颜色占比多少可以自己调节,渐变的模式自己指定;而且还可以顺带加上其他特效,就这一点,xml写配置就无法比拟;
缺点:如果是较为复杂的渐变,对开发人员要求就比较高了,而且还 可能涉及到什么数学算法之类的,数学渣一脸泪有木有·····