我怎样才能缩小按钮上的可画性?

我怎样才能使按钮的可绘制性变小?图标太大了,实际上比按钮高。这是我正在使用的代码:

    <Button
android:background="@drawable/red_button"
android:drawableLeft="@drawable/s_vit"
android:id="@+id/ButtonTest"
android:gravity="left|center_vertical"
android:text="S-SERIES CALCULATOR"
android:textColor="@android:color/white"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:drawablePadding="10dp">
</Button>

上面是它应该看起来的样子,下面是它现在看起来的样子。

The upper is how it should look, the lower how it looks right now.

我试过了,但是没有图像显示

    Resources res = getResources();
ScaleDrawable sd = new ScaleDrawable(res.getDrawable(R.drawable.s_vit), 0, 10f, 10f);
Button btn = (Button) findViewById(R.id.ButtonTest);
btn.setCompoundDrawables(sd.getDrawable(), null, null, null);
110884 次浏览

You can use different sized drawables that are used with different screen densities/sizes, etc. so that your image looks right on all devices.

See here: http://developer.android.com/guide/practices/screens_support.html#support

You should use a ImageButton and specify the image in android:src, and set android:scaletype to fitXY


Setting scaled drawable in code

Drawable drawable = getResources().getDrawable(R.drawable.s_vit);
drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*0.5),
(int)(drawable.getIntrinsicHeight()*0.5));
ScaleDrawable sd = new ScaleDrawable(drawable, 0, scaleWidth, scaleHeight);
Button btn = findViewbyId(R.id.yourbtnID);
btn.setCompoundDrawables(sd.getDrawable(), null, null, null); //set drawableLeft for example

If you want to use 1 image and display it in different size, you can use scale drawable ( http://developer.android.com/guide/topics/resources/drawable-resource.html#Scale ).

Did you try wrapping your image in a ScaleDrawable and then using it in your button?

Buttons do not resize their inner images.

My solution does not require code manipulation.

It uses a layout with TextView and ImageView.

The background of the layout should have the red 3d drawable.

You may need to define the android:scaleType xml attribute.

Example:

<LinearLayout
android:id="@+id/list_item"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:padding="2dp" >


<ImageView
android:layout_width="50dp"
android:layout_height="fill_parent"
android:src="@drawable/camera" />


<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:lines="1"
android:gravity="center_vertical"
android:text="Hello - primary" />


</LinearLayout>

BTW:

  1. Counting on different resolution icons may result in a non predictable UI (icon too big or too small)
  2. Text in textview (including in buttons) does not fill the component. This is an Android problem and I don't know how to solve it.
  3. You can use it as an include.

Good luck

Use a ScaleDrawable as Abhinav suggested.

The problem is that the drawable doesn't show then - it's some sort of bug in ScaleDrawables. you'll need to change the "level" programmatically. This should work for every button:

// Fix level of existing drawables
Drawable[] drawables = myButton.getCompoundDrawables();
for (Drawable d : drawables) if (d != null && d instanceof ScaleDrawable) d.setLevel(1);
myButton.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);

I tried the techniques of this post but didnot find any of them so attractive. My solution was to use an imageview and textview and align the imageview top and bottom to the textview. This way I got the desired result. Here's some code:

<RelativeLayout
android:id="@+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="48dp" >




<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignTop="@+id/textViewTitle"
android:layout_alignBottom="@+id/textViewTitle"
android:src="@drawable/ic_back" />


<TextView
android:id="@+id/textViewBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/textViewTitle"
android:layout_alignBottom="@+id/textViewTitle"
android:layout_toRightOf="@+id/imageView1"
android:text="Back"
android:textColor="@color/app_red"
android:textSize="@dimen/title_size" />
</RelativeLayout>

I have found a very simple and effective XML solution that doesn't require ImageButton

Make a drawable file for your image as below and use it for android:drawableLeft

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">


<item
android:id="@+id/half_overlay"
android:drawable="@drawable/myDrawable"
android:width="40dp"
android:height="40dp"
/>


</layer-list>

You can set the image size with android:width and android:height properties.

This way you could at least get the same size for different screens.

The drawback is that it is not exactly like fitXY which would scale image width to fit X and scale image height accordingly.

