How to check programatically if all the Views fit inside the screen - android

I have a layout which is something like this:
LinearLayout (linearLayout)
'--TextView (textView1)
'--ImageView (imageView)
'--TextView (textView2)
textView1 changes its text sometimes and it can be long, so it leaves part of textView2 out of the screen. I want to prevent that, so I want to remove imageView from the layout whenever this happens. imageView may or may not be visible at the time when this is computed (maybe it was removed before when textView1 was edited previously).
This is what I have coded:
void changeText(String veryLongString){
textView1.setText(veryLongString);
int [] loc = new int [2];
textView2.getLocationOnScreen(loc);
int bottom = textView2.getMeasuredHeight() + loc[1];
if (imageView.getVisibility() == View.GONE)
bottom += imageView.getHeight();
if (bottom > linearLayout.getMeasuredHeight()){
imageView.setVisibility(View.GONE);
} else {
imageView.setVisibility(View.VISIBLE);
}
}
But for some reason this doesn't work as expected, because it seems as if changes in the position and height of the Views don't take place immediately. When I call getMeasuredHeight() and getLocationOnScreen() I get the values BEFORE the changes I have just made. The result that I get is that if I set a very large text imageView is not removed, but if I then set a short text, it is removed.
If there any other way to face this problem?

Even though I think that this is not the right approach (you can do all kinds of stuff in your XML so you don't have to meddle with Java code), here is a quick example of what you can do from Java (for example, in your onStart() method)
ViewGroup group = (ViewGroup) findViewById(R.id.myLayout);
int groupHeight = group.getHeight();
for (int i = 0; i < group.getChildCount(); i++) {
groupHeight -= group.getChildAt(i).getHeight();
if (groupHeight < 0) {
// they don't fit in the layout
myImageView.setVisibility(View.GONE);
}
}

Related

Setting margins programmatically wont let me reassign the value each time

I'm trying to set up a layout at runtime that alternates from having a button on the left side of the screen on then the right side. I have an arrayList of button strings and it iterates through, creating a button for each and then applying some styling. Almost all the styling works, except that the margins I'm using to push them to the side of the screen aren't alternating correctly. I'm trying to make the margin push either from the left or the right, but it seems like the buttons are staying within only one column.
Here's the code first of all:
LayoutParams noteStyle = new LayoutParams((int) getResources().getDimension(R.dimen.sticky_note_height),
(int) getResources().getDimension(R.dimen.sticky_note_width));
int margin = (int) getResources().getDimension(R.dimen.margin_huge);
layout = (LinearLayout) findViewById(R.id.note_layout);
int i = 0;
for (String note : notes){
Button btnTag;
if (i % 2 == 0){
btnTag = (Button) getLayoutInflater().inflate(R.layout.sticky_note_right, null);
noteStyle.setMargins(margin,0,0,0);
} else {
btnTag = (Button) getLayoutInflater().inflate(R.layout.sticky_note_left, null);
noteStyle.setMargins(0,0,margin,0);
}
btnTag.setLayoutParams(noteStyle);
btnTag.setText(note);
btnTag.setId(i);
layout.addView(btnTag);
((Button) findViewById(i)).setOnClickListener(this);
i++;
}
And here's a screenshot of how it comes out:
For some reason unknown to me, reusing the LayoutParams can cause goofy results. Instantiating them each time they are needed can help resolve this.
This means putting them inside the for loop, in this situation
for (String note : notes) {
LayoutParams noteStyle = new LayoutParams((int) getResources().getDimension(R.dimen.sticky_note_height),
(int) getResources().getDimension(R.dimen.sticky_note_width));

how to set textview dynamically according to numbers of strings

I am getting list of phone companies from web service and i have to set it to textview but the problem is i am not getting alignment as above image.How to achieve it.
From what I understand, you want to add text views one beside the other, but when they overflow (go out of the screen) the next text view should be placed in the next line.
Doing this is not trivial. Implementing something like this (optimally and correctly) requires understanding of how android draws views (onMeasure and onLayout). However if you do not care about efficiency that much (mainly because you are going to do it only for a small portion of the view) then here is my quick hack:
mContainer = (RelativeLayout) findViewById(R.id.container);
// first layout all the text views in a relative layout without any params set.
// this will let the system draw them independent of one another and calculate the
// width of each text view for us.
for (int i = 0; i < 10; i++) {
TextView tv = new TextView(getApplicationContext());
tv.setText("Text View " + i);
tv.setId(i+1);
tv.setPadding(10, 10, 20, 10);
mContainer.addView(tv);
}
// post a runnable on the layout which will do the layout again, but this time
// using the width of the individual text views, it will place them in correct position.
mContainer.post(new Runnable() {
#Override
public void run() {
int totalWidth = mContainer.getWidth();
// loop through each text view, and set its layout params
for (int i = 0; i < 10; i++) {
View child = mContainer.getChildAt(i);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// this text view can fit in the same row so lets place it relative to the previous one.
if(child.getWidth() < totalWidth) {
if(i > 0) { // i == 0 is in correct position
params.addRule(RelativeLayout.RIGHT_OF, mContainer.getChildAt(i-1).getId());
params.addRule(RelativeLayout.ALIGN_BOTTOM, mContainer.getChildAt(i-1).getId());
}
}
else {
// place it in the next row.
totalWidth = mContainer.getWidth();
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
params.addRule(RelativeLayout.BELOW, mContainer.getChildAt(i-1).getId());
}
child.setLayoutParams(params);
totalWidth = totalWidth - child.getWidth();
}
mContainer.requestLayout();
}
});
Basically, I let the system do the layout and measurement for me in the first round(s) of drawing. Then using the widths of each text view now available, I reset the layout params based on the wrapping logic and do the layout again.
Try it with text of different size, it will auto adjust. I would say this solution is pretty hacky but it works. If you are not satisfied with it take a look at this.
use
android:textAlignment="textStart"

Android how to calculate amount of elements on a page

Part of application I'm currently working on act exactly as android shell, shows several pages filled with icons with text labels. User could slide between pages to find needed element. I'm using PagerView with GridView in each page.
Content of each page should fit exactly of visible area, no scroll. The question how to calculate number of icons on each page?
The issue next, I can't call pagerView.getHeight(), I'll have 0 in result because actual layout calculation wasn't executed yet.
UPDATED:
Seems I wasn't able to describe my problem well, I'll try to provide more simple case, suppose I do have activity with status bar at the top and some button bar at the bottom, both fixed height. Whole remaining area in the middle is used by GridView.
Grid view should show rectangular icons, and what I need to calculate is how many icons it could show without scroll (because remaining icons will be shown on next activity).
You can try something like:
public int countElements(ViewGroup group) {
int count = 0;
for (int i = 0; i < group.getChildCount(); i++) {
View v = layout.getChildAt(i);
Class c = v.getClass();
if (c == *Icon*) {
count++;
}
}
return count;
}
In case you have inner views you can check if c is a GroupView and call the method recursively.
As for your second issue, try using this in onCreate:
private void calculateSize(int height, int width){
int rows = Math.floor(height/imageHeight);
int columns = Math.floor(width/imageWidth);
//do something with numbers
}
ViewTreeObserver vto = pagerView.getViewTreeObserver();
if(vto.isAlive()){
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
vto.removeGlobalOnLayoutListener(this);
calculateSize(gridView.getHeight(), gridView.getWidth());
}
});
}

