我想创建一个类似下图的形状:
注意从颜色1到颜色2的上半部分渐变,但是从颜色3到颜色4渐变的下半部分。我知道如何使用单个渐变制作形状,但我不知道如何分割形状分为两半,形成一个有2个不同渐变的形状。
有什么想法吗?
答案 0 :(得分:375)
我认为你不能用XML做到这一点(至少在Android中不行),但我发现了一个很好的解决方案here看起来好像很有帮助!
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
LinearGradient lg = new LinearGradient(0, 0, width, height,
new int[]{Color.GREEN, Color.GREEN, Color.WHITE, Color.WHITE},
new float[]{0,0.5f,.55f,1}, Shader.TileMode.REPEAT);
return lg;
}
};
PaintDrawable p=new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
基本上,int数组允许您选择多个颜色停止,并且后面的float数组定义这些停靠点的位置(从0到1)。然后,如上所述,您可以将其用作标准Drawable。
编辑:以下是您在场景中使用此功能的方法。假设你有一个用XML定义的Button,如下所示:
<Button
android:id="@+id/thebutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press Me!"
/>
然后你在onCreate()方法中输入这样的东西:
Button theButton = (Button)findViewById(R.id.thebutton);
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
@Override
public Shader resize(int width, int height) {
LinearGradient lg = new LinearGradient(0, 0, 0, theButton.getHeight(),
new int[] {
Color.LIGHT_GREEN,
Color.WHITE,
Color.MID_GREEN,
Color.DARK_GREEN }, //substitute the correct colors for these
new float[] {
0, 0.45f, 0.55f, 1 },
Shader.TileMode.REPEAT);
return lg;
}
};
PaintDrawable p = new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
theButton.setBackground((Drawable)p);
我目前无法测试这个,这是我头脑中的代码,但基本上只是替换,或为您需要的颜色添加停止。基本上,在我的例子中,你会从浅绿色开始,在中心之前略微淡化到白色(给出淡化,而不是苛刻的过渡),从白色到中间的白色褪色45%到55%之间,然后从中间绿色到深绿色从55%到最后。这可能看起来不像你的形状(现在,我无法测试这些颜色),但你可以修改它来复制你的例子。
编辑:此外,0, 0, 0, theButton.getHeight()
指的是渐变的x0,y0,x1,y1坐标。所以基本上,它从x = 0(左侧)开始,y = 0(顶部),并且延伸到x = 0(我们想要一个垂直渐变,所以不需要从左到右的角度),y =高度的按钮。因此,渐变从按钮顶部到按钮底部成90度角。
编辑:好的,所以我还有一个有用的想法,哈哈。现在它可以在XML中工作,但也应该适用于Java中的形状。它有点复杂,我想有一种方法可以将它简化为单一形状,但这就是我现在所拥有的:
<强> green_horizontal_gradient.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners
android:radius="3dp"
/>
<gradient
android:angle="0"
android:startColor="#FF63a34a"
android:endColor="#FF477b36"
android:type="linear"
/>
</shape>
<强> half_overlay.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid
android:color="#40000000"
/>
</shape>
<强> layer_list.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:drawable="@drawable/green_horizontal_gradient"
android:id="@+id/green_gradient"
/>
<item
android:drawable="@drawable/half_overlay"
android:id="@+id/half_overlay"
android:top="50dp"
/>
</layer-list>
<强>的test.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
>
<TextView
android:id="@+id/image_test"
android:background="@drawable/layer_list"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:text="Layer List Drawable!"
android:textColor="@android:color/white"
android:textStyle="bold"
android:textSize="26sp"
/>
</RelativeLayout>
好的,基本上我已经为XML创建了一个水平绿色渐变的形状渐变,设置为0度角,从顶部区域的左侧绿色变为右侧绿色。接下来,我制作了一个半透明灰色的形状矩形。我很确定可以将其内联到图层列表XML中,避免使用这个额外的文件,但我不确定如何。但是没关系,那么hacky部分会出现在layer_list XML文件中。我将绿色渐变作为底层,然后将半覆盖层作为第二层,从顶部偏移50dp。显然,你希望这个数字总是你视图大小的一半,而不是固定的50dp。不过,我认为你不能使用百分比。从那里,我只是使用layer_list.xml文件作为我的背景,将TextView插入到我的test.xml布局中。我将高度设置为100dp(叠加层偏移量的两倍),结果如下:
多田!
再一次编辑:我意识到你可以将形状嵌入到可绘制为图层的图层列表中,这意味着您不再需要3个单独的XML文件!你可以像这样结合它们来实现相同的结果:
<强> layer_list.xml 强>
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners
android:radius="3dp"
/>
<gradient
android:angle="0"
android:startColor="#FF63a34a"
android:endColor="#FF477b36"
android:type="linear"
/>
</shape>
</item>
<item
android:top="50dp"
>
<shape
android:shape="rectangle"
>
<solid
android:color="#40000000"
/>
</shape>
</item>
</layer-list>
您可以按照自己喜欢的方式对多个项目进行分层!我可以尝试一下,看看我是否可以通过Java获得更多功能。
我认为这是最后一次编辑... :好的,所以你绝对可以通过Java修复定位,如下所示:
TextView tv = (TextView)findViewById(R.id.image_test);
LayerDrawable ld = (LayerDrawable)tv.getBackground();
int topInset = tv.getHeight() / 2 ; //does not work!
ld.setLayerInset(1, 0, topInset, 0, 0);
tv.setBackgroundDrawable(ld);
然而!这导致另一个令人讨厌的问题,因为在绘制之前你无法测量TextView。我还不太确定你怎么做到这一点......但手动为topInset插入一个数字确实有效。
我撒了谎,还有一个编辑
好的,找到了如何手动更新此图层drawable以匹配容器的高度,可以找到完整描述here。这段代码应该放在你的onCreate()方法中:
final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
LayerDrawable ld = (LayerDrawable)tv.getBackground();
ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
}
});
我已经完成了!呼! :)
答案 1 :(得分:27)
您可以使用图层列表在xml中对渐变形状进行叠加。 想象一下具有默认状态的按钮,如下所示,其中第二个项目是半透明的。它增加了一种渐晕。 (请原谅自定义颜色。)
<!-- Normal state. -->
<item>
<layer-list>
<item>
<shape>
<gradient
android:startColor="@color/grey_light"
android:endColor="@color/grey_dark"
android:type="linear"
android:angle="270"
android:centerColor="@color/grey_mediumtodark" />
<stroke
android:width="1dp"
android:color="@color/grey_dark" />
<corners
android:radius="5dp" />
</shape>
</item>
<item>
<shape>
<gradient
android:startColor="#00666666"
android:endColor="#77666666"
android:type="radial"
android:gradientRadius="200"
android:centerColor="#00666666"
android:centerX="0.5"
android:centerY="0" />
<stroke
android:width="1dp"
android:color="@color/grey_dark" />
<corners
android:radius="5dp" />
</shape>
</item>
</layer-list>
</item>
答案 2 :(得分:4)
您只能使用xml形状 - 只需使用图层列表和负填充:
<layer-list>
<item>
<shape>
<solid android:color="#ffffff" />
<padding android:top="20dp" />
</shape>
</item>
<item>
<shape>
<gradient android:endColor="#ffffff" android:startColor="#efefef" android:type="linear" android:angle="90" />
<padding android:top="-20dp" />
</shape>
</item>
</layer-list>
答案 3 :(得分:1)
您是否尝试使用几乎透明的不透明度覆盖一个渐变,使另一个图像上的高光突出显示绿色渐变的不透明不透明度?
答案 4 :(得分:1)
尝试这种方法然后你可以做你想做的每件事。
它就像一个堆栈,所以要小心哪个项目是第一个还是最后一个。
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="50dp" android:start="10dp" android:left="10dp">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp" />
<solid android:color="#012d08"/>
</shape>
</item>
<item android:top="50dp">
<shape android:shape="rectangle">
<solid android:color="#7c4b4b" />
</shape>
</item>
<item android:top="90dp" android:end="60dp">
<shape android:shape="rectangle">
<solid android:color="#e2cc2626" />
</shape>
</item>
<item android:start="50dp" android:bottom="20dp" android:top="120dp">
<shape android:shape="rectangle">
<solid android:color="#360e0e" />
</shape>
</item>