You can call setBounds on the "compound" drawables to modify the size of the image.

Try this code to autosize the drawable of your button:

DroidUtils.scaleButtonDrawables((Button) findViewById(R.id.ButtonTest), 1.0);

defined by this function:

public final class DroidUtils {


/** scale the Drawables of a button to "fit"
*  For left and right drawables: height is scaled
*  eg. with fitFactor 1 the image has max. the height of the button.
*  For top and bottom drawables: width is scaled:
*  With fitFactor 0.9 the image has max. 90% of the width of the button
*  */
public static void scaleButtonDrawables(Button btn, double fitFactor) {
Drawable[] drawables = btn.getCompoundDrawables();


for (int i = 0; i < drawables.length; i++) {
if (drawables[i] != null) {
int imgWidth = drawables[i].getIntrinsicWidth();
int imgHeight = drawables[i].getIntrinsicHeight();
if ((imgHeight > 0) && (imgWidth > 0)) {    //might be -1
float scale;
if ((i == 0) || (i == 2)) { //left or right -> scale height
scale = (float) (btn.getHeight() * fitFactor) / imgHeight;
} else { //top or bottom -> scale width
scale = (float) (btn.getWidth() * fitFactor) / imgWidth;
}
if (scale < 1.0) {
Rect rect = drawables[i].getBounds();
int newWidth = (int)(imgWidth * scale);
int newHeight = (int)(imgHeight * scale);
rect.left = rect.left + (int)(0.5 * (imgWidth - newWidth));
rect.top = rect.top + (int)(0.5 * (imgHeight - newHeight));
rect.right = rect.left + newWidth;
rect.bottom = rect.top + newHeight;
drawables[i].setBounds(rect);
}
}
}
}
}
}

Be aware, that this may not be called in onCreate() of an activity, because button height and width are not (yet) available there. Call this in on onWindowFocusChanged() or use this solution to call the function.

Edited:

The first incarnation of this function did not work correctly. It used userSeven7s code to scale the image, but returning ScaleDrawable.getDrawable() does not seem to work (neither does returning ScaleDrawable) for me.

The modified code uses setBounds to provide the bounds for the image. Android fits the image into these bounds.

My DiplayScaleHelper, that works perfectly:

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ScaleDrawable;
import android.widget.Button;


public class DisplayHelper {


public static void scaleButtonDrawables(Button btn, double fitFactor) {
Drawable[] drawables = btn.getCompoundDrawables();


for (int i = 0; i < drawables.length; i++) {
if (drawables[i] != null) {
if (drawables[i] instanceof ScaleDrawable) {
drawables[i].setLevel(1);
}
drawables[i].setBounds(0, 0, (int) (drawables[i].getIntrinsicWidth() * fitFactor),
(int) (drawables[i].getIntrinsicHeight() * fitFactor));
ScaleDrawable sd = new ScaleDrawable(drawables[i], 0, drawables[i].getIntrinsicWidth(), drawables[i].getIntrinsicHeight());
if(i == 0) {
btn.setCompoundDrawables(sd.getDrawable(), drawables[1], drawables[2], drawables[3]);
} else if(i == 1) {
btn.setCompoundDrawables(drawables[0], sd.getDrawable(), drawables[2], drawables[3]);
} else if(i == 2) {
btn.setCompoundDrawables(drawables[0], drawables[1], sd.getDrawable(), drawables[3]);
} else {
btn.setCompoundDrawables(drawables[0], drawables[1], drawables[2], sd.getDrawable());
}
}
}
}
}

Here the function which I created for scaling vector drawables. I used it for setting TextView compound drawable.