Android TextView: can I stop text that is partially displayed from appearing

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!

Commonsware Drag Drop shrinks row height permanently

I did get the drag and drop working and the TouchListView class works great. However in my case I have rows of various height due to my adapter which contains an EditText that can have multiple lines. Therefore after I drop, all my rows convert to the tlv:normal_height which in my case is 74dip. This causes many rows to cut off all my text in the EditTexts. I tried re initializing my adapter (mylistview.setAdapter= myadapter), setting the ListView to GONE then VISIBLE and invalidateViews() but nothing seems to reset the ListView back to before I dragged, short of leaving the activity and coming back. What can be done here? -Thx
tlv:normal_height="74dip"
tlv:expanded_height="128dip"
There's little question that the original AOSP code was designed for uniform row heights, and the whole expanded_height construct was there to provide space for the user to visualize where the drop would occur.
One starting point would probably be to create a TouchListAdapter mixin interface (akin to SpinnerAdapter) where the normal_height and expanded_height would be retrieved dynamically from the adapter based on position as opposed to being fixed values declared in the layout. Whether that alone would be sufficient or more work would need to be done, I can't say.
If you come up with a solution, patches are welcome. Otherwise, I'll probably take a look at this sometime, but not very soon.
My apologies for not having a near-term silver bullet.
I edited the unExpandViews() method - called getAdapter() and for every item in my adapter set the height to 0 and then all the rows were set back to original. I also bypassed the delete part of the method since it did not apply to me.
private void unExpandViews(boolean deletion) {
int height_saved = 0;
CheckBoxifiedTextListAdapter cbla = (CheckBoxifiedTextListAdapter)getAdapter();
for (int i = 0;i < cbla.getCount(); i++)
{
//View v = getChildAt(i);
View v = cbla.getView(i, null, null);
//if (v == null)
//{
/*
if (deletion)
{
// HACK force update of mItemCount
int position = getFirstVisiblePosition();
int y = getChildAt(0).getTop();
setAdapter(getAdapter());
setSelectionFromTop(position, y);
// end hack
}
layoutChildren(); // force children to be recreated where needed
v = getChildAt(i);
if (v == null)
{
break;
}
height_saved = v.getHeight();
*/
//}
//else
//height_saved = v.getHeight();
if (isDraggableRow(v))
{
ViewGroup.LayoutParams params = v.getLayoutParams();
params.height = 0;
v.setLayoutParams(params);
v.setVisibility(View.VISIBLE);
}
}
}

Categories

Resources