Android ImageView - Fill width and Resize to Maintain Aspect Ratio - java

I have a row View that I am using in a ListView.
This RowView consists of an ImageView on the left and a TextView on the right in a horizontal LinearLayout where the image is given 40% of the space and the text the remaining 60%.
I want the layout to handle the resizing of the image in the ImageView in the following manner:
Stretch the image horizontally so that it fills up given 40% of the LinearLayout
Resize the ImageView vertically to maintain the original aspect ratio
This is my approach to the layouts:
protected class RowView extends LinearLayout {
public ImageView iv = null;
public TextView tv = null;
private LinearLayout.LayoutParams ivlp = null;
private LinearLayout.LayoutParams tvlp = null;
public RowView(Context ct) {
super(ct);
setOrientation(LinearLayout.HORIZONTAL);
// Create the views
iv = new ImageView(ct);
ivlp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 0.4f);
iv.setLayoutParams(ivlp);
iv.setAdjustViewBounds(true);
iv.setScaleType(ScaleType.FIT_XY);
tv = new TextView(ct);
tvlp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 0.4f);
tv.setLayoutParams(tvlp);
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
// Add the views
addView(iv);
addView(tv);
}
}
The result I am getting is something like this:
From what I understand:
The MATCH_PARENT is correctly forcing the image to horizontally stretch to fill the 40% space
The ImageView.setAdjustViewBounds(true) is supposed to allow any resizing of the ImageView that is necessary which is what I want. The problem is none of the ImageView.ScaleType's seem to do what I want
ImageView.ScaleType(ScaleType.FIT_XY) is not what I want because it doesn't maintain the aspect ratio. But all the others that do, don't seem to stretch the height of the ImageView (which is making ImageView.setAdjustViewBounds(true) pretty much useless).
What am I doing wrong? It seems wrong that something this simple could be so difficult?
Or do I actually have to go to the effort of extending an ImageView and Overriding onMeasure to force the resizing and aspect ratio?
Or is there a clever trick with Matrix to get the job done?

I believe this is what you are looking for:
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/myImage"
android:scaleType="fitCenter"
android:adjustViewBounds="true" />

Remove the scale type completely. Also, I think you might have misunderstood what setAdjustViewBounds does. If an image is scaled, the bitmap in the ImageView is scaled, but not the ImageView. Setting setAdjustViewBounds to true will assure that the ImageView's bounds will always match the drawn bitmap's bounds.

Related

Set Gravity to TextView with background drawable image programmatically not working

I search for this problem but i didn't find a convenient answer.
I try to add dynamically a TextView to a LinearLayout, but the problem is that the setGravity doesn't work.
This is my code:
TextView textView = new TextView(mContext);
textView.setTextColor(Color.BLACK);
textView.setText(colorKeyword(resources.getString(R.string.tipsbutton_tooltip)));
textView.setTextSize(35);
textView.setTextScaleX(1.1f);
textView.setPadding(textViewPadding, textViewPadding, 0, textViewPadding);
textView.setTextAppearance(mContext, R.style.fontForTooltipsTexts);
textView.setGravity(Gravity.CENTER_VERTICAL);
textView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
textView.setBackgroundResource(R.drawable.tip_box);
tooltipView.setBackgroundResource(android.R.color.transparent);
ImageView arrowView = new ImageView(mContext);
arrowView.setImageResource(R.drawable.tip_arrow_down);
arrowView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
arrowView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
tooltipView.setOrientation(LinearLayout.VERTICAL);
tooltipView.addView(textView);
tooltipView.addView(arrowView);
If i set the layout height of the textview to MATCH_PARENT, the gravity knows to center the text horizontal as i need, but the side effect is that all the background/ textview area is stretched to the parent height.
I now for sure is a problem related to the order in which they are laid out. Is probably something that i miss to do.
I use this for parent:
LinearLayout tooltipView = new LinearLayout(mContext);
tooltipView.setOrientation(LinearLayout.VERTICAL);
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
tooltipView.setLayoutParams(lp);
tooltipView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
tooltipView.setGravity(Gravity.CENTER_VERTICAL);
I tried to inflate from a layout in which i already added the background, but i have the same problem.
The height of the TextView should match to the background image height.
Thanks for any suggestions!

