Currently I have several views and the screen is divided into two section
Example:
text1 image1
text2
text3
text4
The problem is , if the image1 is tall , it will overlap the textview on left side, so I use to left of to force the textview width not exceed the imageview's left.
android:layout_toLeftOf="#id/imageView1"
however, every textview are aligned to left of the imageview as I do not know the height of it until the view is created . And I want all textview below the baseline of imageview remove the layout rules of android:layout_toLeftOf
So I search for the solution and find two ways ?
1.onWindowFocusChanged
2.getViewTreeObserver().addOnGlobalLayoutListener
Both can get the yaxis of the view.
The problems are:
1. what is the difference between them ?
2. I tried approach 2 , but it is not working, how to fix it?
Code:
image.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
ImgY = image.getY();
}
});
lng.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (lng.getY() > ImgY) {
lng.removeRule(RelativeLayout.LEFT_OF);
}
}
});
The error is I would like to set a global value to store the y of imageview, but it warns The final local variable ImgY cannot be assigned, since it is defined in an enclosing type Also, the removeRule function return
The method removeRule(int) is undefined for the type TextView
Thanks a lot for helping.
Related
I need to position a TextView the way its baseline is 20dp from the bottom of the container.
How can I achieve this?
The layout with bottom margin or padding produces the same result.
I would like to make the text 'sit' on the purple line.
When I write 'sit' I mean, the 'wert' should touch the line, not 'q...y'.
The padding / margin is equal to the purple square size:
If you still need it, I wrote custom method, to not create lots of custom views. It works for me with TextView:
public static void applyExistingBotMarginFromBaseline(View view) {
final int baseline = view.getBaseline();
final int height = view.getHeight();
final ViewGroup.MarginLayoutParams marginLayoutParams;
try {
marginLayoutParams = ((ViewGroup.MarginLayoutParams) view.getLayoutParams());
} catch (ClassCastException e) {
throw new IllegalArgumentException("Applying margins on a view with wrong layout params.");
}
final int baselineMarginValue = baseline + marginLayoutParams.bottomMargin;
marginLayoutParams.bottomMargin = baselineMarginValue - height;
view.setLayoutParams(marginLayoutParams);
}
You can apply it when view is measured already, so like this:
final TextView title = (TextView) findViewById(R.id.title);
title.post(new Runnable() {
#Override public void run() {
Utils.applyExistingBotMarginFromBaseline(title);
}
});
Also you can use databinding framework and write your own custom BindingAdapter with a bit customized method, to use it from xml.
Your problem is not the padding/margin referenced to the parent, I think is about your font, I recommend you to change the fontFamily:"yourStyle"
even worst you have to re-difine your own font style which is explained here Custom fonts and XML layouts (Android) or Set specific font in a styles.xml
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 want to get the height or at least the line count of my text view programatically, but the log says 0. What is wrong ? Here is my code :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_off);
titreOff = (TextView) findViewById(R.id.offTitre);
titreOff.setText("some text"); // displays 2 lines of text with the font size I used
System.out.println(titreOff.getLineCount() + " and " + titreOff.getHeight());
}
Thanks for your advices
In onCreate(), your TextView has not had a layout pass and so currently has a zero width and height. There are a few solutions if you would like to get the dimensions of your TextView:
Add an OnGlobalLayoutListener to your TextView's ViewTreeObserver. (e.g. titreOff.getViewTreeObserver().addOnGlobalLayoutListener(listener) and handle your changes there).
Override TextView and handle your special case by overriding onLayout() (in which you will have the dimensions of your TextView as parameters.
Alternatively, what is the end goal of your measurements? If you can give some specifics, there may be an easier solution than any of this.
Your app doesn't know the actual size of TextView while doing onCreate() method. The solution is to move your output here:
onWindowFocusChanged(boolean hasFocus) {
if (!hasFocus) {
titreOff = (TextView) findViewById(R.id.offTitre);
System.out.println(titreOff.getLineCount() +
" and " + titreOff.getHeight());
}
}
setText() doesn't immediately update the TextView, it just invalidates it. The new text will be set only on the next repaint. If you try to get the height before you will get the old one.
Instead, you should subclass TextView, override onSizeChanged() and you will be notified each time the size of your TextView changed.
I am trying to scale the image in my linear layout to fill the available space, but I don't understand the values I'm getting for the widths of the layout. Here's the relevant part of my main.xml layout file:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LeftButtonsLayout"
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="10"
android:orientation="vertical" >
<TextView
android:id="#+id/Jump"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/jump"
android:textStyle="bold"
android:padding="5dip"
/>
<ImageView
android:id="#+id/JumpButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/jump"
android:contentDescription="#string/jump"
android:padding="5dip"
/>
<LinearLayout
Here's the onCreate() method of my activity, which has a debug print:
public void onCreate (Bundle savedInstanceState) {
setContentView(R.layout.main);
LinearLayout leftButtonsLayout = (LinearLayout) findViewById(R.id.LeftButtonsLayout);
imageView = (ImageView) findViewById(R.id.ResetButton);
Log.d("DEBUG", CLASS_NAME + "scaleLeftButtonsLayoutContents: \n" +
"linear layout height: " + leftButtonsLayout.getHeight() + "\n" +
"text height: " + ((TextView)findViewById(R.id.Jump)).getHeight() + "\n" +
"image height: " + imageView.getLayoutParams().height);
}
1) If I place the setContentVew() call after the Log.d() debug print, I get a Null Pointer Exception. Why? Is memory not allocated for the LinearLayout before it's used on the view?
2) The prints I see are:
linear layout height: 0
text height: 0
image height: -2
What am I doing wrong here? I expected to see sane values here, since I can see the imageView on the device screen.
3) I was planning to scale the image using:
imageView.getLayoutParams().height = newHeight. Is that right to do? Will doing this automatically update the imageView on the screen, or will I have to do a setContentView() again?
Thanks in advance for your help.
UPDATE
Thanks for your answers everyone. I've overridden the onWindowFocusChanged() method of my activity, but when I check the size of the nested ImageView below, it's reported as -2. Resizing it works, but I'm curious why it's -2 when it should've had a sane value. My code's as follows:
#Override
public void onWindowFocusChanged (boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
scaleLeftButtonsLayoutContents();
}
private void scaleLeftButtonsLayoutContents () {
LinearLayout leftButtonsLayout = (LinearLayout)findViewById(R.id.LeftButtonsLayout);
imageView = (ImageView) findViewById(R.id.JumpButton);
Log.d("TAG", CLASS_NAME + "JumpButton.height " + imageView.getLayoutParams().height);
imageView.getLayoutParams().height = verticalSpaceAvailable;
imageView.getLayoutParams().width = verticalSpaceAvailable;
leftButtonsLayout.requestLayout();
}
This produces the print:
JumpButton.height -2
The resize produces a sane image, but why is the initial height -2?
To answer your points,
1) It is because you haven't initailaized your Button or ImageView. Since you call your Log before doing this, obviously the Button and ImageView are null and hence you get the exception.
2)And initializing doesn't mean that your view are completely drawn to provide you with width and height. So you have to provide the time to get itself drawn. But unfortuanately we don't know the exact time it takes to get drawn. So Android provides this method,
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
// which gets called when your view is drawn.
}
Just now answered a similar question here.
So what you have to do is, add your Log inside this method in your Activity and then check the resulting width and height.
3) To answer your third question, you definitely should not call setContentView() once again, which might throw you some other exception. But when considering scaling you might make use of some bitmaps to do this.
Here are some answers for you:
1) If you place the setContentView after calling view.getHeight() you will get null pointer because that view is not set on the Activity content therefore you can't get a reference to it before setting it to the content of the Activity
2) You see that because the view doesn't had time to layout.. if you want to see the height/width of a view it's better to use a ViewTreeObserver listener like this:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
/* don't forget to remove the listener after you use it once */
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
Log.d("MY VIEW WIDTH","width:"+view.getWidth());
}
});
3) After you set the layout params of a view don't forget to call view.requestLayout() to make sure that your view will refresh. You don't have to call setContentView() again.
EDIT: Also the width of your LinearLayout has to be at least wrap_content if not fill_parent or a value greater than 0 if you want to see the child views of the Linear Layout..
You cannot do like this. Because the linearlayout is the main container of your activity. You cannot provide android:layout_weight="10" and android:layout_width="0dip" to the main layout. create one Linear layout outside this android:id="#+id/LeftButtonsLayout" and give the layout height and width to fill_parent or match_parent. This will work in your case.
And one more thing, You cannot allow to call elements of layout before the setContentView.
i have a problem with the TextSwitcher.
In my app i have 3 Textswitcher with wrap_content (width and higth) inside an LinearLayout!
Each TextSwitcher is declared with an in and outAnimation.
My problem:
When the text is switch the first time, i have spaces between the elements!
like: 1.23 45 678
but it has to: 1.2345678 without spaces
when the text switches the second or 3. time the spaces are gone.
I cant imagine why there are spaces?? There is no other Element, no padding, no margin.
maybie the reason is the ViewFactory:
ViewFactory for the middle part switche:
public View makeView() {
TextView t = new TextView(SmartTraderFxTrading.this);
t.setTextColor(Color.BLACK);
t.setTypeface(null, Typeface.BOLD);
t.setTextSize(26f);
return t;
}
an for the switcher left and right from the middle part:
public View makeView() {
TextView t = new TextView(this);
t.setTextColor(Color.DKGRAY);
t.setTextSize(20f);
return t;
}
but i can change everything, the spaces are always there after the first switch, and also maybie after the second.
Is it a bug? Please help!
EDIT:
Problem solved!
The problem is that the Text befor has more digits as after! So the TextSwitcher has a larger width and after redraw of the activitie it wraps the TS.