How to get a Bitmap from a drawable defined in a xml? - android

How can I get the bitmap from a xml shape drawable.
What am I doing wrong?
shadow.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:angle="270.0"
android:endColor="#android:color/transparent"
android:startColor="#33000000"
android:type="linear" />
<size android:height="7.0dip" />
</shape>
My method to retrieve the bitmap from drawable:
private Bitmap getBitmap(int id) {
return BitmapFactory.decodeResource(getContext().getResources(), id);
}
getBitmap() is returning null when the id passed in is the shadow.xml drawable id.

This is a fully working solution:
private Bitmap getBitmap(int drawableRes) {
Drawable drawable = getResources().getDrawable(drawableRes);
Canvas canvas = new Canvas();
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
And here is an example:
Bitmap drawableBitmap = getBitmap(R.drawable.circle_shape);
circle_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:width="15dp"
android:height="15dp" />
<solid
android:color="#94f5b6" />
<stroke
android:width="2dp"
android:color="#487b5a"/>
</shape>

a ShapeDrawable doesn't have a bitmap associated with it - its sole purpose is to be drawn on a canvas. Until its draw method is called, it has no image. If you can get a canvas element at the place where you need to draw the shadow, you can draw it as a shapeDrawable, otherwise you might need a separate, empty view in your layout with the shadow as a background.

You should add size attribute to your shape drawable for preventing "java.lang.IllegalArgumentException: width and height must be > 0".
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#color/colorAccent" />
<stroke
android:width="1.3dp"
android:color="#color/white" />
<size android:height="24dp" android:width="24dp"/>
</shape>

Related

how to add layer list on an user uploaded image?

i want to add effects from my layer-list on an user upload image.In this code i can only do effect on an image from drawable i want to change that to an user upload image
this is my xml file for effect
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/colorPrimary"/>
<item>
<bitmap android:src="#drawable/icn" android:gravity="center" android:alpha="0.1"/>
</item>
<item android:top="300dp"
android:left="0dp"
>
<rotate
android:fromDegrees="-12">
<shape
android:shape="rectangle">
<solid
android:color="?android:colorBackground"/>
</shape>
</rotate>
</item>
this is my xml file for displaying the final image
<ImageView
android:id="#+id/bgImage"
android:layout_width="match_parent"
android:gravity="center"
android:background="#drawable/background"
android:layout_height="290dp"/>
You can construct a LayerDrawable by code instead of xml.
Just new a LayerDrawable and call its addLayer method to add Drawables, and all the properties you set from xml can also be set in code, such as setLayerInset methods.
For example, define the drawable:
<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="-12">
<shape
android:shape="rectangle">
<solid
android:color="?android:colorBackground"/>
</shape>
</rotate>
Get the drawable from code:
Drawable myDrawable;
Resources res = getResources();
try {
myDrawable = Drawable.createFromXml(res, res.getXml(R.xml.my_drawable));
} catch (Exception ex) {
Log.e("Error", "Exception loading drawable");
}
Create LayerDrawable and addLayer into it:
LayerDrawable layerDrawable = new LayerDrawable();
layerDrawable.addLayer(userDrawable); // userDrawable is from the user upload image
layerDrawable.addLayer(myDrawable);
You can do it by combine bitmaps of user photo and layer-list drawable.
Here is example:
Bitmap effects = BitmapFactory.decodeResource(context.getResources(), R.drawable.effect_name);
Bitmap[] parts = new Bitmap[2];
parts[0] = userImage; //Bitmap
parts[1] = effects; //Bitmap
Bitmap result = Bitmap.createBitmap(parts[0].getWidth() * 2, parts[0].getHeight() * 2, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
for (int i = 0; i < parts.length; i++) {
canvas.drawBitmap(parts[i], parts[i].getWidth() * (i % 2), parts[i].getHeight() * (i / 2), paint);
}
first of all Create a layer list like this
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/background" />
<item
<shape>
<solid/>
<stroke android:width="1dip" android:color="#225786" />
<corners android:radius="10dip"/>
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>
</item>
</layer-list>
just want a background:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/background"
android:tileMode="repeat" >
</bitmap>
And finally add background on ImageView
<ImageView
android:id="#+id/bgImage"
android:layout_width="match_parent"
android:gravity="center"
android:background="#drawable/background"
android:layout_height="290dp"/>

Convert layer-list to bitmap not working probably

I try to convert layer-list to bitmap, then set this bitmap as a background for an ImageView but it not working
This is a test project. I know I can set drawable directly to ImageView, but I want to know why when I convert LayerDrawable to Bitmap then convert Bitmap to BitmapDrawable then set it as background of ImageView, it will look different
Here is my layer-list (ic_circle.xml)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
>
<item>
<shape
android:shape="oval">
<solid android:color="#f00"></solid>
</shape>
</item>
<item
android:bottom="3dp" android:left="3dp" android:right="3dp" android:top="3dp">
<shape
android:shape="oval">
<solid android:color="#ff0"></solid>
</shape>
</item>
<item
android:bottom="6dp" android:left="6dp" android:right="6dp" android:top="6dp">
<shape
android:shape="oval">
<solid android:color="#0ff"></solid>
</shape>
</item>
</layer-list>
Activity code
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView img = (ImageView) findViewById(R.id.img);
Bitmap bm = drawableToBitmap(ContextCompat.getDrawable(this, R.drawable.ic_circle));
img.setBackground(new BitmapDrawable(bm));
}
public Bitmap drawableToBitmap (Drawable drawable) {
int width = drawable.getIntrinsicWidth();
width = width > 0 ? width : 1;
int height = drawable.getIntrinsicHeight();
height = height > 0 ? height : 1;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
Xml code
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:background="#drawable/ic_circle"
/>
<ImageView
android:id="#+id/img"
android:layout_marginTop="40dp"
android:layout_width="80dp"
android:layout_height="80dp"
/>
</LinearLayout>
In the emulator, you will see the second image is different to first image
In your drawable you have you have defined only boundaries of 2 outer small circles (yellow and red), and the blue one should take all the rest space. But since it has no defined size, once you draw it on the canvas, it's size will be 0.
You have to define it's size as well if you want to draw it directly on the bitmap.

xml layer-list bitmap tiniting not working for prelollipop

I have my xml drawable as below. It works great on lollipop and above. However for prelollipop, the android:tint="#888" is not working on the bitmap
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="#1222" />
</shape>
</item>
<item android:bottom="2dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="oval">
<solid android:color="#eee" />
</shape>
</item>
<item>
<bitmap android:src="#drawable/ic_action_name" android:tint="#888" />
</item>
</layer-list>
This is same as issue reported in Drawable tinting for api <21, but the answer there are using ImageView, which I can't do it here, since I'm composing my drawable from the bitmap with some shape in the xml. Any soluion out there?
Have you tried DrawableCompat.wrap()?
Example...
static Drawable drawable(Resources resources, Bitmap bitmap, int color) {
Drawable drawable = new BitmapDrawable(resources, bitmap);
Drawable.ConstantState state = drawable.getConstantState();
drawable = DrawableCompat.wrap(state == null ? drawable : state.newDrawable()).mutate();
DrawableCompat.setTint(drawable, color);
return drawable
}
That'll turn the Bitmap to a Drawable then tint it.
If you need the Drawable as a Bitmap, just use this or similar...
static Bitmap bitmap(Drawable drawable) {
if (drawable != null) {
Bitmap bitmap= Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
return null;
}
That should bring it back to a Bitmap, although you may have to set a width/height in the XML.

Rounded corners not working when button has background image

I have a button in my activity and it has a background image also.I have added selector attributes,and it is working for set_pressed and set_focused.But rounded corners are not coming at default state of button, for that i have inserted a background image also.pls help me ...
activity_sam.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape >
<solid android:color="#f27d0f"/>
<corners android:radius="7dp"/>
</shape>
</item>
<item android:state_focused="true">
<shape >
<solid android:color="#f27d0f"/>
<corners android:radius="7dp"/>
</shape>
</item>
<item android:state_focused="false"
android:state_enabled="true"
android:drawable="#drawable/sam_logo" >
<shape >
<corners android:radius="7dp"/>
</shape>
</item>
</selector>
add Layout same size of button
provide background image and set rounder corner xml as background to Button ..if it work accept answer.
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/ic_launcher"
android:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/top_right_left_coner"
android:text="#string/hello_world" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#android:color/transparent" />
<stroke
android:width="1dp"
android:color="#android:color/black" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<corners
android:bottomLeftRadius="10dip"
android:bottomRightRadius="10dip"
android:topLeftRadius="10dip"
android:topRightRadius="10dip" />
</shape>
Add this below last item.
<item>
<shape>
<corners android:radius="7dp"/>
</shape>
</item>
It will work as default style for button.
Add another item to show the default state as like this :
<shape>
<corners android:radius="7dp"/>
</shape>
If you want to show the rounded corner programmatically do the following :
public Drawable getRoundedBitmap(Bitmap bitmap, float Rnd_px) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff151515;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = Rnd_px;
paint.setAlpha(50);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
Drawable image = new BitmapDrawable(output);
return image;
}
The above code will crop the edges of the image. If you want to show a rounded layer over the image view. Please do the following.
<?xml version="1.0" encoding="UTF-8"?>
<solid android:color="#FFFFFF" />
<stroke
android:width="3dp"
android:color="#0000CC" />
<corners
android:bottomLeftRadius="5dp"
android:bottomRightRadius="5dp"
android:topLeftRadius="5dp"
android:topRightRadius="5dp" />
<padding
android:bottom="6dp"
android:left="6dp"
android:right="6dp"
android:top="6dp" />
I would rather try something like this in code(not checked yet):
public class MyDrawable extends PaintDrawable {
BitmapShader mShader;
Rect mRect = new Rect();
public MyDrawable(BitmapDrawable bitmapDrawable) {
super();
final BitmapShader mShader = new BitmapShader(bitmapDrawable.getBitmap(), bitmapDrawable.getTileModeX() == null ? Shader.TileMode.CLAMP : bitmapDrawable.getTileModeX(), bitmapDrawable.getTileModeY() == null ? Shader.TileMode.CLAMP : bitmapDrawable.getTileModeY());
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setShader(mShader);
}
#Override
public void draw(Canvas canvas) {
int saveCount = canvas.getSaveCount();
canvas.save();
getPadding(mRect);
canvas.translate(mRect.left, mRect.top);
getShape().draw(canvas, mPaint);
canvas.translate(-mRect.left, -mRect.top);
canvas.restoreToCount(saveCount);
}
}
thanks to this You can use MyDrawable.setCornerRadii(float[] radiuses), and thanks to this draw image in rect with 4 diffrent radiuses(top-left,top-right,bottom-left,bottom-roght)

Android XML drawable rounded corners with bitmap tag

I have next XML drawable blue_button
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<layer-list>
<item><bitmap android:src="#drawable/button_blue_bg" />
</item>
<item >
<shape>
<corners android:radius="50dip" />
<stroke android:width="1dip" android:color="#ccffffff" />
<solid android:color="#00000000" />
<padding android:bottom="3dip"
android:left="3dip"
android:right="3dip"
android:top="3dip" />
</shape>
</item>
</layer-list>
</item>
</selector>
And i have image button_blue_bg with gradient with 1px width.
When i set button background i get next image
As you can see i have background not clipped with rounded border.
How i need modificate xml for background gradient image be not outside border?
I understand why it happended, because i use layers - so this like sandwich- but i also programming on objective c, and there it's also use layers. But in Apple it's wotks fine.
i use this.... First a Layer for the basic definition, set this layer as backgound of your layout:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<stroke android:width="0.2dp" android:color="#color/anycolor" />
<corners android:radius="10dp" > </corners>
</shape>
</item>
<item>
<bitmap android:src="#drawable/imgback" />
</item>
</layer-list>
i use this function for making round corners:
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = 12;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output ;
}
and finaly, the code in the activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
// i use a Relative Layout
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rlmenu);
// Obtain then backgroud of RelativeLayout
LayerDrawable layer = (LayerDrawable) rl.getBackground();
// obtain the image set in the Layer
BitmapDrawable bg = (BitmapDrawable) layer.getDrawable(1);
// create a new BitmapDrawable from the function
Drawable d =new BitmapDrawable(getRoundedCornerBitmap(bg.getBitmap()));
// set the new roundcorner image in the layer
layer.setDrawableByLayerId(1, d);
rl.setBackgroundDrawable(d);
}
A 9-patch would be perfect for your situation

Categories

Resources