Reputation: 9188
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>
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
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