/**
* Used to load vector drawable and set it's size to intrinsic values
*
* @param context Reference to {@link Context}
* @param resId   Vector image resource id
* @param tint    If not 0 - colour resource to tint the drawable with.
* @param newWidth If not 0 then set the drawable's width to this value and scale
*                 height accordingly.
* @return On success a reference to a vector drawable
*/
@Nullable
public static Drawable getVectorDrawable(@NonNull Context context,
@DrawableRes int resId,
@ColorRes int tint,
float newWidth)
{
VectorDrawableCompat drawableCompat =
VectorDrawableCompat.create(context.getResources(), resId, context.getTheme());
if (drawableCompat != null)
{
if (tint != 0)
{
drawableCompat.setTint(ResourcesCompat.getColor(context.getResources(), tint, context.getTheme()));
}


drawableCompat.setBounds(0, 0, drawableCompat.getIntrinsicWidth(), drawableCompat.getIntrinsicHeight());


if (newWidth != 0.0)
{
float scale = newWidth / drawableCompat.getIntrinsicWidth();
float height = scale * drawableCompat.getIntrinsicHeight();
ScaleDrawable scaledDrawable = new ScaleDrawable(drawableCompat, Gravity.CENTER, 1.0f, 1.0f);
scaledDrawable.setBounds(0,0, (int) newWidth, (int) height);
scaledDrawable.setLevel(10000);
return scaledDrawable;
}
}
return drawableCompat;
}
  • Using "BATCH DRAWABLE IMPORT" feature you can import custom size depending upon your requirement example 20dp*20dp

    • Now after importing use the imported drawable_image as drawable_source for your button

    • It's simpler this way enter image description here

It is because you did not setLevel. after you setLevel(1), it will be display as u want

I made a custom button class to achieve this.

CustomButton.java

public class CustomButton extends android.support.v7.widget.AppCompatButton {


private Drawable mDrawable;


public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);


TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CustomButton,
0, 0);


try {
float mWidth = a.getDimension(R.styleable.CustomButton_drawable_width, 0);
float mHeight = a.getDimension(R.styleable.CustomButton_drawable_width, 0);


Drawable[] drawables = this.getCompoundDrawables();
Drawable[] resizedDrawable = new Drawable[4];


for (int i = 0; i < drawables.length; i++) {
if (drawables[i] != null) {
mDrawable = drawables[i];
}
resizedDrawable[i] = getResizedDrawable(drawables[i], mWidth, mHeight);
}


this.setCompoundDrawables(resizedDrawable[0], resizedDrawable[1], resizedDrawable[2], resizedDrawable[3]);
} finally {
a.recycle();
}
}


public Drawable getmDrawable() {
return mDrawable;
}


private Drawable getResizedDrawable(Drawable drawable, float mWidth, float mHeight) {
if (drawable == null) {
return null;
}


try {
Bitmap bitmap;


bitmap = Bitmap.createBitmap((int)mWidth, (int)mHeight, Bitmap.Config.ARGB_8888);


Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return drawable;
} catch (OutOfMemoryError e) {
// Handle the error
return null;
}
}
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomButton">
<attr name="drawable_width" format="dimension" />
<attr name="drawable_height" format="dimension" />
</declare-styleable>
</resources>

Usage in xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.MainActivity">


<com.example.CustomButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_hero"
android:text="Avenger"
custom:drawable_height="10dp"
custom:drawable_width="10dp" />


</RelativeLayout>

I am doing it as below. This creates a 100x100 size image in the button independent of the input image.

drawable.bounds = Rect(0,0,100,100)
button.setCompoundDrawables(drawable, null, null, null)

Not using ScaleDrawable either. Not using button.setCompoundDrawablesRelativeWithIntrinsicBounds() solved my problem, as that seems to use intrinsic bounds (source image size) instead of the bounds you just set.

Using Kotlin Extension

val drawable = ContextCompat.getDrawable(context, R.drawable.my_icon)
// or resources.getDrawable(R.drawable.my_icon, theme)
val sizePx = 25
drawable?.setBounds(0, 0, sizePx, sizePx)
//                            (left,     top,  right, bottom)
my_button.setCompoundDrawables(drawable, null, null, null)

I suggest creating an extension function on TextView (Button extends it) for easy reuse.

button.leftDrawable(R.drawable.my_icon, 25)


// Button extends TextView
fun TextView.leftDrawable(@DrawableRes id: Int = 0, @DimenRes sizeRes: Int) {
val drawable = ContextCompat.getDrawable(context, id)
val size = context.resources.getDimensionPixelSize(sizeRes)
drawable?.setBounds(0, 0, size, size)
this.setCompoundDrawables(drawable, null, null, null)
}