Как полностью покрыть 9-PATCH-PNG? - PullRequest
6 голосов
/ 21 сентября 2010

Я пытаюсь реализовать эффект наведения (эффект при нажатии кнопки), помещая полупрозрачный файл PNG поверх фона кнопки и значок кнопки. К сожалению, фоновый файл кнопки представляет собой 9-PATCH-PNG, что вызывает здесь некоторые проблемы: он «проглатывает» все поверх своего слоя и не позволяет покрывать растягиваемые области (тонкую светлую линию вокруг) из 9-patch-png , Другими словами, черные линии на верхнем и левом краях PNG-файла 9 PATCH вызывают не только растяжение, но и поведение заполнения.

Удаление 9-Patch-Information не является хорошим решением.

Здесь вы можете увидеть мою кнопку. Синий фон - это 9-патч PNG. Тонкая светлая линия вокруг кнопки нежелательна.

alt text

Этот список слоев назначен атрибуту кнопки «фон»:

<?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» на каждой границе. У вас, ребята, есть предложения?

Обновление

Я попробовал следующее, что позволит избежать масштабирования , предложено с здесь Но тоже не сработало:

<!-- 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 остаются открытыми):

alt text

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

Может ли это работать на меня? Сделать наложенное изображение прозрачным на ощупь в Android?

Ответы [ 4 ]

4 голосов
/ 08 октября 2010

[NeverMind] Внутренние комментарии для LayerDrawable.getPadding утверждают, что он берет отступ от первого элемента в списке. Если этот комментарий говорит правду, вы можете получить желаемое поведение, поместив произвольное (возможно, пустое) изображение перед вашим 9 патчем в списке.

Быстрое чтение кода, однако, подразумевает, что он на самом деле использует сумму всех отступов элемента, что означает, что нет способа устранить вашу проблему , используя LayerDrawable по умолчанию . Оператор подразумевает решение: реализовать подкласс LayerDrawable, который переопределяет «getPadding» для возврата {0, 0, 0, 0}. Возможно, вам придется инициализировать свой подкласс в коде, а не загружать макет XML, но это не особенно сложно. [/ NeverMind]

Обновление: Приведенное выше решение не работает, поскольку проблема заключается не в самом заполнении, а в том, что реализация по умолчанию устанавливает 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>

Ниже приведен пример скриншота:

NinePatchCover screen shot

Обновление 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» вниз, чтобы увидеть окно в его несфокусированном состоянии.)

2 голосов
/ 18 февраля 2011

Я получил полный оверлей для работы, манипулируя девятью патчами.Вместо того, чтобы оставлять нижнюю и правую стороны (содержимое) пустыми, попробуйте заполнить их черными пикселями.

2 голосов
/ 28 сентября 2010

У меня все работает нормально:

Рез / макет / main.xml

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

Рез / рисуем / 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 с прозрачностью вокруг него.

Вот результат: alt text

Снятие прозрачной части вокруг помидора (заполнение розовым): alt text

Редактировать 2: Это сделает томатное покрытие полностью патч-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 в качестве фона и «content» в качестве кнопки. В этом случае вам нужно установить отступ в 0 для этого src

1 голос
/ 07 октября 2010

Я думаю, что есть два решения этой проблемы.

Решение 1:

Когда вы говорите «эффект наведения», вы имеете в виду, когда кнопка находитсяприжал?Если это так, то, что вы хотите сделать, используйте селектор или список состояний для фона кнопки, где выбранное состояние отличается от вашего обычного изображения:

<?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 .Это сохранит текущее поведение растяжения изображения, но удалит любые отступы, присущие изображению.Затем вы можете добавить или удалить отступы по желанию для внутренних видов, чтобы получить желаемый дисплей.

...