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.
Related
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"/>
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.
I have a white image that I'd like to color with a gradient. Instead of generating a bunch of images each colored with a specific gradient, I'd like to do this in code (not xml).
To change an image's color, I use
imageView.setColorFilter(Color.GREEN);
And this works fine. But how can I apply a gradient color instead of a solid color? LinearGradient doesn't help, because setColorFilter can't be applied to Shader objects.
EDIT: This is the image I have:
This is what I want:
And this is what I'm getting:
You have to get Bitmap of your ImageView and redraw same Bitmap with Shader
public void clickButton(View v){
Bitmap myBitmap = ((BitmapDrawable)myImageView.getDrawable()).getBitmap();
Bitmap newBitmap = addGradient(myBitmap);
myImageView.setImageDrawable(new BitmapDrawable(getResources(), newBitmap));
}
public Bitmap addGradient(Bitmap originalBitmap) {
int width = originalBitmap.getWidth();
int height = originalBitmap.getHeight();
Bitmap updatedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(updatedBitmap);
canvas.drawBitmap(originalBitmap, 0, 0, null);
Paint paint = new Paint();
LinearGradient shader = new LinearGradient(0, 0, 0, height, 0xFFF0D252, 0xFFF07305, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawRect(0, 0, width, height, paint);
return updatedBitmap;
}
UPDATE 3
I changed: colors of gradient, LinearGradient width = 0 and PorterDuffXfermode.
Here a good picture to understand PorterDuffXfermode:
You could use a selector
main_header.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/. android"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:orientation="horizontal"
android:background="#drawable/main_header_selector">
</LinearLayout>
main_header_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/. android">
<item>
<shape>
<gradient
android:angle="90"
android:startColor="#FFFF0000"
android:endColor="#FF00FF00"
android:type="linear" />
</shape>
</item>
</selector>
The same background can be applied to an ImageView.
To define and use selector dynamically, refer to this link :
Dynamically defining and using selectors
Create a XML file , and place it in the drawable folder .
gradient.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#CCb1e7fa"
android:centerColor="#B3ffffff"
android:endColor="#CCb1e7fa"
android:angle="180" />
<corners android:radius="5dp" />
</shape>
Next add this as a background to your image view
<ImageView
android:id="#+id/umageview1"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/gradient"
android:layout_centerHorizontal="true"
/>
I know there are many questions but it do not work out for me so i am posting this question:
I a adding a circular Imageview to my application, and i want some elevation/shadow to it so that it worked on all Api not only after 21. so what should i do?
this is my code:
xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:background="#drawable/mybackground"
/>
</RelativeLayout>
this is mybackground in drawable :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#42000000" />
<corners android:radius="5dp" />
</shape>
this is my code :
public class MainActivity extends AppCompatActivity {
Bitmap bmp;
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.frames);
bmp = getroundedBitmap(bmp);
ImageView iv = (ImageView) findViewById(R.id.imageView);
iv.setImageBitmap(bmp);
//iv.setBackground(new BitmapDrawable(getResources(),bmp));
Outline outline = null;
/* if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
// outline = new Outline();
// outline.setOval(0,0,iv.getWidth(),iv.getHeight());
iv.setElevation(1500);
}*/
}
private Bitmap getroundedBitmap(Bitmap bmp) {
int targetwidth = 250;
int targetheight = 250;
Bitmap targetBitmap = Bitmap.createBitmap(targetwidth,targetheight,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(targetBitmap);
Path path = new Path();
path.addCircle(((float) targetwidth - 1) / 2, ((float) targetheight - 1) / 2, Math.min(targetwidth, targetheight) / 2, Path.Direction.CCW);
canvas.clipPath(path);
Paint p = new Paint();
p.setColor(Color.WHITE);
canvas.drawBitmap(bmp, new Rect(0, 0, bmp.getWidth(), bmp.getHeight()), new Rect(0, 0, targetwidth, targetheight), null);
return targetBitmap;
}
}
Please help me out. i ma working in android studio
Elevation cannot work before API 21 but you can have a work around by help of shadows. Create a shadow (circular in your case) in your mybackground drawable itself. Use layer-list as the parent element and gradient to create the shadow layer inside it.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<gradient android:startColor="#d1c4e9"
android:endColor="#android:color/transparent"
android:angle="270"/>
</shape>
</item>
<item android:right="1dp" android:left="1dp" android:bottom="3dp">
<shape android:shape="oval">
<solid android:color="#673ab7"/>
</shape>
</item>
</layer-list>
We can take ImageView Inside CardView,and height and width match with cardView
try once,it will work.
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>