多渐变形状


Answers:


383

我认为您无法使用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_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>

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中,从而避免了这个额外的文件,但是我不确定如何做到。但是好吧,然后这种有问题的部分就会出现在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>

您可以按照这种方式分层放置任意多的项目!我可以尝试一下,看看是否可以通过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);
            }
        });

我完成了!ew!:)


问题在于梯度是垂直的。我需要垂直分离的形状(即:一条水平线),但我需要将渐变变为水平的(即:从左向右移动)。在此示例中,分隔符和渐变都是垂直的。
安德鲁(Andrew)2010年

哦,好的,我现在明白你的意思。(图片在工作中被遮挡,因此我只能通过手机查看您的照片,很难很好地说明细节)。不幸的是,尽管我假设您可以创建一个具有两个矩形的可绘制形状,一个矩形具有水平渐变,一个矩形具有白色至黑色的垂直渐变,大小为一半,半不透明,但我对此没有解决方案,对齐底部。至于如何做到这一点,我目前没有任何具体的例子。
凯文·科波克

是的,那是我希望能够做到的,但是我还没有弄清楚。感谢您的帮助
安德鲁2010年

别客气!我再试一次,我想我已经找到了您想要的东西。您可能必须通过Java动态地制作这些文件(根据注释),但是现在这可以解决固定大小的问题。
凯文·科波克

17
那就是您至少想给+10的答案。我喜欢您的回答中的战斗感:您与Android API谁将获胜?我们最终会知道么?;)另外,由于您保留了所有遇到的怪癖,因此它是非常有用的学习材料。
andr 2013年

28

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


4

您可以仅使用xml形状进行操作-只需使用layer-list和负填充即可,如下所示:

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

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>


0

您是否尝试过用一个几乎透明的不透明性将高光覆盖在一个渐变上,而将另一个渐变的绿色渐变不透明地覆盖在另一个图像上?


不,我没有,虽然我不太确定如何在形状中将一个渐变放置在另一个渐变上。我使用android:background =“ @ drawable / myshape”将形状用作LinearLayout的背景
Andrew

是否可以将两个具有不同不透明度的形状彼此叠加?(我不知道。)
Greg D 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.