【问题标题】:How to cover a 9-PATCH-PNG entirely?如何完全覆盖 9-PATCH-PNG?
【发布时间】:2010-09-21 16:18:18
【问题描述】:

我尝试通过在按钮背景和按钮图标顶部放置一个半透明的 PNG 文件来实现悬停效果(按下按钮时的效果)。不幸的是,按钮背景文件是一个 9-PATCH-PNG,这在这里造成了一些麻烦:它“吞噬”了其图层顶部的所有内容,并且不允许覆盖 9-patch-png 的可拉伸区域(周围的细光线) . 换句话说,9 PATCH PNG 的顶部和左侧边缘的黑线不仅会导致拉伸,还会导致填充行为。

删除 9-Patch-Information 不是一个好的解决方案。

在这里你可以看到我的按钮。蓝色背景是 9 PATCH PNG。按钮周围的细线是不需要的。

这个图层列表被分配给按钮属性“背景”:

<?xml version="1.0" encoding="utf-8"?>
<layer-list
  xmlns:android="http://schemas.android.com/apk/res/android">
  <item
    android:drawable="@drawable/home_btn_bg_blue_without_padding" />
  <item>
    <bitmap
      android:src="@drawable/home_icon_test"
      android:gravity="center" />
  </item>
  <item
    android:drawable="@drawable/layer_black_50" />
</layer-list>

在每个边框上将图层的偏移量设置为“-1”是无效的。你们有什么建议吗?

更新

我尝试了以下操作,这应该避免缩放,来自here 的建议。但也没有用:

<!-- To avoid scaling, the following example uses a <bitmap> element with centered gravity: -->
<item>
  <bitmap android:src="@drawable/image"
          android:gravity="center" />
</item>

我的版本(9-patch-png 的可拉伸区域仍然未覆盖):

<?xml version="1.0" encoding="utf-8"?>
<layer-list
  xmlns:android="http://schemas.android.com/apk/res/android">
  <item
    android:drawable="@drawable/home_btn_bg_blue_hover_without_padding" />
  <item>
    <bitmap
      android:src="@drawable/home_icon_test"
      android:gravity="center" />
  </item>
  <item>
    <bitmap android:src="@drawable/layer_black_100"
          android:height="100dp"
          android:width="100dp"/></item>
</layer-list>

更新 2

这对我有用吗? Making Overlaid image transparent on touch in Android?

【问题讨论】:

  • 让我做对了。第一张图就是想要的效果吧?
  • @Octavian:不,把“@drawable/layer_black...”放在最上面是想要的效果
  • 您在顶部添加的关于“更新 2”的文本在问题列表中显示为问题的预览,从而不太可能有人大致了解您的内容'在他们浏览 Android 问题列表时询问,我猜他们不太可能想要点击并回答。
  • 谢谢!删除它...
  • 另一种方法:操纵drawable。 developer.android.com/resources/articles/… 也在这个视频的某个地方讨论过(总是值得一看)youtube.com/…

标签: android android-layout layer nine-patch


【解决方案1】:

[没关系] LayerDrawable.getPadding 的内部 cmets 声称它从列表中的第一个可绘制对象中获取填充。如果此评论说的是实话,您可以通过在列表中的 9 补丁之前放置任意(可能是空的)图像来获得所需的行为。

然而,快速阅读代码意味着它实际上使用了所有项目的填充的sum,这意味着没有办法解决你的问题使用默认的LayerDrawable。该语句暗示了解决方案:实现 LayerDrawable 的子类,它覆盖“getPadding”以返回 {0,0,0,0}。您可能必须在代码中初始化您的子类,而不是通过加载 XML 布局,但这并不是特别困难。 [/没关系]

更新: 上面的解决方案不起作用,因为问题不在于填充本身,而是默认实现将每个图像的 bounds 设置为前面图像的填充之和。换句话说,它强制嵌套,这是大多数人想要的。正确的解决方案仍然是覆盖 LayerDrawable,但您改为替换“onBoundsChange”。一个完整的、经过测试的演示如下:

package com.beekeeper.ninepatchcover;

import android.app.Activity;
import android.graphics.*;
import android.graphics.drawable.*;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.ImageButton;

public class NinePatchCover extends Activity {
  private Drawable mCover0;
  private Drawable mCover1;

  /** Called when the activity is first created. */
  @Override public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final Drawable button =
      getResources().getDrawable(android.R.drawable.btn_default);
    final Bitmap iconBitmap =
      BitmapFactory.decodeResource(getResources(),
                                   android.R.drawable.ic_menu_mylocation);
    final BitmapDrawable icon = new BitmapDrawable(iconBitmap);
    icon.setGravity(Gravity.CENTER);
    mCover0 =
      getResources().getDrawable(android.R.drawable.title_bar);
    mCover1 =
      getResources().getDrawable(android.R.drawable.title_bar);

    final LayerDrawable unsolved =
      new LayerDrawable(new Drawable[]{button, icon, mCover0});
    final LayerDrawable solved =
      new MyLayerDrawable(new Drawable[]{button, icon, mCover1,}, mCover1);

    ((ImageButton)findViewById(R.id.uncovered)).setBackgroundDrawable(unsolved);
    ((ImageButton)findViewById(R.id.covered)).setBackgroundDrawable(solved);
  }

  class MyLayerDrawable extends LayerDrawable {
    Drawable mCover;

    public MyLayerDrawable(final Drawable[] layers, final Drawable cover) {
      super(layers);
      mCover = cover;
    }

    @Override protected void onBoundsChange(final Rect bounds) {
      super.onBoundsChange(bounds);
      mCover.setBounds(bounds);
    }
  }
}