prevent gridView from expanding to fit landscape width

I have a gridView with 4 columns of imgs. When phone is turned to landscape layout, grids of the gridView expand to fill the width, creating white spaces in between the img although the img stay at desired width. Is there a way to keep the grid view from filling width of screen when in landscape layout ?
I have 2 methods to do that:
1) Create layout for each orientation:
res/layout/....
res/layout-land/....
2) Only one layout for both vertical and horizontal orientation:
set up GridView with: android:numColumns="4"
your custom view item, always set android:layout_width="match_parent"
with the second method, you may encount problem with high of item. Just create your custom View and override onMeasure.
For example: I need a LinearLayout for my item and the keep my ratio height/width = 4.5/4, so I do the following custom:
public class MyLinearLayout extends LinearLayout {
//..... constructor methods
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int scaleHeight =(int)( widthMeasureSpec/4*4.5);
super.onMeasure(widthMeasureSpec, scaleHeight);
}
}

Android ImageView Layout Issues

There very well may be a duplicate question, but I have yet to find it. I am doing thing all programmatically, not using the xml. Basically what I am trying to do is to have an EditText appear below an image. I am using RelativeLayout with an ImageView and and EditText.
These are the parameters that I am setting up for the ImageView and EditText:
RelativeLayout.LayoutParams editTextParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
editTextParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
editTextParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
editTextParams.width=500;
RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
imageParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
imageParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
imageParams.addRule(RelativeLayout.ABOVE, editText.getId());
Which I have verified correctly places the EditText in the bottom right corner and the image above. What I run into is if the picture it "too tall" then it covers the EditText. I also tried using
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
and it stretches it over the EditText as well.
The full code that I am using is this
RelativeLayout layout = (RelativeLayout) findViewById(R.id.mainLayout);
ImageView imageView = new ImageView(this);
EditText editText = new EditText(this);
RelativeLayout.LayoutParams editTextParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
editTextParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
editTextParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
editTextParams.width=500;
RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
imageParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
imageParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
imageParams.addRule(RelativeLayout.ABOVE, editText.getId());
imageView.setLayoutParams(imageParams);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
editText.setLayoutParams(editTextParams);
Bitmap image = getImage();
imageView.setImageBitmap(image);
layout.addView(editText);
layout.addView(imageView);
Thanks. Any suggestions would be greatly appreciated.
Create a LinearLayout and then add the two components in it (ImageVIew and EditText)
Here is what you should do;
Set the orientation to vertical for the horizontal layout and width to whatever you need
Set the with of both components to 0 and weights to 1 each
After that, you should have the two items one above the other;
I hope this helps
One thing you can do is fix the imageview width and height. This way you can control the maximum size without the imaging going over the edit text.
RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams(256, 256);
Hopefully this helps.
Your editText has a vertical MATCH_PARENT. Shouldn't it be WRAP_CONTENT?
(I am not sure if this helps, but it might help, as the MATCH_PARENT contradicts your planned layout, and your screenshot indicates that the editText is vertically centered.)

android - TextView getting scrollbar to always show programatically

