Abhishek Singh
Abhishek Singh

Reputation: 9188

Create a button with Image above Text not with drawableTop()

I want to create a custom button with text and image like the below image. I don't want to use drawableTop because I cannot set the size of image. Also I don't want to use a layout with Imageview and TextView.

After lots of trying and searching i created a util file which do the same but the problem is the its showing the image at left. By this file I'm able to control the size of images. So my question is what should I have to change in my code so that image will shift to top.

My Code Is

<com.kliff.digitaldwarka.utils.IconButton
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     app:iconSrc="@drawable/services_video"
     app:iconSize="50dp"
     app:iconPadding="1dp"
     android:text="hello"
     android:background="@null" />

IconButton.java

public class IconButton extends AppCompatButton {
    private Bitmap mIcon;
    private Paint mPaint;
    private Rect mSrcRect;
    private int mIconPadding;
    private int mIconSize;

    public IconButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public IconButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public IconButton(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int shift = (mIconSize + mIconPadding) / 2;

        canvas.save();
        canvas.translate(shift, 0);

        super.onDraw(canvas);

        if (mIcon != null) {
            float textWidth = getPaint().measureText((String)getText());
            int left = (int)((getWidth() / 2f) - (textWidth / 2f) - mIconSize - mIconPadding);
            int top = getHeight()/2 - mIconSize/2;

            Rect destRect = new Rect(left, top, left + mIconSize, top + mIconSize);
            canvas.drawBitmap(mIcon, mSrcRect, destRect, mPaint);
        }

        canvas.restore();
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.IconButton);

        for (int i = 0; i < array.getIndexCount(); ++i) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.IconButton_iconSrc:
                    mIcon = drawableToBitmap(array.getDrawable(attr));
                    break;
                case R.styleable.IconButton_iconPadding:
                    mIconPadding = array.getDimensionPixelSize(attr, 0);
                    break;
                case R.styleable.IconButton_iconSize:
                    mIconSize = array.getDimensionPixelSize(attr, 0);
                    break;
                default:
                    break;
            }
        }

        array.recycle();

        //If we didn't supply an icon in the XML
        if(mIcon != null){
            mPaint = new Paint();
            mSrcRect = new Rect(0, 0, mIcon.getWidth(), mIcon.getHeight());
        }
    }
    public void setmIcon(Context mContext,int drawableRes){
        Drawable drawable= ContextCompat.getDrawable(mContext,drawableRes);
        mIcon = drawableToBitmap(drawable);
        if(mIcon != null){
            mPaint = new Paint();
            mSrcRect = new Rect(0, 0, mIcon.getWidth(), mIcon.getHeight());
        }
    }

    public static Bitmap drawableToBitmap (Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable)drawable).getBitmap();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }
}

attrs.xml

<declare-styleable name="IconButton">
    <attr name="iconSrc" format="reference" />
    <attr name="iconSize" format="dimension" />
    <attr name="iconPadding" format="dimension" />
</declare-styleable>

 

Output

Expected

Note: Also If this code can be manipulate to set the image at any side with adding one more attribute. Any help would be appriciated

Upvotes: 1

Views: 121

Answers (1)

motis10
motis10

Reputation: 2596

I would use FrameLayout, but if you have no choices, take a look in the code below: I changed the onDraw() + i changed a bit the Paint object of the text and add a Paint object for the icon.

public class IconButton extends AppCompatButton {
    private Bitmap mIcon;
    private Paint mPaint;
    private Paint mIconPaint;
    private int mIconPadding;

    public IconButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public IconButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public IconButton(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mIcon != null) {
            float xPos = (canvas.getWidth() - mIconPadding - mIcon.getScaledWidth(canvas)) / 2;
            canvas.drawBitmap(mIcon, xPos, mIconPadding, mIconPaint);
        }

        final CharSequence text = "Movie tickets";
        float textWidth = getTextWidth(mPaint, text.toString());
        float xPos = ((canvas.getWidth() - textWidth) / 2);
        canvas.drawText(text, 0, text.length(), xPos, mIcon.getScaledWidth(canvas) + (mIconPadding * 2), mPaint);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.IconButton);

        for (int i = 0; i < array.getIndexCount(); ++i) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.IconButton_iconSrc:
                    mIcon = drawableToBitmap(array.getDrawable(attr));
                    break;
                case R.styleable.IconButton_iconPadding:
                    mIconPadding = array.getDimensionPixelSize(attr, 0);
                    break;
                case R.styleable.IconButton_iconSize:
                    mIconSize = array.getDimensionPixelSize(attr, 0);
                    break;
                default:
                    break;
            }
        }

        array.recycle();

        //If we didn't supply an icon in the XML
        if (mIcon != null) {
            mPaint = new Paint();
            mSrcRect = new Rect(0, 0, mIcon.getWidth(), mIcon.getHeight());
        }

        mIconPaint = new Paint(TextPaint.ANTI_ALIAS_FLAG);
        mIconPaint.setStyle(Paint.Style.FILL);
    }

    /**
     * @param paint the paint you are going to paint the text with
     * @param str   String to check its width
     * @return the width of string in PX
     */
    public static float getTextWidth(Paint paint, String str) {
        return paint.measureText(str);
    }
}

Edited: I added the function getTextWidth to the code

Upvotes: 1

Related Questions