Android Problems Converting ViewGroup with Children into Bitmap - android

I'm successfully converting a ViewGroup (RelativeLayout) into Bitmap using a Canvas. However, when the draw happens I only see the ViewGroup with its background drawable and not its children (two TextViews) who should be laid out within the RelativeLayout using rules like FILL_PARENT.
The RelativeLayout is created using the following static function:
public static RelativeLayout createProgrammeView(Context context, int width, int height, String title, String time) {
RelativeLayout.LayoutParams params;
// Layout Root View (RelativeLayout)
RelativeLayout rlv = new RelativeLayout(context);
params = new RelativeLayout.LayoutParams(width, height);
rlv.setLayoutParams(params);
rlv.setPadding(3, 3, 3, 3);
rlv.setBackgroundResource(R.drawable.background);
// Layout Title
TextView tv = new TextView(context);
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
tv.setId(R.id.title);
tv.setLayoutParams(params);
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setSingleLine(true);
tv.setEllipsize(TruncateAt.END);
tv.setTextColor(Color.parseColor("#fff"));
tv.setTextSize(11);
tv.setText(title);
rlv.addView(tv);
// Layout Start Time
tv = new TextView(context);
params = new RelativeLayout.LayoutParams(16, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, R.id.title);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
params.setMargins(0, 4, 0, 0);
tv.setId(R.id.time);
tv.setLayoutParams(params);
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setSingleLine(true);
tv.setEllipsize(null);
tv.setTextColor(Color.parseColor("#fff"));
tv.setTextSize(10);
tv.setText(time);
rlv.addView(tv);
}
return rlv;
}
I then use the following to turn the RelativeLayout into a Bitmap:
public static Bitmap loadBitmapFromView(RelativeLayout v) {
Bitmap b = Bitmap.createBitmap(v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
As expected this gives me a nice Bitmap in the dimensions that I require with the background drawable, but the children are not in the bitmap. I call these functions quite a lot to build a large image which then gets drawn onto a custom view in my activity.
This is the loop which calls the static function:
public static void renderViews(final Context context) {
largeBitmap = Bitmap.createBitmap(largeWidth, largeHeight, Bitmap.Config.RGB_565);
Canvas largeCanvas = new Canvas(largeBitmap);
for (int i = 0; i < items.size(); i++) {
int leftMargin = ...SOME CALCULATIONS...;
RelativeLayout newView = createProgrammeView(context, width, rowHeight, "Title", "21:00");
Bitmap newViewBitmap = loadBitmapFromView(newView);
largeCanvas.drawBitmap(newViewBitmap, leftMargin, 0, new Paint());
}
myCustomView.invalidate();
}
My custom view overrides the onDraw() function:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(largeBitmap, 0, 0, null);
}
From what I can see I believe this is because Android doesn't call a measure() on the child Views. I have tried calling this manually, but this doesn't solve the problem.
So, I guess what I would like to know is, how can I achieve converting a RelativeLayout with children into a Bitmap and get Android to measure the children so they respect their relative layout rules.
Many thanks to anyone who can help me work this out.
Rob

The problem is that you did not measure and layout the container. You must call v.measure(widthSpec, heightSpec) and then v.layout(left, top, right, bottom) before drawing can work. The first method will make sure the view knows how big you want it to be, and the second method will ensure the children are positioned properly.
In your case you would do:
v.measure(MeasureSpec.makeMeasureSpec(v.getLayoutParams().width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(v.getLayoutParams().height, MeasureSpec.EXACTLY));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
v.draw(c);

Solution that based on DisplayMetrics for the Layouts could be useful as well. In order not to repeat - look here .

Related

Android is not creating bitmap image from view

I am working on an android app and I am trying to create bitmap image from view. My view creation codes are,
private View createInflatedViewFromLayout(Context context, String question, String answer, ViewGroup containerView){
View view;
//Creating view from layout inflater
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.image_export_view, (ViewGroup) containerView.getParent(), false);
//Getting layout and text views
LinearLayout layout = (LinearLayout)view.findViewById(R.id.imageExportLayout);
TextView pre_text_one = (TextView)view.findViewById(R.id.imageLayout_pre_text_one);
TextView pre_text_two = (TextView)view.findViewById(R.id.imageLayout_pre_text_two);
TextView pre_text_three = (TextView)view.findViewById(R.id.imageLayout_pre_text_three);
TextView post_text_one = (TextView)view.findViewById(R.id.imageLayout_post_text_one);
TextView post_text_two = (TextView)view.findViewById(R.id.imageLayout_post_text_two);
//Setting up typeface
pre_text_one.setTypeface(custFont);
pre_text_two.setTypeface(custFont);
pre_text_three.setTypeface(custFont);
post_text_one.setTypeface(custFont);
post_text_two.setTypeface(custFont);
//Setting up text and answer in text views
post_text_one.setText(question);
post_text_two.setText(answer);
//To get random number so we can get color from colors array
Random r = new Random();
int Low = 0;
int High = 5;
int Result = r.nextInt(High-Low) + Low;
layout.setBackgroundColor(Color.parseColor(colors[Result][0]));
post_text_one.setTextColor(Color.parseColor(colors[Result][1]));
post_text_two.setTextColor(Color.parseColor(colors[Result][1]));
return view;
}
So this function is working properly and creating view. I have verified it by codes below,
final LinearLayout testLo = (LinearLayout)convertView.findViewById(R.id.test_lo);
if(testLo.getChildCount() > 0)
testLo.removeAllViewsInLayout();
View lv = createInflatedViewFromLayout(context,
questions[(Integer)v.getTag()],
answers[(Integer)v.getTag()],
finalConvertView);
testLo.addView(lv, 0);
My bitmap image creation function is
public static Bitmap loadBitmapFromView(View v, Context ctx) {
Bitmap b = Bitmap.createBitmap(
2000, 2000, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, 2000, 2000);
v.draw(c);
return b;
}
and when I check the image with these codes,
Bitmap bmp = loadBitmapFromView(testLo.findViewById(0), context);
ImageView image = new ImageView(context);
image.setImageBitmap(bmp);
testLo.addView(image);
All I get is colored background but no text from view. And problem I am facing with with bitmap creation function is that I have to give height and width manually.
I mean if I use these codes,
Bitmap b = Bitmap.createBitmap(
v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getWidth(), v.getHeight());
or these codes,
Bitmap b = Bitmap.createBitmap(
v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height);
it is crashing app by throwing error that height and width needs to be greater than 0. It is returning -1, -2 etc.
To create bitmap image I have also used below line of code,
Bitmap bmp = loadBitmapFromView(lv, context);
Can anyone tell me where I have problem? What do I need to change to get height, width and create image from layout view.
I'm not sure but I used this boilerplate code for creating bitmaps from my screen - in other words the code below will actually take a screenshot of your phone:
final View v = getWindow().getDecorView().getRootView();
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
If you only want to take a bitmap of a specific view, like a TextView or ImageView, you can just do this:
TextView v = (TextView) findViewById(R.id.example);
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);

