Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#android:color/transparent"
android:id="#+id/globeViewStreamInfoPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView android:id="#+id/streamIndicator"
android:src="#drawable/nv_tidestreamindicator"
android:scaleType="matrix"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_margin="10dp"
android:maxHeight="40dp"
android:maxWidth="40dp"
android:layout_width="40dp"
android:layout_height="40dp"/>
Code (streamIndicator is the ImageView):
streamIndicatorMatrix.reset();
streamIndicatorMatrix.setScale(size,size);
// rotate indicator in the direction of the flow
streamIndicatorMatrix.setRotate((float)(stream.currentStream.direction));
streamIndicator.setImageMatrix(streamIndicatorMatrix);
When I rotate, or scale, or both, the ImageView moves in the layout.
Weird thing is, when I break on the line after setImagematrix and inspect streamIndicator, mTop, mLeft, mWidth and mHeight all look correct. size and my rotation angle are always legal, sensible values.
I just know this is something stupid, what have I missed?
Thanks!
[EDIT]
Here's a pic, the red arrow was added by me to point to the errant ImageView:
Matrix.setRotate uses the (0, 0) pivot point by default. This is the reason your image moves in the layout. There is a overloaded version of the Matrix.setRotate method that allows you to speficy the pivot point.
final float density = getResources().getDisplayMetrics().density;
final int center = Math.round(20 * density);
streamIndicatorMatrix.setScale(size,size, center, center);
streamIndicatorMatrix.setRotate((float)(stream.currentStream.direction), center, center);
Related
I have a FrameLayout for example like this:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/tools_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent">
<ImageView
android:id="#+id/imgv1"
android:layout_width="300dp"
android:layout_height="200dp"
android:layout_gravity="center_vertical|center_horizontal"
app:cameraCropOutput="true"
app:cameraPlaySounds="false" />
<ImageView
android:id="#+id/imgv2"
android:layout_width="300dp"
android:layout_height="200dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:visibility="gone" />
</FrameLayout>
For imgv1 user can move, scale and rotate the image. After user moves the imgv1 with for example dragging it on the screen, if I use:
ImageView imgv1;
float xcoordinate, ycoordinate;
xcoordinate = imgv1.getX();
ycoordinate = imgv1.getY();
If I have not rotated the imgv1, then getX() and getY will return the position of the top left corner as can be seen here:
so in this case the value of xcoordinate is x and value of xcoordinate is y.
Now assume that I rotate the imgv1 and put the top left corner at the same location as before, i.e at (x and y) as shown here:
Now when I run:
xcoordinate = imgv1.getX();
ycoordinate = imgv1.getY();
I don't get x and y anymore, depending on the angle I get different strange values. What are these returned values and why they are not x and y?
On some sense, after the rotation, there is no top left corner. So does getX() returns the leftmost point which is the x-value for the bottom left of the rotated rectangle and getY() returns y?
First let's introduce me, I'm new in Android and mobile device programming, I previously worked on embedded systems running on QNX.
I hope I will respect the rules of this forum which seem to be quite stricts ;-).
I'm wrinting an application where I declare a layout for a welcome screen populated, between other things with a image view.
There is a first image placed in this image view in the xml file, but I will replace it by an other one later in the application's code and this second image will be potentially of a different size.
My problem is to resize and center my second image. According to my tests, it's quite automatic by using resources in Lint but it seems not so obvious by program, even if I read in the docs that it should be similar.
After reading several posts on the subject, I finally have a doubt; Can I center an image in an ImageView, or do I have to center the ImageView in the available space?
I tried the first solution without success.
So my layout is:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/fragmentInit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.cabbonline.ndguidelt.MainActivity" >
<TextView
android:id="#+id/textViewAppName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/textViewAppVersion"
android:layout_centerHorizontal="true"
android:text="#string/app_name" />
<TextView
android:id="#+id/textViewAppVersion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/TextViewDevelopCabb"
android:layout_centerHorizontal="true"
android:text="#string/app_version" />
<TextView
android:id="#+id/TextViewDevelopCabb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/imagecaBB"
android:layout_centerHorizontal="true"
android:text="#string/develop_cabb" />
<ImageView
android:id="#+id/imagecaBB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/textViewCabbUrl"
android:layout_centerHorizontal="true"
android:contentDescription="#string/logo_caBB"
android:maxHeight="150dp"
android:src="#drawable/logo_cabb_100x51_or" />
<TextView
android:id="#+id/textViewCabbUrl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="#string/cabb_url" />
<ImageView
android:id="#+id/imageSite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/textViewAppName"
android:contentDescription="#string/logo_Site"
android:scaleType="centerInside"
android:src="#drawable/image_guide_320x400" />
</RelativeLayout>
Here I can say tht the "imageSite" ImageView is well displayed, centered and occupies the whole area. Right.
Now I have a piece of code to replace this image in this same ImageView:
Bitmap imageSite = site.getSitePictureBitmap();
if (imageSite != null) {
imageGuide.setImageBitmap(imageSite);
}
If I only do that, despite en center_inside flag, the new bitmap, smaller and rectangular horizontally compare to the first one which is almost sqaure, the image is displayed very small on the bottom right corner of the ImageView, or the area taken by the ImageView, Idon't really know.
So I add this piece of code to resize it:
imageSite = site.getSitePictureBitmap(); // here I read the bitmap in a file.
if (imageSite != null) {
float maxWidth = imageGuide.getWidth();
float maxHeight = imageGuide.getHeight();
float width = imageSite.getWidth();
float height= imageSite.getHeight();
float hRatio = width / maxWidth;
float vRatio = height / maxHeight;
if (Math.abs(1 - hRatio) < Math.abs(1 - vRatio)) {
// We match horizontal available size
width = width / hRatio;
height = height / hRatio;
} else {
width = width / vRatio;
height = height / vRatio;
}
Bitmap reSizedBitmap = Bitmap.createScaledBitmap(imageSite, (int)width, (int)height, true);
imageGuide.setImageBitmap(reSizedBitmap);
So the image is now of the good width but as its vertical dimension is lower than the first picture, it's close to the textViewAppName. So as it's a rule for the ImageView in the layout description, I wonder if my image is not in the center of the ImageView in fact and my problem would come from the fact that the ImageView is now of a smaller height and doesn't fill up the whole space available at the top of the layout.
I also wondered if setting a new image doesn't reset the positionning flags. I didn't see that in the doc AFAIR but...
So I add this line after setImagebitmap() without success:
imageGuide.setScaleType(ScaleType.CENTER_INSIDE);
Can you tell me a bit more about ImageView behavior in this case and how to get my image vertically in the center of the available space. Do I have to calculate padding?
Regards,
Al
I am very close to a solution but the last bit is eluding me. I have two images of identical size that I have overlayed in a section of my layout. These images will be scaled to fit the screen depending up on screen size. I have used multiple drawables if that is relevant.
Essentially one image is a circle with an airplane in the middle and the other is a little windsock. I want the windsock to sit in the relative position that the wind is coming from.
I have got the windsock to overlay at the start nicely, I can rotate it BUT it is not rotating concentrically and the scale of the windsock changes slightly when I do the rotation. I can see this because when I return the rotation to zero the windsock graphic is not in the starting position and is slightly larger.
So the question is how do I scale the overlay to be the same as what android does when it creates the initial view?
My XML:
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="0.60"
android:gravity="center"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:textSize="12sp"
android:text="#string/runwayDirection"
android:textColor="#ffffff" />
<EditText
android:id="#+id/rwyDirection"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:background="#drawable/border"
android:ems="10"
android:gravity="center"
android:inputType="number"
android:maxLength="3"
android:text="#string/zero"
android:textColor="#ffffff"
android:textCursorDrawable="#null" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/aircraftGraphic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/windRose"
android:src="#drawable/aircraftgraphic" />
<ImageView
android:id="#+id/windpic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/windRose"
android:src="#drawable/windsockring"
/>
</FrameLayout>
</LinearLayout>
The code I am using to rotate:
public void rotate_windsock(){
float relativeWind=90;
float rwydir;
float windDirection;
if (rwyDirection.getText().toString().matches("")) rwydir=0;
else rwydir=Float.parseFloat(rwyDirection.getText().toString());
if (windAngle.getText().toString().matches("")) windDirection=0;
else windDirection=Float.parseFloat(windAngle.getText().toString());
if (rwydir>windDirection) relativeWind=360-(rwydir-windDirection);
else relativeWind=(windDirection-rwydir);
Matrix matrix=new Matrix();
windSock.setScaleType(ScaleType.MATRIX); //required
matrix.postRotate((float) relativeWind, aircraftGraphic.getWidth()/2, aircraftGraphic.getWidth()/2);
//matrix.postScale(aircraftGraphic.getWidth(), aircraftGraphic.getWidth());
windSock.setImageMatrix(matrix);
}
You can see I am currently trying to get the width of the underlying picture and since it is a square use that as the arguments for postRotate. I have tried getting the width of LinearLayout and I have tried doing a rotate on the underlying image hoping that it would scale to the same as the overlying image but nothing has worked. It is close but is obviously not right.
Anyone help me out? The only other thing I have thought of is shrinking the images further so they aren't scaled but this will waste space on larger screens?
EDIT:
I have tried changing the rotation code to this:
Matrix mat = new Matrix();
Bitmap bMap = BitmapFactory.decodeResource(getResources(),R.drawable.windsockring);
mat.postRotate(relativeWind);
Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0,bMap.getWidth(),bMap.getHeight(), mat, true);
windSock.setImageBitmap(bMapRotate);
Now that appears to work perfectly the difference between the runway direction and wind direction is a multiple of 90 but otherwise the scaling of the windsock is affected?!?!?! What is up with that!
EDIT #2:
OK For those in the future I now have it working thanks to these links:
Rotate image without shrinking on Android
http://learnandroideasily.blogspot.com.au/2013/07/imageview-animation-in-android.html
The code to do it:
RotateAnimation rAnimClockWise = new RotateAnimation(0.0f, relativeWind, 1, 0.5f, 1, 0.5f);
rAnimClockWise.setFillAfter(true);
rAnimClockWise.setInterpolator(new LinearInterpolator());
rAnimClockWise.setDuration(0);
windSock.startAnimation(rAnimClockWise);
I know this is incredibly long in the end but I am sure it will help someone in the future!!
See the edits I made in the origina question for the answer!
I'm getting my downloaded drawables correctly and they show up correctly. I just want to show the top 144x284dip of the image on my ImageView. Instead, when the images are downloaded the ImageView resizes itself to the width and height of the drawable. I've tried modifying both layoutparams and minimumwidth / minimumheight, to no avail.
Is there anything I can do to force the ImageView to stay at 144x284?
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="284dip"
android:layout_height="144dip" >
<ImageView
android:id="#+id/imageViewLogo"
android:layout_width="284dip"
android:layout_height="144dip" />
</LinearLayout>
If I understand you correctly, you want to do two things:
Fix the size of the ImageView to 284dip X 144dip.
Show only the top left portion of the image, unscaled.
Doing the second part will require you to use "matrix" scale type and set scale to 1.0 and transform factor to 0.0.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView"
android:layout_width="284dip"
android:layout_height="144dip"
android:scaleType="matrix"
android:src="#drawable/ic_launcher" />
</LinearLayout>
By default, scale factor is 1 and translation is 0. So, you don't have to do anything else. If you do wish a different scaling and translation, you could write code like this.
void showImage(Bitmap bm) {
float scaleFactor = ...;
float transform = ...;
imageView.setImageBitmap(bm);
final Matrix matrix = new Matrix();
matrix.setScale(scaleFactor, scaleFactor);
matrix.setTranslate(transform, transform);
imageView.setImageMatrix(matrix);
}
Ok, I solved it.
I just did this:
Bitmap newBitmap = Bitmap.createBitmap(bm, 0, 0, 144, 284);
Then set it to the ImageView.
How do I make a background image fit the view but keep its aspect ratio when using <bitmap /> as a background drawable XML?
None of <bitmap>'s android:gravity values gives the desired effect.
It is impossible to achieve manipulating background attribute within xml-files only. There are two options:
You cut/scale the bitmap programmatically with
Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
boolean filter) and set it as some View's background.
You use ImageView instead of background placing it as the first layout's element and specify android:scaleType attribute for it:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/backgrnd"
android:scaleType="centerCrop" />
...
rest layout components here
...
</RelativeLayout>
There is an easy way to do this from the drawable:
your_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#color/bg_color"/>
<item>
<bitmap
android:gravity="center|bottom|clip_vertical"
android:src="#drawable/your_image" />
</item>
</layer-list>
The only downside is that if there is not enough space, your image won't be fully shown, but it will be clipped, I couldn't find an way to do this directly from a drawable. But from the tests I did it works pretty well, and it doesn't clip that much of the image. You could play more with the gravity options.
Another way will be to just create an layout, where you will use an ImageView and set the scaleType to fitCenter.
Hope this information helps you achieve what you want.
I wanted to do something similar in my custom Drawable class.
Here are the important pieces:
public class CustomBackgroundDrawable extends Drawable
{
private Rect mTempRect = new Rect();
private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
...
public void draw(#NonNull Canvas canvas)
{
Rect bounds = getBounds();
if (mBitmap != null ) {
if (mScaleType == ScaleType.SCALE_FILL) {
//bitmap scales to fill the whole bounds area (bitmap can be cropped)
if (bounds.height() > 0 && bounds.height() > 0) {
float scale = Math.min(mBitmap.getWidth()/(float)bounds.width(), mBitmap.getHeight()/(float)bounds.height());
float bitmapVisibleWidth = scale * bounds.width();
float bitmapVisibleHeight = scale * bounds.height();
mTempRect.set((int)(mBitmap.getWidth()-bitmapVisibleWidth)/2, 0, (int)(bitmapVisibleWidth+mBitmap.getWidth())/2, (int)bitmapVisibleHeight);
canvas.drawBitmap(mBitmap, mTempRect, bounds, mBitmapPaint);
}
} else if (mScaleType == ScaleType.SCALE_FIT) {
//bitmap scales to fit in bounds area
if (bounds.height() > 0 && bounds.height() > 0) {
float scale = Math.min((float)bounds.width()/mBitmap.getWidth(), (float)bounds.height()/mBitmap.getHeight());
float bitmapScaledWidth = scale * mBitmap.getWidth();
float bitmapScaledHeight = scale * mBitmap.getHeight();
int centerPadding = (int)(bounds.width()-bitmapScaledWidth)/2;
mTempRect.set(bounds.left + centerPadding, bounds.top, bounds.right - centerPadding, bounds.top+(int)bitmapScaledHeight);
canvas.drawBitmap(mBitmap, null, mTempRect, mBitmapPaint);
}
}
}
}
With this approach you are flexible to apply any scale logic that you need
Another approach would be to create patch 9 images of your regular image and have it stretch scale the way you want it to.
You could have it center the content by putting 9-patch-dots in the corners that will preserve your ratio obviously (assuming the outer most edge of your image is repeatable/transparent).
Hopefully you get the idea.
If your bitmap is wider than it is tall, use android:gravity="fill_vertical". Otherwise, use android:gravity="fill_horizontal". This has a similar effect as using android:scaleType="centerCrop" on an ImageView.
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="fill_vertical"
android:src="#drawable/image" />
If you support multiple orientations, you can create one bitmap XML file in the drawable-port folder and the other in the drawable-land folder.
Using the method described by a.ch worked great for me except I used this scale type which worked much better for what I needed:
android:scaleType="centerCrop"
Here is a full list of available scale types:
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
Try using InsetDrawable (worked well for me).
Just give this your drawable, and insets (or padding) you want from either of the four sides.
InsetDrawable insetDrawable = new InsetDrawable(drawable, insetLeft, insetTop, insetRight, insetBottom);
It is specifically used for setting background drawable, of size smaller or than the View.
See Here :
https://developer.android.com/reference/android/graphics/drawable/InsetDrawable.html
Old question, but none of the other answers worked for me. This xml code did however:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
android:src="#drawable/background_image"/>
</RelativeLayout>
In order to fit the image to the available space (or if you have set width and height in dp), I have tried the following approach, also if the image is not too wide.
Here I have set same width and height for square images [or you can wrap_content on both].
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/background_image"/>
</RelativeLayout>
adjust view bounds and scale type center fit does the trick.