I have the following code called in my Android application. When I run it on an old Samsung Dart (api < 13), I get a NullPointer exception as noted below.
Is there a particular reason the code is working for the four lines above it but not the line it is getting the NullPointer?
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
public void adjustSize() {
int width, height;
Display display = getWindowManager().getDefaultDisplay();
if (android.os.Build.VERSION.SDK_INT >= 13) {
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
} else {
width = display.getWidth(); // deprecated
height = display.getHeight(); // deprecated
}
ImageView counties = (ImageView) findViewById(R.id.btnCounties);
ImageView members = (ImageView) findViewById(R.id.btnMembers);
ImageView webLink = (ImageView) findViewById(R.id.btnWebLink);
ImageView logo = (ImageView) findViewById(R.id.logo);
// Calculate image sizes
if (height > width) {
counties.getLayoutParams().height = (int) (width / 2.5);
counties.getLayoutParams().width = (int) (width / 2.5);
members.getLayoutParams().height = (int) (width / 2.5);
members.getLayoutParams().width = (int) (width / 2.5);
webLink.getLayoutParams().height = (int) ((width / 2.4) / 3.5); // Null pointer error
webLink.getLayoutParams().width = (int) (width / 2.4);
logo.getLayoutParams().height = (int) (height / 6);
logo.getLayoutParams().width = width;
} else {
counties.getLayoutParams().height = (int) (height / 2.5);
counties.getLayoutParams().width = (int) (height / 2.5);
members.getLayoutParams().height = (int) (height / 2.5);
members.getLayoutParams().width = (int) (height / 2.5);
}
}
Simply,
ImageView webLink = (ImageView) findViewById(R.id.btnWebLink);
webLink is null.
Check your layout xml: are you sure the name (btnWebLink) is correct? Are you sure you're loading the correct layout xml file?
Probabily you have the ImageView in one layout but Android is loading the layout for a specific screen size where there's no btnWebLink.
Have a breakpoint in that line and check if the variable webLink is null.
The null pointer exception comes the first time you try to use the variable.
Related
I am trying to create dynamic buttons at the center of spesific areas of the ImageView. To figure out center of any area, I am using this function:
TextView createButton(int i, String[] boundingBoxArray) {
String[] coorArray = boundingBoxArray[i].split(",");
int[] coordinates = new int[4];
int x11 = Integer.parseInt(coorArray[0].replace(" ", ""));
int y11 = Integer.parseInt(coorArray[1].replace(" ", ""));
int x22 = Integer.parseInt(coorArray[2].replace(" ", ""));
int y22 = Integer.parseInt(coorArray[3].replace(" ", ""));
coordinates[0] = x11;
coordinates[1] = y11;
coordinates[2] = x22;
coordinates[3] = y22;
TextView buttonn = new TextView(context);
buttonn.setText(String.valueOf(i + 1));
buttonn.setTextSize(15);
buttonn.setId(i + 1);
buttonn.setBackgroundResource(R.drawable.circle);
RelativeLayout.LayoutParams rel_btn
= new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
Rect bounds = imageView.getDrawable().getBounds();
int scaledHeight = bounds.height();
int scaledWidth = bounds.width();
double scale;
double differWidth = 0;
double differHeight = 0;
imageViewHeight = imageView.getHeight();
imageViewWidth = imageView.getWidth();
if (scaledHeight > scaledWidth) {
scale = ((double) imageViewHeight / (double) scaledHeight);
differWidth = (imageViewWidth - (scaledWidth * scale)) / 2;
} else {
scale = ((double) imageViewWidth / (double) scaledWidth);
differHeight = (imageViewHeight - (scaledHeight * scale)) / 2;
}
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int swidth = displaymetrics.widthPixels;
int buttonWidth = swidth / 30;
double a = ((double) (x11 + x22) / 2) * scale - buttonWidth + differWidth;
double b = ((double) (y11 + y22) / 2) * scale - buttonWidth + differHeight;
rel_btn.leftMargin = (int) a;
rel_btn.topMargin = (int) b;
rel_btn.width = 2 * buttonWidth;
rel_btn.height = 2 * buttonWidth;
buttonn.setGravity(Gravity.CENTER);
buttonn.setLayoutParams(rel_btn);
return buttonn;
}
When the activity starts, this function is called in for loop (number of loop is depends on number of areas) to create buttons on the ImageView. When all buttons are created, user can click on one of any dynamic button to focus on the spesific area.
If the user click on any button, the createButton() function is called again (it doesnt necessary but it doesnt make an issue either) for some purposes.
The problem is height of ImageView is not fixed. At the first time of calling createButton() function, the height returns as greater than the normal height. Then if you call createButton() again, the height returns the normal value.
imageViewHeight = imageView.getHeight();
imageViewWidth = imageView.getWidth();
The class has 2-3 nested thread, so maybe this is cause of problem. But I tried lots of things like:
I used CountDownLatch to handle threads and functions
I used mImageView.post(new Runnable...) to be sure to call functions after imageView is created.
I called imageView.getHeight() lots of
different places, but nothing is changed.
I keep the expression long, because I couldn't decided if the information is enough to understand. And as you realize, English is not my native. Thank you.
Edit: I forgot to mention: Below API 19, everything is cool (getHeight() value is returning as the normal size, either at the first time of calling createButton() methor or later ). API 20 and above, I get this error.
I luckily found the solution.. I use fullscreen mode at my app, but I didn't use AreaSelectActivity in fullscreen. After activity opened, status bar is coming down in a while. That's why height is changed but length is not. I put AreaSelectActivity in fullscreen mode and bum ! it is fixed now.
I'm trying to play video with ExoPlaye on TextureView. In order to scale and crop video to fit view I use matrix. My custom view extends `TextureView' Here is my code:
#Override
public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio) {
updateTextureViewSize(width, height);
Log.v("EXO", "onVideoSizeChanged() " + width + "x" + height);
}
private void updateTextureViewSize(float videoWidth, float videoHeight) {
float viewWidth = getWidth();
float viewHeight = getHeight();
float scaleX = 1.0f;
float scaleY = 1.0f;
float viewRatio = viewWidth / viewHeight;
float videoRatio = videoWidth / videoHeight;
if (viewRatio > videoRatio) {
// video is higher than view
scaleY = videoHeight / videoWidth;
} else {
//video is wider than view
scaleX = videoWidth / videoHeight;
}
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY, viewWidth / 2, viewHeight / 2);
setTransform(matrix);
}
I had a rectangular views and it worked perfectly. But now views have 2 states: expanded (the old ones that are still rectangular) and collapsed (have smaller height.
So now video is stretched vertically in those collapsed views.
For instance I have view 1080x480 and video 360x640 but it looks like video is scaled and cropped to 1080x1080 and than stretched to 1080x480.
What am I doing wrong here ?
UPD: Here are screenshots:
I fixed this issue next by multiplying or dividing scale factors by viewRatio (width / height):
if (viewRatio > videoRatio) {
// video is higher than view
scaleY = videoHeight / videoWidth * viewRatio;
} else {
//video is wider than view
scaleX = videoWidth / videoHeight / viewRatio;
}
But I did not get why it works like this. According to my calculations if I have, for instance, view 1080x480 and video 360x640 video should be scaled to have width x' = 1080 and height proportional. So height should be y' = 640*1080/360 (videoHeight * viewHeight / videoWidth) and x' = 1080
According to this image:
sx * 360 = 1080 => sx = 1080 / 360
sy * 640 = 640*1080/360 => sy = 1080 / 360
Looks like it makes sense. If we need save proportions width and height should be multiplied by the same factor. But it does not work this way. Where is a mistake ? Is there any good doc on this ?
check updateTextureViewSize :
/**
* Set the display options
*
* #param layout <ul>
* <li>{#link #VIDEO_LAYOUT_ORIGIN}
* <li>{#link #VIDEO_LAYOUT_SCALE}
* <li>{#link #VIDEO_LAYOUT_STRETCH}
* <li>{#link #VIDEO_LAYOUT_ZOOM}
* </ul>
*/
public void updateTextureViewSize(int layout,float videoWidth, float videoHeight) {
RelativeLayout.LayoutParams lp = (android.widget.RelativeLayout.LayoutParams) getLayoutParams();
DisplayMetrics disp = m_Context.getResources().getDisplayMetrics();
int windowWidth = disp.widthPixels, windowHeight = disp.heightPixels;
float windowRatio = windowWidth / (float) windowHeight;
float videoRatio = (float) videoWidth / (float) videoHeight;
m_iSurfaceHeight = videoHeight;
m_iSurfaceWidth = videoWidth;
if (VIDEO_LAYOUT_ORIGIN == layout && m_iSurfaceWidth < windowWidth && m_iSurfaceHeight < windowHeight) {
lp.width = (int) (m_iSurfaceHeight * videoRatio);
lp.height = m_iSurfaceHeight;
} else if (layout == VIDEO_LAYOUT_ZOOM) {
lp.width = windowRatio > videoRatio ? windowWidth : (int) (videoRatio * windowHeight);
lp.height = windowRatio < videoRatio ? windowHeight : (int) (windowWidth / videoRatio);
} else {
boolean full = layout == VIDEO_LAYOUT_STRETCH;
lp.width = (full || windowRatio < videoRatio) ? windowWidth : (int) (videoRatio * windowHeight);
lp.height = (full || windowRatio > videoRatio) ? windowHeight : (int) (windowWidth / videoRatio);
lp.leftMargin = (disp.widthPixels - lp.width) / 2;
lp.topMargin = (disp.heightPixels - lp.height) / 2;
}
lp.leftMargin = (disp.widthPixels - lp.width) / 2;
lp.topMargin = (disp.heightPixels - lp.height) / 2;
getHolder().setFixedSize(m_iSurfaceWidth, m_iSurfaceHeight);
setLayoutParams(lp);
m_iVideoLayout = layout;
}
I am working on a video conferencing project. My video display is using surface view. Now during a video call there is a chance of aspect ratio change for the incoming frames. So i have tried the following code for it
public void surfaceResize() {
// WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Point size = new Point();
int screenWidth = 0;
//Get the SurfaceView layout parameters
float aspectRatio = (float) recv_frame_width / recv_frame_height;
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
{
//Get the width of the screen
getWindowManager().getDefaultDisplay().getSize(size);
screenWidth = size.x;
//Set the width of the SurfaceView to the width of the screen
surflp.width = screenWidth;
//Set the height of the SurfaceView to match the aspect ratio of the video
//be sure to cast these as floats otherwise the calculation will likely be 0
surflp.height = (int) ((1 / aspectRatio) * (float)screenWidth);
//Commit the layout parameters
} else {
size.x = size.y = 0;
//Get the width of the screen
getWindowManager().getDefaultDisplay().getSize(size);
int screenHeight = size.y;
//Set the width of the SurfaceView to the width of the screen
surflp.height = screenHeight;
//Set the width of the SurfaceView to match the aspect ratio of the video
//be sure to cast these as floats otherwise the calculation will likely be 0
surflp.width = (int) ( aspectRatio * (float)screenHeight);
//Commit the layout parameters
// code to do for Portrait Mode
}
surflp.addRule(RelativeLayout.CENTER_HORIZONTAL);
surflp.addRule(RelativeLayout.CENTER_VERTICAL);
if(myVideoSurfaceView != null)
myVideoSurfaceView.setLayoutParams(surflp);
System.out.println("Surface resized*****************************************");
}
Everything is fine if I call this function at beginning of call.
My problem is when I call this function in between a call for changing aspect ratio it takes too much time to display the next frame. Sometimes the video gets stuck even.
I tried to destroy and recreate the surface with
myVideoSurface.setVisibility(VIEW.GONE);
But the surface is not getting created.
I am using Mediacodec for video decode I will get notified when there is a resolution change.
Is there something more I should do for resizing a surfaceView when already video is being played.
Thanks for help.........................
Hello try with below code:
private void setVideoSize() {
// // Get the dimensions of the video
int videoWidth = mediaPlayer.getVideoWidth();
int videoHeight = mediaPlayer.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
// Get the width of the screen
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
// Get the SurfaceView layout parameters
android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
// Commit the layout parameters
surfaceView.setLayoutParams(lp);
}
This problem can be solved like this.
How to get ImageView's Height and Width after Zoom in Zoom out.
I am using the following code:
mRectSrc.left = (int)(panX * bitmapWidth - viewWidth / (zoomX * 2));
mRectSrc.top = (int)(panY * bitmapHeight - viewHeight / (zoomY * 2));
mRectSrc.right = (int)(mRectSrc.left + viewWidth / zoomX);
mRectSrc.bottom = (int)(mRectSrc.top + viewHeight / zoomY);
mRectDst.left = getLeft();
mRectDst.top = getTop();
mRectDst.right = getRight();
mRectDst.bottom = getBottom();
// Adjust source rectangle so that it fits within the source image.
if (mRectSrc.left < 0) {
mRectDst.left += -mRectSrc.left * zoomX;
mRectSrc.left = 0;
}
if (mRectSrc.right > bitmapWidth) {
mRectDst.right -= (mRectSrc.right - bitmapWidth) * zoomX;
mRectSrc.right = bitmapWidth;
}
if (mRectSrc.top < 0) {
mRectDst.top += -mRectSrc.top * zoomY;
mRectSrc.top = 0;
}
if (mRectSrc.bottom > bitmapHeight) {
mRectDst.bottom -= (mRectSrc.bottom - bitmapHeight) * zoomY;
mRectSrc.bottom = bitmapHeight;
}
canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
So using This code i am getting zoom effect on image. How Can i Get Bitmap Height and width after zoom in and zoom out.
I tried looking for some inbuilt function for getting the size of the bitmap attached with the image view but couldn't find any. So, I made a workaround. Just store the initial height and width of the bitmap in some variable and then update these variable values with the scale factor.
This is how you can get the bitmap attached with the image(will always return the initial size):
Drawable d = imageView.getDrawable();
Bitmap bmp = ((BitmapDrawable)d).getBitmap();
float w = bmp.getWidth();
float h = bmp.getHeight();
Method to update the values:
public void updateSize(float scaleFactor)
{
w *= scaleFactor;
h *= scaleFactor;
}
You can call this method from where you are adding zoom to the image.
The code is simple:
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/cat"/>
Notice the ImageView used fill_parent for width and height.
The image cat is a small image and it will be zoomed in to fit the ImageView, and keep the width/height ratio at the same time.
My question is how to get the displayed size of the image? I tried:
imageView.getDrawable().getIntrinsicHeight()
But which it the original height of the image cat.
I tried:
imageView.getDrawable().getBounds()
But which returns Rect(0,0,0,0).
the following will work:
ih=imageView.getMeasuredHeight();//height of imageView
iw=imageView.getMeasuredWidth();//width of imageView
iH=imageView.getDrawable().getIntrinsicHeight();//original height of underlying image
iW=imageView.getDrawable().getIntrinsicWidth();//original width of underlying image
if (ih/iH<=iw/iW) iw=iW*ih/iH;//rescaled width of image within ImageView
else ih= iH*iw/iW;//rescaled height of image within ImageView
(iw x ih) now represents the actual rescaled (width x height) for the image within the view (in other words the displayed size of the image)
EDIT: I think a nicer way to write the above answer (and one that works with ints) :
final int actualHeight, actualWidth;
final int imageViewHeight = imageView.getHeight(), imageViewWidth = imageView.getWidth();
final int bitmapHeight = ..., bitmapWidth = ...;
if (imageViewHeight * bitmapWidth <= imageViewWidth * bitmapHeight) {
actualWidth = bitmapWidth * imageViewHeight / bitmapHeight;
actualHeight = imageViewHeight;
} else {
actualHeight = bitmapHeight * imageViewWidth / bitmapWidth;
actualWidth = imageViewWidth;
}
return new Point(actualWidth,actualHeight);
Here is a helper function to get the bounds of image in an imageView.
/**
* Helper method to get the bounds of image inside the imageView.
*
* #param imageView the imageView.
* #return bounding rectangle of the image.
*/
public static RectF getImageBounds(ImageView imageView) {
RectF bounds = new RectF();
Drawable drawable = imageView.getDrawable();
if (drawable != null) {
imageView.getImageMatrix().mapRect(bounds, new RectF(drawable.getBounds()));
}
return bounds;
}
I guess a lot of people are coming from this example https://developer.android.com/training/animation/zoom.html and don't want to use android:scaleType="centerCrop" (maybe because the ImageView is in a constraint layout and you want to see the small picture uncroped) don't you worry, I got your back!
Just replace the entire block beginning with
// Adjust the start bounds to be the same aspect ratio as the final
// bounds using the "center crop" technique.
with the following
//adjust for scaled image to constraint
int realheight = ResourcesCompat.getDrawable(getResources(),imageResId,null).getIntrinsicHeight();
int realwidth = ResourcesCompat.getDrawable(getResources(),imageResId,null).getIntrinsicWidth();
// Adjust the start bounds to be the same aspect ratio as the final
// bounds using ueen's adjusteddimensions technique. This prevents undesirable
// stretching during the animation. Also calculate the start scaling
// factor (the end scaling factor is always 1.0).
float startScale;
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
// Extend start bounds horizontally
// after check whether height or width needs adjusting
if ((float) startBounds.width() / startBounds.height() < (float) realwidth / realheight) {
int adjustedheight = realheight*startBounds.width()/realwidth;
int adjustedoffset = (startBounds.height()-adjustedheight) / 2;
startScale = (float) adjustedheight / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
startBounds.offset(+0, +adjustedoffset);
} else {
int adjustedwidth = realwidth*startBounds.height()/realheight;
int adjustedoffset = (startBounds.width()-adjustedwidth) / 2;
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - adjustedwidth) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
startBounds.offset(+adjustedoffset, +0);
}
} else {
// Extend start bounds vertically
// after check whether height or width needs adjusting
if ((float) startBounds.width() / startBounds.height() > (float) realwidth / realheight) {
int adjustedwidth = realwidth*startBounds.height()/realheight;
int adjustedoffset = (startBounds.width()-adjustedwidth) / 2;
startScale = (float) adjustedwidth / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
startBounds.offset(+adjustedoffset, +0);
} else {
int adjustedheight = realheight*startBounds.width()/realwidth;
int adjustedoffset = (startBounds.height()-adjustedheight) / 2;
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - adjustedheight) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
startBounds.offset(+0, +adjustedoffset);
}
}
works like a charme,
you're welcome :)
Further explanation: as usual we check wheter the picture is taller than wide (expanded the height of the picture should match the height of expandedImageView) or vice versa. Then we check if the picture in the original (smaller) ImageView (thumbView) is matching the width or the heigth, so we can adjust for the space.
This way we achieve a smooth scaling animation while not croping the picture in the thumbView, no matter it's dimension (as they may change from device to device when using constarints) or that of the picture.
use
// For getting imageview height
imgObj.getMeasuredHeight()
// For getting imageview width
imgObj.getMeasuredWidth();
//For getting image height inside ImageView
imgObj.getDrawable().getIntrinsicHeight();
//For getting image width inside ImageView
imgObj.getDrawable().getIntrinsicWidth();