Android place ImageView on top of Canvas

how can I display a programmatically created ImageView on top of a previously created View Canvas? I tried using bringToFront(), but without success.
Code:
RelativeLayout root = findViewById(R.id.layout);
ImageView img = new ImageView(GameGuessActivity.context);
img.setImageResource(R.drawable.image);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
params.leftMargin = x;
params.topMargin = y;
root.addView(img, params);
img.bringToFront();
The Image is being displayed, but underneath the canvas, which I don't want.
You have to redraw your imageview on canvas:
pcanvas = new Canvas();
pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
pcanvas.drawBitmap(bitmap, 0, 0, null);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
image.draw(pcanvas);
img.bringToFront();
img.invalidate();
img.draw(pcanvas);

TextView to Bitmap, alignment issues

I am facing a situation in which I need to draw bitmap for a given text. I tried to render a TextView with required properties and then draw its bitmap using canvas. My try looks like this:
TextView nameTv = new TextView(context);
Bitmap bmp = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
nameTv.layout(0, 0, 200, 200);
nameTv.setGravity(Gravity.CENTER);
nameTv.setText("Test");
nameTv.setBackgroundColor(Color.RED);
nameTv.draw(canvas);
The problem with this code is that the text on TextView not center aligned, which I require.
Any suggestions are welcomed :)
Thanks,
Ammar
I think the problem is in measuring. You not calling measure for that and it don't have properly size. Call nameTv.measure() before layout().
Call measure like this:
int measureSpecWidth = MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY);
int measureSpecHeight = MeasureSpec.makeMeasureSpec(200, MeasureSpec.EXACTLY);
nameTv.measure(measureSpecWidth, measureSpecHeight);

Android custom view: Set canvas size to wrap bitmap

I have a custom view that has Canvas in it. I'm using this canvas to show a bitmap on it and then I can draw over the bitmap on touch. When I load the bitmap it is a lot bigger then the view size and I can't see the whole bitmap (it's picture taken with camera). I tried to create scaled bitmap and then draw it on the canvas, but in that case the bitmap is smaller and the canvas is taking the whole layout space available. I'm adding this view programmatically, not int the xml layout. I have set this to the view but not working:
fdvImage = new ImageEditingView(this, b);
RelativeLayout.LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_IN_PARENT, 1);
fdvImage.setLayoutParams(lp);
and this is my view constructor:
public ImageEditingView(Context c, Bitmap b) {
super(c);
this.setMinimumHeight(0);
mBitmap = Bitmap.createScaledBitmap(b, b.getWidth()/2, b.getHeight()/2, true);
mCanvas = new Canvas(mBitmap);
}
and in the onDraw I have this:
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}
So, my question is: Why is the canvas taking all the layout space even if the bitmap is smaller then it?
Use this code to draw bitmap
canvas.drawBitmapMesh(yourBitmap, 1, 1,vertices, 0, null, 0,
paint);
Make vertices according to your view
[EDIT]
float[] vertices = new float[8];
vertices[0]=0; vertices[1]=0; vertices[2]=100; vertices[3]=0;
vertices[4]=0;vertices[5]=200; vertices[6]=100; vertices[7]=200;
change the 100 to your width and 200 to height

measure() doesnt work properly with dynamic layouts and textView - Android

I want to convert a RelativeLaout view into a Bitmap. I've tried another answers and different options without success.
My XML View is kind of:
----RelativeLayout
-------ImageView
-------TextView
Every ones have wrap_content measures.
As i need several bitmaps of the view, im inflating it this way:
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.localviewlayout, null);
ImageView img = (ImageView) v.findViewById(R.id.imgPlace);
img.setImageBitmap(MyDynamicBitmap);
TextView txt1 = (TextView)v.findViewById(R.id.text1);
txt1.setText(MyDynamicText);
return v;
After that :
//in measure() i get a nullpointerException on RelativeLayout.onMeasure().I also have tried //with MeasureSpec.EXACTLY
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap b = Bitmap.createBitmap( v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
v.draw(new Canvas(b));
Paint p = new Paint();
myMainCanvas.drawBitmap(b, myPointX, myPointY, p);
The content of textView of the RelativeLayout is dynamic, so i cant know the width or height of the text.
Besides of the exception, if i manually set enough size on the measure function (insted of 0), my dynamic text doesnt display entirely.
I hope you can help me because right now, im stuck. Thank youuu
Try adding
v.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
before calling measure(). Does that fix the NullPointerException?

Categories

Resources