I have a linear layout that has multiple fields that are to be filled by the user. The fields are to be filled with text or decimal numbers and they are all TextInputLayouts with one date picker. After the user has filled those fields I have a review button which once clicked shows a preview of all the values entered in an image view. I am showing the image by using bitmap and canvas and sending the bitmap as an argument to my material bottom sheet with the following code.
private Bitmap getDailySheetBitmap() {
Bitmap bitmap = Bitmap.createBitmap(completeSheetLinearLayout.getWidth(), completeSheetLinearLayout.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Log.d("Bitmap", "bitmap size: "+bitmap.getByteCount());
completeSheetLinearLayout.draw(canvas);
return bitmap;
}
And the code for sending arg is
private void buildBottomSheet(Bitmap bitmap) {
Bundle args = new Bundle();
args.putParcelable("Bitmap", bitmap);
ViewDailySheet viewDailySheet = new ViewDailySheet();
viewDailySheet.setArguments(args);
viewDailySheet.show(getChildFragmentManager(), "DailySheet");
}
The problem is that after the user reviews the fields and changes are made to those fields and when the user again clicks on the review button, the bitmap with the same old values is shown. I have tried recycling bitmap, invalidating the view, requestLayout() and forceLayout() method. But none of it is helping.
This is the code that puts bitmap into image view.This is in bottom sheet dialog fragment.
if (getArguments() != null) {
bitmap = getArguments().getParcelable("Bitmap");
binding.dailySheetImage.invalidate();
binding.dailySheetImage.setImageBitmap(bitmap);
getArguments().clear();
}
What am I doing wrong or missing?
The bitmap only captures what it thinks has changed. If the text field(not the data, just UI) is not changed it will show the same text field value as before. So I refreshed the whole layout as it would re-draw the entire layout by the following code.
private void refreshView() {
completeSheetLinearLayout.setVisibility(View.GONE);
completeSheetLinearLayout.setVisibility(View.VISIBLE);
}
I put this code just before creating the bitmap.
Related
I have implemented a video calling feature in our app. There is a button which captures the screenshot of specific view. On video call there a two views Local View and Remote View. These are actually Relative and Frame layouts. In this case i want take screenshot of remote view but it's just giving me a blank image. I think somehow agora video calling not allowing it but there should be any settings or something to disable this but that i have not found yet. here is the code:
Setting up remote video:
mRemoteContainer is a RelativeLayout and mRemoteVideo is VideoCanvas by agora.io
Similarly mLocalContainer is FrameLayout.
private void setupRemoteVideo(int uid) {
ViewGroup parent = mRemoteContainer;
if (parent.indexOfChild(mLocalVideo.view) > -1) {
parent = mLocalContainer;
}
if (mRemoteVideo != null) {
return;
}
SurfaceView view = RtcEngine.CreateRendererView(getBaseContext());
view.setZOrderMediaOverlay(parent == mLocalContainer);
parent.addView(view);
mRemoteVideo = new VideoCanvas(view, VideoCanvas.RENDER_MODE_HIDDEN, uid);
mRemoteVideo.view.setWillNotDraw(false);
mRtcEngine.setupRemoteVideo(mRemoteVideo);
}
This function used to get bitmap from the view
private Bitmap getScreenShotFromView(View v) {
Bitmap screeShoot = null;
try {
screeShoot = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(screeShoot);
v.draw(canvas);
} catch (Exception e) {
Log.e("GFG", "Failed to capture screenshot because:" + e.getMessage());
}
return screeShoot;
}
I tried function call with both view but getting black or blank image
Bitmap bitmap = getScreenShotFromView(mRemoteVideo.view);
Bitmap bitmap = getScreenShotFromView(mRemoteContainer);
Your help will be really appreciated for me as i stuck on this issue.
By the way I used the same view capturing technique on iOS with swift
and Its working fine.
I've a screen in android, which has multiple controls like a Listview and TextView and some buttons to save the record.
If there are more question (say 15) the Listview is displayed in scroll bar as the Listview has fixed length. We have used the below code to take screenshot of the screen on save but when we have more questions in Listview the screen shot is taken only for the record available in the screen. Please suggest how I can take screenshot of all the questions in the Listview when we have more.
Code Used to take screenshot where View is the LinerLayout defined in .xml file
Sample :1
public Bitmap screenShot(View v) {
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
return bitmap;
}
Sample :2
Bitmap bitmap = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Drawable bgDrawable = v.getBackground();
if (bgDrawable != null)
bgDrawable.draw(canvas);
else
canvas.drawColor(Color.WHITE);
v.draw(canvas);
So I have this camera preview set up with Camera, SurfaceView and SurfaceHolder.
I have also an ImageView where I will be putting a modified version of the camera image and I want this to update lets say once every second.
All code is ready and already working when I load images from "res" but I have a really hard time reading the image data from the camera.
I've tried following already:
Creating an intent for MediaStore.ACTION_IMAGE_CAPTURE and starting an onActivityResult getting a small thumbnail (enough for me actually) from (Bitmap)data.getExtras().get("data")
The problem is that this opens the camera App and you need to "manually" take a picture.
Creating a Camera.PreviewCallback, taking the YuvImage, and converting it to an image using YuvImage.compressToJpeg(...).
The problem here is that I can't get it to start no matter when or where i put the Camera.setPreviewCallbackWithBuffer(PreviewCallback).
Try to take the data directly from PreviewHolder by locking in to the canvas using lockCanvas() and trying to convert it to a bitmap
Obviously Doesn't work.
Edit:
What is the best way to make this work? I mean QR-Code readers must read the image data out of the camera continuously, how do they work?
I went for option number 2 and finally made it work.
used this callback, forgot the #Override before
private Camera.PreviewCallback previewCallback= new Camera.PreviewCallback()
{
#Override
public void onPreviewFrame(byte[] data,Camera cam)
{
Camera.Size previewSize = cam.getParameters().getPreviewSize();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21,previewSize.width,previewSize.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0,0,previewSize.width,previewSize.height),80,baos);
byte[] jdata = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jdata,0,jdata.length);
}
};
And initiating it using setPreviewCallback rather than setPreviewCallbackWithBuffer
SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback()
{
public void surfaceCreated(SurfaceHolder holder) {
camera.setPreviewCallback(previewCallback);
}
}
Sorry for my English!
Need help!
I make some program, who show random image after button click.
How i can make description for each image after user click on it ?
Program show random image, and how i can make description for every image in new window when user click on it ?
Well you can use the setOnClickListener method on your button to do what you want.
final TextView label = (TextView)findViewById(R.id.some_text_label);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
label.setText("Hello, World!");
}
}
Here's a tip.
Use a list or hashmap and create a custom class to hold image and image data. (Changes by a commentor)
Use Math.Random();//Random the id numbers
Stuff to learn:
Research button events and view flipper events
Here's an example:
My idea for using weakhashmap and
for improvements I recommend saving location instead of the bitmap(wastes memory).
private WeakHashMap<int, Image> whp = new WeakHashMap<Int, Image>
private int position = 0;
public void onCreate{
//Do download information or store images from sd card
//Place it in image class
loop amount of images{
image Image = new image(Bitmap_Image, Image_Description);//load image
whp.add(position, Image);//Note the amount of positions the image is field
position++;
}
//To get bitmap use "whp.get(position).image" <- This code returns a bitmap
setOnClickListener//Create event to listen on clicked image
{
int image_random = new Random().nextInt(position);
String data = whp.get(image_random).note_item;//Image Description
}
}
class image{
Bitmap image;//Actual Image
String note_item;//Image description
public void image(Bitmap intake_image, String intake_description){
this.image = intake_image;
this.note_item = intake_description;
}
}
I'm trying to implement a footer for my ListView which will act as a menu-type frame with five elements. I want the elements to be able to (dynamically, based on user input) display either images or text (or possibly both, but I'm not there yet). Eventually it will be more interactive but for now I was trying to implement it so that the ImageView (which by default displays an image) would erase the image and display text instead.
I thought the best way to implement this was to draw text on a canvas and use the android.view.View.draw(canvas c) method to draw it onto the ImageView. However, I'm having trouble doing this. Specifically, I can modify the view in almost any way (set the background color, change the drawable, etc etc) and it all works fine, and the code to draw the canvas compiles properly, but it doesn't do anything at runtime. The view remains completely unchanged.
(Note: I've tried to eliminate any stupid mistakes through code (i.e. made sure text wasn't transparent/same color as bg, made sure text was drawn inside the area of the view, etc) but I am not 100% it's error free.)
I tried both drawing to the view passed into the onClick function and drawing to a new ImageView constructed from the passed view - neither works.
Does anyone have any suggestions?
Code follows:
login_button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
Bitmap img = Bitmap.createBitmap( 60, 60, Config.ARGB_8888);
Canvas c = new Canvas();
c.setBitmap(img);
Paint myPaint = new Paint();
myPaint.setTypeface(mFace);
myPaint.setColor(android.R.color.black);
myPaint.setTextSize(2);
myPaint.setTextAlign(Paint.Align.LEFT);
String content = "testing";
c.drawText(content, 0,0, myPaint);
view.draw(c);//does nothing
ImageView view2 = (ImageView) view;
view2.setBackgroundColor(android.R.color.white); //this works perfectly
view2.draw(c);//does nothing
Toast.makeText(MainListView.this, ""+c.getHeight(), Toast.LENGTH_SHORT).show(); //making sure c has height - this returns 60 as expected
Toast.makeText(MainListView.this, "end of method", Toast.LENGTH_SHORT).show();
}
});
View.draw(Canvas) draws the View onto the Canvas, not vice versa like you seem to expect.
If you want to do it along the lines that you already are, you need to extend an existing View class, likely TextView or ImageView, and override onDraw(), as explained in the Custom Components Dev Guide.
I think what I would do is use something like a FrameLayout and set it to contain either the appropriate TextView or ImageView as necessary. That seems cleaner than manually rendering text in an ImageView.
You could create the Canvas from the Bitmap, and set the Bitmap as the Image for your ImageView.
Bitmap img = Bitmap.createBitmap( 60, 60, Config.ARGB_8888);
Canvas c = new Canvas(img);
Paint myPaint = new Paint();
myPaint.setTypeface(mFace);
myPaint.setColor(android.R.color.black);
myPaint.setTextSize(2);
myPaint.setTextAlign(Paint.Align.LEFT);
String content = "testing";
c.drawText(content, 0,0, myPaint);
ImageView view2 = (ImageView) view;
view2.setImageBitmap(img);
Toast.makeText(MainListView.this, ""+c.getHeight(), Toast.LENGTH_SHORT).show(); //making sure c has height - this returns 60 as expected
Toast.makeText(MainListView.this, "end of method", Toast.LENGTH_SHORT).show();
Although, I believe the "right" way to do this is to use an extension of View and override the onDraw method to draw differently based on some local variables:
login_button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
((MyView)view).mContextVariable = true; //or false, etc
//you might not need this invalidate, because the click event probably causes and invalidate to be called
view.invalidate();
}
}
class MyView extends View
{
Paint myPaint;
boolean mContextVariable;
public MyView(Context context)
{
super(context);
myPaint = new Paint();
myPaint.setTypeface(mFace);
myPaint.setColor(android.R.color.black);
myPaint.setTextSize(2);
myPaint.setTextAlign(Paint.Align.LEFT);
}
#Override
protected void onDraw(Canvas canvas)
{
if(mContextVariable)
{
//draw something
}
else
{
//draw something else
}
canvas.drawText("testing", 0,0, myPaint);
}
}