I am dynamiclly creating a View which contains an image and a TextView this is then being added to a ViewFlipper. This is all working as it should the issue is I require the scrollbar to always be visible, however I simple cannot get it to work and am not sure what I am doing wrong.
Below is my dynamic code and the xml code which I am trying to replicate
for(int i = 0; i < 5; i++)
{
// Creating my linear layouts & views
lls = new LinearLayout(this);
llv = new LinearLayout(this);
lls.setOrientation(LinearLayout.VERTICAL);
// Adding image view
imgStory = new ImageView(this);
imgStory.setImageResource(GetImage(i));
imgStory.setLayoutParams(new LayoutParams(width, width));
lls.addView(imgStory);
// adding textview, which is scrollable
txtStory = new TextView(this);
txtStory.setText(unescape(story.get(i)));
txtStory.setTextColor(getResources().getColor(R.color.orange));
txtStory.setPadding((int)padding, (int)padding, (int)padding, (int)padding);
txtStory.setMovementMethod(new ScrollingMovementMethod());
//txtStory.setVerticalScrollBarEnabled(true);
//txtStory.setVerticalFadingEdgeEnabled(false);
lls.addView(txtStory);
// Adding views to my view flipper
llv.addView(lls);
viewFlipper.addView(llv, i);
}
XML code I am trying to replicate programatically
<TextView
android:id="#+id/txtStoryText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/imgStoryLine"
android:layout_above="#+id/footer"
android:layout_margin="20dp"
android:scrollbars="vertical"
android:scrollbarSize="10dp"
android:fadeScrollbars="false"
android:textColor="#color/orange"
android:text="" />
How about trying to use a ScrollView as the top most parent. So, something like this:
// Creating my linear layouts & views
lls = new LinearLayout(this);
llv = new ScrollView(this); // This looks like the view you're adding to the viewFlipper
lls.setOrientation(LinearLayout.VERTICAL);
Or, if it's just the text you want to scroll, make the first LinearLayout a Scrollview:
// Creating my linear layouts & views
lls = new ScrollView(this); // This wraps your textView
llv = new LinearLayout(this);
lls.setOrientation(LinearLayout.VERTICAL);
NOTE: this is not tested. Just trying to give you an idea. You may have to specify more layout parameters for the ScrollView to get this to work.
You can also take a look at this post where they talk about setting:
textView.setMovementMethod(new ScrollingMovementMethod())

How do I have an ActionBar icon/logo that overlaps the content as well?

I'm currently making one of my very first applications. I'm using ActionBarSherlock.
I would like to make my logo overlap the actionbar (scrollview).
Currently I have main_activity.xml. In MainActivity.java I use setContentView to view main_activity.xml. After that I use getSupportActionBar() for ActionBarSherlock. I've tried things out using RelativeLayout  (http://www.mkyong.com/android/android-relativelayout-example/). That didn't really work because there are multiple layouts.
So I've tried some things right and left, but it always ends up infront or behind the actionbar, or stops just before reaching the content. It's because of two different layouts, that's what I know. But how can I going to solve this? Is it possible? Thanks in advance!
What I want:
http://f.cl.ly/items/3N0w243N1t2Q3i1H1f1k/Untitled-1.png
You can either:
A. Split your image in two
Have the top part as the ActionBar logo, then show the bottom part over your content.
B. Use a single image
You'll need a layout file that contains just your logo (you'll probably want something like an ImageView inside a LinearLayout so you can easily set the correct margins).
Then after calling setContentView for your activity, add your logo view with:
ViewGroup decorViewGroup = (ViewGroup) getWindow().getDecorView();
decorViewGroup.addView(logoView);
Using a layout file
Example layout file (logo_view.xml):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/logo_image"
android:scaleType="center"
android:layout_marginLeft="10dip"
/>
</LinearLayout>
Inflate the layout file:
LayoutInflater inflater = LayoutInflater.from(this);
View logoView = inflater.inflate(R.layout.logo_view, null, false);
Although the original answer works on some devices, on others the image sits under the status bar. I resolved this by getting the location of the top ActionBar and comparing it to the location of the top of the logo image and then just adding some top padding, as follows:
// Inflate logo layout
LayoutInflater inflater = LayoutInflater.from(this);
final View logoView = inflater.inflate(R.layout.menu_logo, null);
// Add logo to view
ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
viewGroup.addView(logoView);
// Adjust the logo position
int resId = getResources().getIdentifier("action_bar_container", "id", "android");
final View actionBarView = viewGroup.findViewById(resId);
if (actionBarView != null) {
actionBarView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// Remove the listener
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
actionBarView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
actionBarView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// Measure views
int[] location = new int[2];
actionBarView.getLocationOnScreen(location);
int[] logoLocation = new int[2];
logoView.getLocationOnScreen(logoLocation);
// Add top padding if necessary
if (location[1] > logoLocation[1]) {
logoView.setPadding(0, location[1] - logoLocation[1], 0, 0);
}
}
}
);
}
This worked on a wide range of devices (phones, big/small tablets - inc Kindle Fire HDX) running Android versions 4.0 up to 4.4.4 as well as Android L preview.

Categories