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

alt text

请注意上半部分从 colored颜色 1渐变到 colored颜色 2,但下半部分从 colored颜色 3渐变到 colored颜色 4.我知道如何用一个渐变来做一个形状,但我不知道如何把一个形状分成两半,用两个不同的渐变来做一个形状.

有什么 idea 吗?

推荐答案

我不认为您可以用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数组允许您 Select 多个 colored颜色 停止点,下面的float数组定义这些停止点的位置(从0到1).如前所述,您可以将其用作标准绘图工具.

编辑:下面是如何在您的场景中使用它.假设您有一个用XML定义的按钮,如下所示:

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

我现在无法测试这个,这是我头脑中的代码,但基本上只是替换,或者为你需要的 colored颜色 添加停止.基本上,在我的例子中,你将从浅绿色开始,在中心之前稍微淡入白色(以进行淡入,而不是剧烈的过渡),从白色淡入中绿色45%到55%,然后从中绿色淡入深绿色55%到最后.这可能与您的形状不完全相同(目前,我无法测试这些 colored颜色 ),但您可以修改它以复制您的示例.

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

编辑:好吧,我还有一个 idea 很管用,哈哈.目前,它可以在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中,从而省go 这个额外的文件,但我不确定如何实现.但是好的,那么LAYER_LIST XML文件中出现了一些棘手的部分.我把绿色渐变作为底层,然后把一半覆盖作为第二层,从顶部偏移50dp.显然,您希望这个数字始终是视图大小的一半,而不是固定的50dp.不过,我认为你不能用百分比.在那里,我使用layer_list.xml文件作为背景,将一个TextView插入到test.xml布局中.我将高度设置为100dp(是覆盖偏移大小的两倍),结果如下:

alt text

塔达!

One more edit:我已经意识到,你可以将形状嵌入到图层列表中,作为项目绘制,这意味着你不再需要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获得更通用的结果.

I think this is the last edit...:好的,那么你肯定可以通过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插入一个数字是可行的.

I lied, one more edit

好的,了解如何手动更新此层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);
            }
        });

我完了!唷!:)

Android相关问答推荐

在Android Studio Iguana上运行示例代码时,Gradle Build错误

ENV变量在gradle进程中没有更新

如何禁用Android 34+版的TileService,但保留以前的版本?

在Android上使用XSLT文件转换XML文件

默认调度程序是否在协程中使用共享线程池?

Lateinit变量结果始终以kotlin格式未初始化

如何在Android中将以前的数据保存在复选框中?

是否可以附加事件处理程序,如onClick,拖动到Canvas Composable中绘制的内容,或使用drawBehind修饰符?

看不到选项菜单栏

从包含的(复合)模块导入 Kotlin 类时,Android 应用程序模块的 build.gradle.kts 未解决的引用错误

retrofit2.HttpException: HTTP 401

减少Compose中可滚动选项卡之间的间距

错误:无法安装应用程序:INSTALL_PARSE_FAILED_MANIFEST_MALFORMED (React-Native-Android-Studio)

如何仅使用您的 Android 应用程序定位平板电脑?

在 Jetpack Compose 中使用 .observeAsState() 时,如何在更改 MutableLiveData 的值后开始执行一段代码?

在 Jetpack Compose 中使用 .observeAsState() 时,如何在更改 MutableLiveData 的值后开始执行一段代码?

JetPack Compose - 卡片行中的权重()不起作用

如何为具有不同屏幕尺寸但相同密度的手机创建响应式布局?

在 Android Studio 中替换字符串中的 "

WearOS - 有没有办法从心电图传感器收集原始数据?