How to fully cover 9-PATCH-PNG?

I am trying to implement a hover effect (effect when a button is pressed) by placing a translucent PNG file on top of the button background and button icon. Unfortunately, the background file of the button is a 9-PATCH-PNG, which causes some problems here: it swallows everything on top of its layer and does not allow covering the stretchable areas (thin line of light around) of nine patch-PNG, in other words, black lines top and left edges 9 PATCH PNGs cause not only stretching, but also the behavior of add-ons.

Removing 9-Patch-Information is not a good solution.

Here you can see my button. Blue Background - 9 PATCH PNG. Unwanted thin light line around the button.

alt text

This list of layers is assigned to the "background" attribute:

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

Setting layer offsets to -1 at each boundary is invalid. Do guys have any suggestions?

Update

I tried the following to avoid scaling suggested here . But it didn’t work out:

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

My version (stretch areas 9-patch-png are still available):

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> 

Update 2

Could this work for me? Overlay a transparent image on a touch screen on Android?

+6
android android-layout nine-patch layer
source share
4 answers

[NeverMind] Internal comments for LayerDrawable.getPadding claim that it is ranked first in the list. If this comment is telling the truth, you can get the right behavior by placing an arbitrary (possibly empty) image in front of your 9 patch in the list.

However, a quick code reading implies that it actually uses the sum of all paddings of elements, which means that there is no way to fix your problem using LayerDrawable by default . A statement implies a solution: implement a subclass of LayerDrawable that overrides "getPadding" to return {0, 0, 0, 0}. You may need to initialize your subclass in code rather than loading an XML layout, but this is not particularly difficult. [/ NeverMind]

Update: The above solution does not work, because the problem is not with the gasket itself, but with the fact that the default implementation sets the boundaries of each image as the sum of the gaskets of the previous images. In other words, it ensures nesting compliance, which is what most people want. The correct solution still overrides LayerDrawable, but instead you replace "onBoundsChange". Full test demo:

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

using the following layout /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> 

Below is an example screenshot:

NinePatchCover screen shot

Update 2:

As requested, how can you change it to initialize the Selector in code. Replace the initialization of "mCover1" with the following code:

 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; 

This will be displayed in green in the normal case when the window is focused, but the button is not pressed, red when the button is pressed, and by default (gray) when the window is not focused. (Try dragging the windowshade notification bar to see the window in an unallocated state.)

+4
source share

I worked fine:

Res / layout / main.xml

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

Res / draw / 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 is my ninefold png. A tomato is a basic png with transparency around it.

Here is the result: alt text

Removing the transparent part around the tomato (filling in pink): alt text

Edit 2: This will completely cover the tomato 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> 

Another way to use ImageButton is that you can use patch-9-png as the background and “content” as the src button. In this case, you need to set the fill value to 0 for this src parameter

+2
source share

I got a full waybill for work, manipulating nine patch. Instead of leaving the bottom and right sides (contents) blank, try filling them with black pixels completely.

+2
source share

I think there are two solutions to this problem.

Solution 1:

When you say “hover effect”, do you mean when the button is pressed? If so, then what you want to use, use the aka state list selector for the button background, where the selected state is different from your normal image:

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

Then set the button background to this list of available XML.

Solution 2:

Until you send your unprocessed nine PNG patches, I suspect that you can remove the right and bottom markings denoting the “fill field” by keeping the left and top markings denoting the “stretch area” as described in the 2D Graphics Doc . This will preserve the current image stretching behavior, but will remove any padding that is an integral part of the image. You can then add or remove the add-on as desired to the internal views to get the desired display.

+1
source share

All Articles