I am unable to get bitmap of expandable listview
This is what I tried
private Bitmap convertViewToBitMap() {
View printlayout = (View) getActivity().findViewById(R.id.expandableList);
printlayout.setDrawingCacheEnabled(true);
printlayout.measure(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
printlayout.layout(0, 0, printlayout.getMeasuredWidth(),
printlayout.getMeasuredHeight());
printlayout.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(printlayout.getDrawingCache());
printlayout.setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
Following method helped me
private Bitmap convertViewToBitMap() {
View printlayout = (View) getActivity().findViewById(R.id.expandableList);
printlayout.setDrawingCacheEnabled(true);
Bitmap b = printlayout.getDrawingCache();
return b;
}
I think all you need it to get the hold of the view and convert that view into the bitmap and then print the bitmap.
You can get the view using findViewById();
For converting view into bitmap, a quick google may help more, but i found this
And once you have bitmap, do what ever you want.
#Pietu1998 pointed correctly, also show your attempt so reduce chance for downvoting.
You can re-draw your list into a bitmap which you can then use.
Here I'm issuing a re-draw on an instance variable mListView and then using that bitmap for my ImageView. Note that I'm using a Handler to force the re-draw on the UI thread.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Bitmap bitmap = Bitmap.createBitmap(mListView.getWidth(),
mListView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
mListView.draw(canvas);
// Do something the
((ImageView)mContext.findViewById(R.id.img)).setImageBitmap(bitmap);
}
}, 1);
Also note that you will need to have the ImageView inside of your xml already and the ListView not taking up all the space in the layout.
Related
I want to take a picture of a view in Activity and share this picture.
First I use this method :
private Bitmap getShareViewShot() {
this.setDrawingCacheEnabled(true);
this.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(this.getDrawingCache(), 0, mSharePageRoot.getTop(), this.getWidth(), mSharePageRoot.getBottom());
this.setDrawingCacheEnabled(false);
return bitmap;
}
But if the view is in a ScrollView and the view has scrolled outside the screen, this method can't get a whole picture of this view.
So I change this method to below :
private Bitmap getShareViewShot() {
Bitmap bitmap = Bitmap.createBitmap(mSharePageRoot.getWidth(), mSharePageRoot.getHeight(),
Bitmap.Config.ARGB_8888);
mSharePageRoot.layout(0, 0, mSharePageRoot.getLayoutParams().width, mSharePageRoot.getLayoutParams().height);
final Canvas canvas = new Canvas(bitmap);
mSharePageRoot.draw(canvas);
return bitmap;
}
But another question comes: this view has no backgroud, so the picture I get has a black backgroud.In my code ,the Activity have a network image as the backgroud, so this means this method can't get the backgroud of the activity.
Please forgive me for my bad English.
Is there any other method ? thanks.
Yes, there is another method. There is a library by google called ASL(Android screenshot library). It's pretty simple.
https://code.google.com/archive/p/android-screenshot-library/wikis/DeveloperGuide.wiki
You can draw background by canvas, like this:
private Bitmap getShareViewShot() {
Bitmap bitmap = Bitmap.createBitmap(mSharePageRoot.getWidth(), mSharePageRoot.getHeight(),
Bitmap.Config.ARGB_8888);
mSharePageRoot.layout(0, 0, mSharePageRoot.getLayoutParams().width, mSharePageRoot.getLayoutParams().height);
final Canvas canvas = new Canvas(bitmap);
// the bitmap will have a white background
canvas.drawColor(0xffffffff);
mSharePageRoot.draw(canvas);
return bitmap;
}
I´m doing a 2d render class(that renders an int array of pixels) and i want to show this pixels into the screen. I´ve tried with an ImageView but its not working; Is there any method like canvas on android ? Or How do you create an image that updates all the time ? (I have implemented the runnable class)
This is what I have done:
#Override
public void run()
{
Imageview exampleImage = (ImageView) findViewById(R.id.exampleId);
// This is a simple method to do the int array image;
int[] img = new int[100]
for(int i = 0; i < 100; i++){
img[i] = i*100;
}
Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
bitmap.setPixels(img, 0, 10, 0, 0, 100, 100);
exampleImage.setImageBitmap(bitmap);
}
Well, and it does not show anything on the screen
Yes, you should create a custom View and draw on Canvas which will fill the Bitmap underneath.
Override the View#onDraw(Canvas) and draw the pixels with the Canvas#drawPoints(float[], Paint) method. Then you can use View#postInvalidateDelayed(long) or some of it's sibling methods to force the View to redraw itself until your animation is finished.
You can find more info about Canvas and Drawables in this API Guide.
My problem is similar to the one in Android View.getDrawingCache returns null, only null.
My code used to work with the method
private Bitmap getBitmapFromView(View v) {
v.setDrawingCacheEnabled(true);
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
But today I changed the xml layout file. Since the change I have been getting NullPointerException at the line Bitmap b = Bitmap.createBitmap(v.getDrawingCache()). So I tried changing the method getBitmapFromView to
public static Bitmap loadBitmapFromView(View v) {
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);
v.draw(c);
return b;
}
But that didn't help. I get the null in the very first line.
The situation is this: I am trying to convert the view into a bitmap. But I am doing this without first displaying the view on screen. Again, this all used to work until I changed the content of the xml layout file. The change was not even that big. I just moved stuff around and removed -- yes removed -- some of the subviews.
In any case, I know for certain there is no problem with my layout file because I can display it on screen if I want; which I have done as part of troubleshooting.
Someone suggested using a handler to call getDrawingCache(). If that's the answer, how would I write that code?
UPDATE
View view = activity.getLayoutInflater().inflate(R.layout.my_view, null, false);
findViewsByIds(view);//where I inflate subviews and add content to them.
Execute createBitmapFromView when the view is measured.
public static void executeWhenViewMeasured(final View view, final Runnable runnable) {
if(view.getMeasuredHeight() == 0 || view.getMeasuredWidth() == 0){
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
runnable.run();
removeGlobalOnLayoutListener(view, this);
}
});
} else {
runnable.run();
}
}
public static Bitmap createBitmapFromView(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void removeGlobalOnLayoutListener(View view,
ViewTreeObserver.OnGlobalLayoutListener listener) {
try {
view.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
} catch (NoSuchMethodError e) {
view.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
}
}
executeWhenViewMeasured(view, new Runnable() {
#Override
public void run() {
Bitmap bitmap = createBitmapFromView(view);
}
});
Since you are not showing the view it's easier to just draw the view on a canvas.
You are already trying to do that but I would merge both methods into one without using drawing cache.
private Bitmap getBitmapFromView(View v) {
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredWidth());
Bitmap b = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredWidth(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
v.draw(c);
return b;
}
Also check that MeasureSpec.UNSPECIFIED may not work well without the view in layout so you may need to specify a width and height.
I am taking a bitmap, creating a new one from the original and then setting the new one to an ImageView, when I recycle the original I get that error, but I am not drawing the original? For more detail read my comments in my code. As you can see I recycle the bitmap that comes in which I do not draw, I always make a new bitmap called tile that I draw.
My Code:
public void tileImage(Bitmap bm){
if(bm==null){
Debug.out("Bitmap is null");
}
else{
Bitmap tile;
float tileWidth = bm.getWidth();
float tileHeight =1024;
//if my bitmap is too wide
if(bm.getWidth()>width){
Debug.out("Bitmap too wide: "+bm.getWidth());
//if this code runs I get no error, if not I get the error
bm = Bitmap.createScaledBitmap(bm,
(int)width,
(int)(bm.getHeight()*(float)(width/tileWidth)),
false
);
}
Debug.out("Bitmap height: "+bm.getHeight()+" adjusted width "+bm.getWidth());
//if my bitmap is too tall
if(bm.getHeight()>tileHeight){
for(int i = 0; tileHeight*i<bm.getHeight(); i++){
image = new ImageView(main);
//make tiles of the body
if((tileHeight*(i+1))<bm.getHeight()){
tile = Bitmap.createBitmap(
bm,
0,
(int)(tileHeight*i),
(int)bm.getWidth(),
(int)(tileHeight)
);
Debug.out("Tiling: "+i);
}
//tile the reaminder
else{
tile = Bitmap.createBitmap(
bm,
0,
(int)(tileHeight*i),
(int)bm.getWidth(),
(int)(bm.getHeight()%tileHeight)
);
Debug.out("Tiling: "+bm.getHeight()%tileHeight+" "+i);
}
image.setImageBitmap(tile);
tiles.addView(image);
}
}
//else its not too tall
else{
image = new ImageView(main);
Debug.out("No tiling");
tile = Bitmap.createBitmap(
bm,
0,
0,
(int)bm.getWidth(),
(int)bm.getHeight()
);
Debug.out("Bitmap too small height: "+bm.getHeight()+" width "+bm.getWidth());
image.setImageBitmap(tile);
tiles.addView(image);
}
}
//this is the trouble maker
bm.recycle();
}
Bitmap.createBitmap(params) Returns an immutable bitmap from the specified subset of the source bitmap. The new bitmap may be the same object as source, or a copy may have been made.
bitmap.recycle() method Frees the native object associated with this bitmap, and clear the reference to the pixel data. This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.
onDraw() method takes some time to inflate the View. If you are passing the bitmap to draw a view and calling recycle() on the same reference then the bitmap is marked as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing.
You should call recycle() in onDestroy().
My Code:
public class MainActivity extends Activity {
private Bitmap mBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView image1 = (ImageView) findViewById(R.id.image1);
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
image1.setImageBitmap(mBitmap);
tileImage();
}
private void tileImage() {
ImageView image2 = (ImageView) findViewById(R.id.image2);
Bitmap bm = Bitmap.createBitmap(mBitmap, 0, 0,
(int) mBitmap.getWidth(), (int) mBitmap.getHeight());
image2.setImageBitmap(bm);
}
#Override
protected void onDestroy() {
mBitmap.recycle();
super.onDestroy();
}
}
The answer above is not entirely correct. You should in fact not wait until onDestroy with recycle. Especially if you make heavy use of creating these bitmaps. You might not even get to onDestroy before you get an OOM error. What you should do is test the dimensions you're scaling it to to the dimensions of the bitmap. If they are equal, return the original bitmap and no recycle is necessary. Otherwise, you'll get a new bitmap object and you should immediately call recyle on the original bitmap.
see http://developer.android.com/training/displaying-bitmaps/manage-memory.html
I have been trying to create a bit map of a list view, where the entire list view is not visible on the screen. I am using
Bitmap mBitmap = fullView.getDrawingCache();
to create bitmap. It works ok for the part of list view that is visible on the screen but, not for the part that isn't.I would like to know if a bitmap of a list view can be created without having to display it completely on the screen. All suggestions and or solutions are appreciated.
As android only draws what is visible, may idea would be to take bitmaps in pieces and then group the bitmaps into a single one. You could first get the bitmap of first n items. Then use the scrollTo method to scroll beyond the previous n items and get the bitmap for the next n items. This way you can get bitmap of the whole list view.
Try using this method. Hack here is calling the layout and measure method of the view yourself.
public Bitmap loadBitmapFromView(View v) {
v.setLayoutParams(new ViewGroup.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
Bitmap bitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
v.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bitmap);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
v.draw(c);
return bitmap;
}
Pass the view in this method like
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedFrame = inflater.inflate(R.layout.my_view, null);
Bitmap bitmap = loadBitmapFromView(inflatedFrame.findViewById(R.id.id_of_your_view_in_layout));