【问题标题】:How to merge two Drawables dynamically in Android?如何在Android中动态合并两个Drawable?
【发布时间】:2017-12-22 11:52:05
【问题描述】:

所以我有两个不同的Drawables,我需要在运行时合并并获得一个Drawable。我希望第一个 Drawable 位于顶部,另一个位于底部。我遇到了LayerDrawable,它看起来正是我需要的,但我在尝试安排Drawables 时遇到了麻烦。

所以我有一个 ImageButton,它是 48x48 dp,这就是最终的 Drawable 所在的位置。第一个 Drawable 是加号按钮 (20x20 dp),第二个是加号按钮下方的小圆点 (4x4 dp)。

加号按钮Drawable 使用字体字形加载。我正在使用这个 xml sn-p 创建点按钮Drawable

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
       android:shape="oval">
    <solid
        android:color="@color/white_40"/>
    <size
        android:width="4dp"
        android:height="4dp"/>
</shape>

我的第一种方法是将Drawables 添加到LayerDrawable,但是当我这样做时,xml 中指定的点的宽度/高度属性将被忽略,它会延伸以覆盖加号图标。

LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] {plusIcon, dotIcon});

以上结果如下:



我尝试的第二种方法是使用setLayerInset 尝试定位两个Drawables

    LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] {plusIcon, dotIcon});
    finalDrawable.setLayerInset(0, 0, 0, 0, 0);
    finalDrawable.setLayerInset(1, dp(22), dp(44), dp(22), 0);

上面的代码 sn-p 最终将点放置在正确的位置,但它也开始影响加号按钮的位置和大小,最终看起来像这样:

但我真正想要的是在ImageButton 的中心添加加号按钮,并在其下方添加加号图标。有谁知道我哪里出了问题以及如何正确定位两个可绘制对象?

PS:我的应用支持 API 15+,所以我不能使用 LayerDrawable 的 API 中的一堆方法,例如 setLayerGravity、`setPaddingMode 等。

【问题讨论】:

    标签: android android-layout drawable android-drawable layerdrawable


    【解决方案1】:

    编辑

    此代码适用于 23 以下的 API 级别:

    ImageButton button = (ImageButton) findViewById(R.id.button);
    
    Drawable plusIcon = ContextCompat.getDrawable(this, R.drawable.plus);
    Drawable dotIcon = ContextCompat.getDrawable(this, R.drawable.oval);
    
    int horizontalInset = (plusIcon.getIntrinsicWidth() - dotIcon.getIntrinsicWidth()) / 2;
    
    LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] {plusIcon, dotIcon});
    finalDrawable.setLayerInset(0, 0, 0, 0, dotIcon.getIntrinsicHeight());
    finalDrawable.setLayerInset(1, horizontalInset, plusIcon.getIntrinsicHeight(), horizontalInset, 0);
    
    button.setImageDrawable(finalDrawable);
    

    原创

    以下代码适用于我:

    ImageButton button = (ImageButton) findViewById(R.id.button);
    
    Drawable plusIcon = ContextCompat.getDrawable(this, R.drawable.plus);
    Drawable dotIcon = ContextCompat.getDrawable(this, R.drawable.oval);
    
    LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] {plusIcon, dotIcon});
    finalDrawable.setLayerInsetBottom(0, dotIcon.getIntrinsicHeight());
    finalDrawable.setLayerGravity(1, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
    
    button.setImageDrawable(finalDrawable);
    

    这会产生以下用户界面:

    【讨论】:

    • 嗨,本,感谢您的回答。但setLayerGravity 仅适用于 API 23 及更高版本的 iirc。我的应用支持 API 15 及更高版本。
    • 嘿,非常感谢!编辑后的答案使其工作。不过只是一个小问题,我看到如果我更改底部点的大小,加号图标将不得不向上移动以为点图标腾出空间,因为它在ImageButton 中的相对位置取决于点。有什么办法可以将加号图标准确地定位在中心(Gravity.CENTER)和点图标,比如说它下面的 4 dp
    • 我认为在这一点上我们已经超出了 LayerDrawable 的真正意图。我可能会考虑创建一个包含点和加号的矢量可绘制对象,或者使用 FrameLayout/ConstraintLayout(在您的按钮顶部)来定位两个可绘制对象。
    • 是的,我不能使用布局来定位可绘制对象,因为我只能返回一个Drawable,它会应用于ImageButton。所以这正是我尝试使用LayerDrawable 来实现这一目标的原因。有什么想法吗?
    • 似乎LayerDrawable 的每一层都将被放大以适应LayerDrawable 的大小,这是其所有层中最大的大小。这个“层大小”包括插图。因此,如果您定义了一些尺寸填充,您可以在所有边上通过 (padding + 点直径) 插入加号,并在顶部和 ((2*diameter + 2*padding + plus width) - 直径) / 每边 2。
    【解决方案2】:

    这就是我解决这个问题的方法:

    final View view = findViewById(R.id.view_in_layout);
    
    Drawable bottom = ContextCompat.getDrawable(context, R.drawable.ic_bottom);
    Drawable top = ContextCompat.getDrawable(context, R.drawable.ic_top);
    
    //bottom = index 0, top = index 1
    final LayerDrawable layer = new LayerDrawable(new Drawable[]{bottom, top});
    
    view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom,
                      int oldLeft, int oldTop, int oldRight, int oldBottom) {
            //get the real height after it is calculated
            int height = view.getHeight();
            //set the height half of the available space for example purposes,
            //the drawables will have half of the available height
            int halfHeight = height / 2;
            //the bottom drawable need to start when the top drawable ends
            layer.setLayerInset(0, 0, halfHeight, 0, 0);
            //the top drawable need to end before the bottom drawable starts
            layer.setLayerInset(1, 0, 0, 0, halfHeight);
    
            view.setBackground(layer);
            view.removeOnLayoutChangeListener(this);
        }
    });
    

    您可以为您的可绘制对象选择不同的尺寸或使用索引移动它们。例如,我使用View.OnLayoutChangeListener(...) 等待视图的当前可用高度

    【讨论】:

      猜你喜欢
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-27
      • 2017-06-19
      • 1970-01-01
      相关资源
      最近更新 更多