I needed to get constant aspect ratio of TextView with background image (9patch). So i used the code below in my activity:
#Override
public void onResume() {
super.onResume();
// adding contact image resize callback for adjusting image height
findViewById(R.id.contactText).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// aspect ratio
float resizeRatio = 1.13f;
// getting contact frame
TextView contactView = (TextView) findViewById(R.id.contactText);
ViewGroup.LayoutParams layout = contactView.getLayoutParams();
// resizing contact text
layout.height = (int) (contactView.getWidth() * resizeRatio);
contactView.setLayoutParams(layout);
contactView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
This code does what i expect - TextView is resized. But the borders (padding) for text, described in nine-patch are get from not resized image. So text is displayed in the center of TextView instead of bottom, where the padding borders are located.
How to fix this problem?
The problem is because of constant top padding of image even after stretch. When android stretches image vertically it keeps top padding value. So if padded area is not in stretched area it increases though it is not stretched at all.
This problem is described here
Related
I want to translate this circle image percentage wise within the same view group. The New location could be anything 30% or 50% or 100% according to data I will get.
How can I achieve this?
Try this code:
mContainerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mContainerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Start animation here so getHeight won't return 0
int maxTranslateDistance = mContainerView.getHeight() - mCircleView.getHeight();
float percent = 1; // Within 0 - 1
mCircleView.animate().translationY((int)(maxTranslateDistance * percent)).setDuration(0).start();
}
});
mContainerView is your container LinearLayout and mCircleView is the circle view. You calculate the maximum distance can be translated by both the height, multiply by the percentage (0 - 1) to get the final distance.
You can remove getViewTreeObserver().addOnGlobalLayoutListener part if you start the animation after the layout is fully drawn on the screen.
the LL should contain a space on top of the circle with height="0dp". when data received, you should set weight attribute of the space to
100-(received_percentage). remember to set weight_sum of LL to 100.
I am working on android application in which on button click i am giving width and height to my linear layout to make it full screen and by clicking again i am giving its width and height to 1dp. I just need to animate this thing like when i press the button it will slowly animate to full screen and on again pressing of button it will slowly animate to 1dp width and height. I have used translate for this thing but it didn't work in this scenario.
btnResize.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(resize==true){
otherLayout.setLayoutParams(new LayoutParams(1, 1));
resize=false;
}else{
resize=true;
int height = LayoutParams.WRAP_CONTENT;
int width = LayoutParams.MATCH_PARENT;
// ImageView imageView = (ImageView)findViewById(R.id.imageView);
//
// Animation animZoomin = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.zoom_in);
//
// imageView.startAnimation(animZoomin);
otherLayout.setLayoutParams(new LayoutParams(width, height));
}
}
});
You can use scale animation:
Start by calculating your screen size: Get screen dimensions in
pixels
Next get the current view width and height.
Calculate the ratio between the 2 to get the scale factor (hint: screenH / viewH)
Next use view.animate().scaleX(xRatio).scaleY(yRatio) to start the
animation
You may need to translate the view too if it is not centered in the screen
Other option is to use this method: Expand/collapse animation
My app shows a widget with a total of 8 buttons. I would like to give the user the possibility to style that widget and customize the size of the ImageViews which are below the buttons.
The aim is to leave the Buttons as they are, but to change the ImageView sizes dynamically.
For this the User gets to set an icon Size, which is stored in a SharedPreference as an Integer iconSize.
How can I change the size of an ImageView in a Widget?
For now, the ImageViews are created with the size set in the xml file. How can I achieve a redraw with another size?
I assume there is not much code to post here but I will be glad to do so if necessary, just tell me if you have an idea what code could help here.
What I don't want to do:
resize the entire widget
create tons of layout files to switch according to the iconSize
Some Code:
This is how I set the ImageView size in my activity as a preview of the widget. icons is an array of ImageViews, progress refers to a ProgressBar that is used to choose iconSize.
for (ImageView icon : icons) {
icon.requestLayout();
// convert into actual Pixels
progress = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX,
progress,
getResources().getDisplayMetrics()
);
// set width and height
icon.getLayoutParams().height = progress;
icon.getLayoutParams().width = progress;
sizeText.setText("" + progress);
}
Here is a little workaround I found:
simply use
views.setViewPadding(R.id.vieId, left, top, right, bottom);
(views = RemoteViews)
You just have to make some calculation, so that an iconSize of 100% (of the biggest possible size) equals 0 padding and 1% iconSize equals max padding.
It worked without, too but I think it can'T harm to add the
android:cropToPadding="true"
attribute to ImageViews if you use this method.
Edit:
I forgot to mention that at some point after setting the padding you should update the widget (I do it in onPause() when the user quits the application to look at the widget).
Using the setPadding() in an activity will also lead to nowhere without calling invalidate() on the View, to force a redraw/update of it.
Here more code:
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Map the values, 100 is the custom max of my seekBar
// I am adding 1 to because the seekBar goes from 0-99,
// but the size from 1% to 100%
int iconSize = 100 - (progress+1);
for (ImageView icon : icons) {
// set the padding
icon.setPadding(iconSize, iconSize, iconSize, iconSize);
// force the ImageView to redraw with the new padding, this
// serves as a live preview of the icons' sizes.
icon.invalidate();
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// you might want to do something here
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// map the value
int iconSize = 100 - (seekBar.getProgress()+1);
// save it in your SharedPreferences or somewhere else
Utils.setDefaultsInt(Con._ICONSIZE, iconSize, MainPage.this);
}
});
In my app I display several text views containing text of various length that is loaded in at run time. I do not know the dimensions of the text view or the length of the text until run time. Sometimes, when the text is long and the textview small some of the text is partially visible, for example:
I want to remove the partially visible text as it looks a bit naff, but I can't find a way to do this. Any help would be appreciated!
Thanks,
Dave
You can hard code the TextView height in a way that the second row of text will not be visible.
Or use:
android:maxLines , Makes the TextView be at most this many lines tall.
as suggested above.
Put your textviews in a scrollview layout.And specify a specific width to your textview and make the height wrap content.So that your text doesn't get cut.
This is how I did it. I ran this code after the activity had loaded by posting the method CheckTextIsVisible to the parent relativelayout's handler queue, otherwise the height of the textviews will not be known:
m_eventsLayout.Post(new Action(CheckTextIsVisible));
Then the method CheckTextIsVisible finds each textview with text in it, calculates the height of the font, works out how many lines can fit in the textview, and sets the number of maximum lines accordingly:
private void CheckTextIsVisible()
{
View view;
TextView tView;
Android.Text.TextPaint tPaint;
float height;
int heightOfTextView;
int noLinesInTextView;
for (int i = 0; i < m_eventsLayout.ChildCount; i++)
{
view = m_eventsLayout.GetChildAt(i);
if (view is TextView)
{
tView = (TextView)view;
if (tView.Text != "")
{
//calculate font height
tPaint = tView.Paint;
height = CalculateTextHeight(tPaint.GetFontMetrics());
//calculate the no of lines that will fit in the text box based on this height
heightOfTextView = tView.Height;
noLinesInTextView = (int)(heightOfTextView / height);
//set max lines to this
tView.SetMaxLines(noLinesInTextView);
}
}
}
}
private float CalculateTextHeight(Android.Graphics.Paint.FontMetrics fm)
{
return fm.Bottom - fm.Top;
}
This results in no partially visible text!
I have an image which is smaller than the container I would like it to fit inside of. I would like the image to stretch, keeping it's aspect ratio, to it's largest possible size.
To illustrate this problem:
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/thumbnail"
android:scaleType="fitXY"
android:adjustViewBounds="true"/>
The ImageView above would be stretched to fill the width of the container. The #drawable it contained would also stretch along the x axis to fit the width of ImageView which is perfect. The problem however is that the dimension labelled wrap_content, in this case height, remains the same size as the #drawables initial height.
I have read the documentation regarding ScaleType here and can't find the answer there.
The following image describes the above code:
Current behaviour Desired Behaviour
Edit
An ImageView given scaleType="fitCenter" will accurately expand/shrink the #drawable inside of it to grow as large as possible while retaining it's aspect ratio.
The ImageViews dimensions are defined before the #drawable is scaled in any way. The ImageView dimensions are not effected by scaling of it's contained #drawable.
XML
The only solution to this in XML is to use "match_parent" or a discrete maximum value instead of "wrap_content" where possible. This will ensure the ImageView is the correct size, which will then meaning adding scaleType="fitCenter" will ensure the #drawable will then scale correctly.
Programatically
It's ugly, but you can resize the ImageView after it's dimensions have been given discrete values:
final ImageView thumbnailView = (ImageView) toReturn.findViewById(R.id.thumbnail);
ViewTreeObserver thumbnailViewVto = thumbnailView.getViewTreeObserver();
thumbnailViewVto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean changed = false;
#Override
public void onGlobalLayout() {
if(!changed) {
Drawable image = getResources().getDrawable(R.drawable.thumbnail);
float heighToWidthRatio = image.getIntrinsicWidth()/image.getIntrinsicHeight();
int height = thumbnailView.getHeight();
thumbnailView.setLayoutParams(
new LayoutParams(
(int) (height * heighToWidthRatio), height));
changed = true;
}
}
});
EDIT
final ImageView thumbnailView = (ImageView) toReturn.findViewById(R.id.thumbnail);
thumbnailView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove the GlobalOnLayout Listener so it only fires once.
thumbnailView.getViewTreeObserver().removeGlobalOnLayoutListener(this)
// Find the images Height to Width ratio
Drawable image = getResources().getDrawable(R.drawable.thumbnail);
float heighToWidthRatio = image.getIntrinsicWidth()/image.getIntrinsicHeight();
// Use this ratio to discover the ratio of the ImageView to allow it to perfectly contain the image.
int height = thumbnailView.getHeight();
thumbnailView.setLayoutParams(new LayoutParams(
(int) (height * heighToWidthRatio), height));
}
});
Looks like you want fitCenter, which uses Matrix.ScaleToFit CENTER.