多梯度形状

我想创建一个如下图所示的形状:

alt text

注意上半部分从颜色1到颜色2的渐变,但是下半部分从颜色3到颜色4的渐变。我知道如何使一个形状与一个单一的渐变,但我不知道如何分裂成两个一半的形状,使一个形状与2个不同的渐变。

有什么想法吗?

119288 次浏览

你是否尝试过用一个几乎透明的不透明度来覆盖另一个图像上的高光,并用一个不透明的不透明度来覆盖绿色渐变?

我不认为您可以在 XML 中做到这一点(至少在 Android 中不行) ,但是我发现了一个很好的解决方案,它发布在 给你上,看起来会有很大的帮助!

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 _ level _ 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>

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 中,从而避免这个额外的文件,但我不确定如何做到这一点。但是,好吧,那么这种恶作剧的部分出现在 Layer _ list XML 文件中。我把绿色渐变作为底层,然后把半覆盖作为第二层,偏移从顶部的50分贝。显然,你会希望这个数字始终是你的视图大小的一半,虽然,而不是一个固定的50dp。但我觉得你不能用百分比。从那里开始,我只是在 test.xml 布局中插入了一个 TextView,使用 Layer _ list.xml 文件作为背景。我将高度设置为100dp (叠加偏移量的两倍) ,结果如下:

alt text

当当当!

再次编辑 : 我已经意识到您可以将形状嵌入到图层列表中作为项目来绘制,这意味着您不再需要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 的数字是可行的。

我撒谎了,再剪辑一次

好了,找到了如何手动更新这个图层的可绘制性来匹配容器的高度,完整的描述可以找到 给你。这段代码应该放在 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);
}
});

我受够了

您可以使用分层列表在 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>

你可以只使用 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>

尝试这个方法,然后你可以做任何你想要的事情。
它就像 ,所以要小心哪个项目是第一个或最后一个。 < br >

<?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>