使用以下布局/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="fill_parent"
 android:layout_height="fill_parent"
>
 <ImageButton android:id="@+id/uncovered"
  android:layout_width="fill_parent" android:layout_height="wrap_content" />
 <ImageButton android:id="@+id/covered"
  android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>

示例截图如下:

更新 2:

根据要求,您可以在下面修改它以在代码中初始化选择器。将“mCover1”的初始化替换为以下代码:

final StateListDrawable sld = new StateListDrawable();
sld.addState(new int[]{android.R.attr.state_pressed},
                 new ColorDrawable(0xffff0000));
sld.addState(new int[]{android.R.attr.state_window_focused},
                 new ColorDrawable(0xff00ff00));
sld.addState(new int[]{},
                 getResources().getDrawable(android.R.drawable.title_bar));
mCover1 = sld;

这将在窗口聚焦但未按下按钮的正常情况下显示为绿色,当按下按钮时显示为红色,当窗口未聚焦时显示默认可绘制对象(灰色)。 (尝试向下拖动“windowshade”通知栏以查看处于未聚焦状态的窗口。)

【讨论】:

  • 哦,好吧,听起来很有趣。你能提供一个例子的代码吗? (价值 100 分)
  • 完成。尝试、失败、改进和测试。
  • 那么,你现在提供的代码是为了工作吗?我明天去试试。
  • 是的。这是我运行以生成上面的屏幕截图的完整应用程序(减去我忘记粘贴的清单 - 如果需要我可以包含它,但这只是显而易见的)。它当然似乎满足您的要求。希望你会同意。
  • 恭喜!有你的 100 分 ;) 你绝对值得他们! ;) 嘿,我在代码中构建选择器时遇到了一些麻烦。我会走这条路,但它不起作用: ((ImageButton)findViewById(R.id.covered)).setBackgroundDrawable(new Selector( ... ) ) ;你能再帮我一次吗?
【解决方案2】:

我让它工作得很好:

res/layout/main.xml

...
<ImageButton
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:src="@drawable/button"
    />
...

res/drawable/button.xml

<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/frame" /> 
    <item>
        <bitmap
            android:src="@drawable/tomato"
            android:gravity="center"
            />
    </item>
</layer-list>

frame.9.png 是我的九个补丁-png。番茄是一个基本的 png,周围有透明度。

结果如下:

去除番茄周围的透明部分(用粉红色填充):

编辑 2: 这将使番茄完全覆盖 patch-9-png :

<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
    <bitmap
        android:src="@drawable/frame"
        />
    </item>
    <item>
    <bitmap
        android:src="@drawable/tomato"
        />
    </item>
</layer-list>

使用 ImageButton 的另一种方法是,您可以使用 patch-9-png 作为背景,使用“内容”作为按钮的 src。在这种情况下,您需要将该 src 的 padding 设置为 0

【讨论】:

  • 您的番茄图像是否完全覆盖了九个补丁?可以用不透明的图片吗?
  • 它在九块之上……九块是它周围的黑色矩形。我没有缩放/移动番茄,它只是放在上面..
  • 好的。我想知道如何覆盖这九个补丁,所以黑色矩形不再可见。
  • 所以??那是你想要的吗?
  • 嗨,Matthieu,您的 Edit 2 第一眼就可以使用。这也是我的尝试之一。然而,这只有效,因为这会禁用所有 9 补丁功能,如智能拉伸边界。因此,该解决方案等于“删除 9-Patch-Information 不是一个好的解决方案”;(
【解决方案3】:

通过操纵九个补丁,我得到了一个完整的覆盖。不要将底部和右侧(内容)留空,而是尝试用黑色像素完全填充它们。

【讨论】:

    【解决方案4】:

    我认为这个问题有两种解决方案。

    解决方案 1:

    当您说“悬停效果”时,您是指按下按钮时吗?如果是这种情况,那么您想要使用 selector a.k.a. state list 作为按钮背景,其中所选状态与您的正常图像不同:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true"
              android:drawable="@android:color/black" /> <!-- pressed -->
        <item android:drawable="@drawable/home_btn_bg_blue_hover_without_padding" /> <!-- default -->
    </selector>
    

    然后将按钮背景设置为该状态列表可绘制 XML。

    解决方案 2:

    虽然您尚未发布原始的九个补丁 PNG,但我怀疑您可以删除表示“填充框”的右侧和底部标记,同时保留表示“可拉伸区域”的左侧和顶部标记,如记录在2D Graphics Doc。这将保留图像的当前拉伸行为,但会删除图像固有的任何填充。然后,您可以根据需要向内部视图添加或删除填充以获得所需的显示。

    【讨论】:

    • @Solution1:事实并非如此。我已经将选择器与图层列表结合使用,类似于状态列表。 @Solution2:好的,我没有提供原始的 9 PATCH PNG,但我可以很容易地描述边缘:左侧:第一个和最后一个像素为空,其余有黑线。 UPPER SIDE:第一个和最后一个像素为空,其余为黑线。右侧和底部:全部为空。左侧和上侧也导致填充行为,这就是所有问题的全部问题!我无法关闭填充行为并同时保持拉伸行为!
    猜你喜欢
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 2019-04-20
    • 2021-11-04
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2017-06-02
    相关资源
    最近更新 更多