多梯度形状

And*_*rew 174 android gradient shapes

我想创建一个类似下图的形状:

替代文字

注意从颜色1到颜色2的上半部分渐变,但是从颜​​色3到颜色4渐变的下半部分.我知道如何使用单个渐变制作形状,但我不确定如何将形状分割成两半,并制作1个形状,2个不同的渐变.

有任何想法吗?

kco*_*ock 376

我不认为你可以用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);
Run Code Online (Sandbox Code Playgroud)

基本上,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!"
    />
Run Code Online (Sandbox Code Playgroud)

然后你在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);
Run Code Online (Sandbox Code Playgroud)

我现在无法测试这个,这是我脑子里的代码,但基本上只是替换,或为你需要的颜色添加停止.基本上,在我的例子中,你会从浅绿色开始,在中心之前略微淡化到白色(给出淡化,而不是苛刻的过渡),从白色到中间的白色褪色45%到55%之间,然后从中间绿色到深绿色从55%到最后.这可能看起来不像你的形状(现在,我无法测试这些颜色),但你可以修改它来复制你的例子.

编辑:此外,0, 0, 0, theButton.getHeight()指的是渐变的x0,y0,x1,y1坐标.所以基本上,它从x = 0(左侧)开始,y = 0(顶部),并且延伸到x = 0(我们想要一个垂直渐变,所以不需要从左到右的角度),y =高度的按钮.因此,渐变从按钮顶部到按钮底部成90度角.

编辑:好的,所以我还有一个有用的想法,哈哈.现在它可以在XML中工作,但也应该适用于Java中的形状.它有点复杂,我想有一种方法可以将它简化为单一形状,但这就是我现在所拥有的:

green_horizo​​ntal_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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

的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>
Run Code Online (Sandbox Code Playgroud)

好吧,基本上我已经为XML创建了一个水平绿色渐变的形状渐变,设置为0度角,从顶部区域的左侧绿色变为右侧绿色.接下来,我制作了一个半透明灰色的形状矩形.我很确定可以将其内联到图层列表XML中,避免使用这个额外的文件,但我不确定如何.但是没关系,那么hacky部分会出现在layer_list XML文件中.我将绿色渐变作为底层,然后将半覆盖层作为第二层,从顶部偏移50dp.显然,你希望这个数字总是你视图大小的一半,而不是固定的50dp.不过,我认为你不能使用百分比.从那里,我只是使用layer_list.xml文件作为我的背景,将TextView插入到我的test.xml布局中.

替代文字

田田!

还有一个编辑:我已经意识到你可以将形状嵌入到可以绘制为项目的图层列表中,这意味着你不再需要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>
Run Code Online (Sandbox Code Playgroud)

您可以通过这种方式将任意多个项目分层!我可以尝试一下,看看我是否可以通过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);
Run Code Online (Sandbox Code Playgroud)

然而!这导致另一个令人讨厌的问题,因为在绘制之前你无法测量TextView.我还不太确定你怎么做到这一点......但手动为topInset插入一个数字确实有效.

我骗了,还有一个编辑

好的,找到了如何手动更新此图层drawable以匹配容器的高度,可在此处找到完整描述.这段代码应该放在你的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);
            }
        });
Run Code Online (Sandbox Code Playgroud)

而且我已经完成了!呼!:)

  • 这是你想要给予+10至少的答案.我喜欢你的答案中的战斗感:你和Android API,谁会赢?我们最终会知道么?;)另外,它是非常有用的学习材料,因为你保留了你遇到的所有怪癖. (16认同)

Lor*_*ley 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>
Run Code Online (Sandbox Code Playgroud)