I have a TableLayout that is focusable.
I dynamically add to TableRows to this TableLayout.
Although I can get the TableRow, and its contents (a few TextViews), to respond to Touch events, I can't get any of them to respond to Focus events.
Aside from setting a OnFocusChangeListener, is there anything else I need to do?
TableRow tableRow = new TableRow(this); // "this" is a valid Context...
tableRow.setFocusableInTouchMode(true);
tableLayout.addView(tableRow);
TextView someNameTextView = new TextView(this);
someNameTextView.setText("Foo");
someNameTextView.setFocusableInTouchMode(true);
tableRow.addView(someNameTextView);
tableRow.setOnFocusChangeListener(someRowFocusChangeListener);
someNameTextView.setOnFocusChangeListener(someRowFocusChangeListener);
Are you actually calling setFocusable (see http://developer.android.com/reference/android/view/View.html#setFocusable%28boolean%29) on the Views and TableRows?
I was using the wrong component for the UI interaction I was looking for.
Related
I'm confronted with the Problem of slow Performance...
Just take a case:
RelativeLayout myLayout = (RelativeLayout) findViewById(R.id.myrlLayout);
//Adding now 100 Buttons with 100 TextViews below each Button(just a example)
for(i=0;i<100;i++) {
Button btn = new Button(this);
btn.setId(i+1); //Should be a positive integer
//set LayoutParams for Button
RelativeLayout.Layoutparams btn_layoutparams = new RelativeLayout.LayoutParams....
....
myLayout.addView(btn, btn_layoutparams);
TextView mytv = new TextView(this);
mytv.setid(101+i);
//set LayoutParams for Button with referenced to the Button(because the Textview Needs to be
of Button)
....
myLayout.addView(mytv, tv-layoutparams);
}
Regarding to the high amount of Views programmatically created, my app starts really slow...
I think it's not because of creating a new View, but because of setting the LayoutParamters each time for the view. I can't find a Workaround because my LayoutParams for the TextView for example Need to reference to the button created before. Due to that i'm not really able to create a XML-layout-file or XML-style-file because i can't reference the tv's layoutparameters anchor in the XML-file to the button which does not exist at the Moment. At least i didn't find a way. I hope somebody got an idea how to appreciable improve the Performance when creating such a amount of views at runtime. Every advise is welcome.
Update regarding answere from rom4ek
The Problem is, that i Need to calculate how much views can i add per row before the Screen-width is fully used. That means i Need second LayoutParams to add the next Button below the first Button from the first row. And i also Need to reference to the img-Button added before in the LayoutParams.. so it's not possible to reference LayoutParams to a Button which doesn't exist before the for-loop.Maybe i completely miss something.. Do you have an idea/solution? Thank you for your respond.
If you're setting the same LayoutParams, what if you move RelativeLayout.Layoutparams btn_layoutparams = new RelativeLayout.LayoutParams.... before the cycle? So you will initialize it one time, and then no need to create new LayoutParams every step.
I would like to create a method which returns a RelativeLayout created dynamically. To be clear, let's use this simplified example:
private RelativeLayout createLayout() {
RelativeLayout layout = new RelativeLayout(activity);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
layout.setLayoutParams(params);
TextView tv1 = new TextView(activity);
tv1.setText("Text 1");
TextView tv2 = new TextView(activity);
tv2.setText("Text 2");
TextView tv3 = new TextView(activity);
tv3.setText("Text 3");
layout.addView(tv1);
layout.addView(tv2);
layout.addView(tv3);
return layout;
}
Now I want to position these TextViews relatively to each other. For that I have the idea to use a LayoutParams with the addRule method.
But this method requires an ID, e.g. addRule(RelativeLayout.BELOW, tv2Id). It means that I have to set an ID for each TextViews.
My problem is that the createLayout method will be called several times, so the question is:
Do I have to set different IDs for the TextViews each time the method is called in order to avoid conflicts ? If so, how can I do that ?
Most generally, Is there a better solution for doing it ?
EDIT
The idea behind this is to have a kind of ListView, where each item contains a Map (that can be shown or hidden).
Problem: the Map can't be scroll if it is inside a ListView (at least I did not manage to do that).
For that, I have decided to use a ScrollView and a LinearLayout to copy the behaviour of a ListView. This way the Map can be scrolled correctly and now, all I have to do is to create the items dynamically
ID's don't have to be unique. As you can see from this extract
setId (int id)
Sets the identifier for this view. The identifier does not have to be unique in this view's hierarchy. The identifier should be a positive number.
But like you said, if you want to avoid conflict then you have to find a way to generate unique identifiers for each view.
Frankly, IMO I don't think it matters much the value of the ID. You can use 10, 20, 30. Just make sure you can have access to them anytime you need it, possible using a static final variable.
You asked if there is a better solution, yes there is. The most preferred way is to inflate an xml layout.
I am having a little bit of trouble making the table look like I intend to.
These are a few questions, but since they all refer to the picture below and the details I provide I thought they should all be in a single post.
Here is what I achieved so far:
The header row contains one element of type Button.
TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
Button bt = new Button(getContext());
bt.setText("Column1");
mHeader.addView(bt, params);
mHeader.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT));
addView(mHeader);
The rest of the table is poulated like this:
(Messagerow extends TableRow and has a TextView member)
for(int i = 0; i < 100; i++) {
MessageRow mr = new MessageRow(getContext());
// stuff to set the TexView text and color
mr.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT));
this.addView(mr);
}
1. How can I make the header row height be more like the rows?
2. How can I make the button occupy the full width of the row?
If the table is empty, no text rows just header, then the button matches the row width. As soon as I add a row of text, the column width is adapted but the button width is not.
3. How can I make the row fill the screen width? (MATCH_PARENT does not do it)
4. How can I draw a thin line between the table rows?
I tried to override the onDraw() function on MessageRow, but it never gets called, not even once.
Don't get me wrong. I am not asking that you do my work for me. These are issues I tried to solve by myself and googled them and read similar posts, but did not find an answer.Note: I find that UI design in Javascript for Android lacks clear control and clear documentation over all these little details.
Edit
This is how I create the table:
TableLayout mTable = new TableLayout(this);
HorizontalScrollView hview = (HorizontalScrollView) findViewById(R.id.hscroll);
populate(mTable);
mTable.setLayoutParams(new TableLayout.LayoutParams( TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
mTable.setBackgroundColor(Color.WHITE);
hview.addView(mTable);
How can I make the header row height be more like the rows?
Using the default Button there isn't much to do. The Button uses a nine-patch image that has some space between the button's text and the borders that you see. You could use a smaller font but that you'll probably look ugly. Another thing to try is using your own background for the Button and get rid of the default extra space(of the default nine-patch image) so the final height is near the height of the text from the TextViews. Or try to enforce a standard height for all rows using a fixed value.
How can I make the button occupy the full width of the row?
I think that you have more then one TextView in MessageRow so when you add the Button it moves to the first column(corresponding to the first TextView). If this is the case, make your Button span across the number of columns representing the number of TextViews in MessageRow:
TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
params.span = 3; // if you have 3 `TextView` in the MessageRow
Button bt = new Button(getContext());
bt.setText("Column1");
mHeader.addView(bt, params);
If this is not the case add more details.
How can I make the row fill the screen width? (MATCH_PARENT does not do it)
As I said on one of your previous questions, I don't know why that happens(but I gave you some solutions there to overcome this issue). Also:
mHeader and the other MessageRow are children of a Tablelayout and the correct LayoutParams to use on them is the LayoutParams of the parent: TableLayout.LayoutParams and not TableRow.LayoutParams.
You add some TextView in the MessageRow(from what I seen in your previous questions), add those child views with TableRow.LayoutParams to MessageRow.
You use only WRAP_CONTENT for your LayoutParams everywhere in your code, you might want to set the width(the first parameter in the constructor) to FILL_PARENT/MATCH_PARENT
How can I draw a thin line between the table rows?
You could use a simple View that will act as a separator:
for(int i = 0; i < 100; i++) {
MessageRow mr = new MessageRow(getContext());
// stuff to set the TexView text and color
mr.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
this.addView(mr);
View separator = new View(getContext());
separator.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.FILL_PARENT, 3)));
separator.setBackgroundColor(Color.RED);
this.addView(separator);
}
Because you have 100 rows you could try to set a drawable with a separator line as the background for theTableRow(header and MessageRow) instead of the above method that adds another 100 Views to the layout.
Extra Note:
You have a lot of views to add to a single activity layout, you are talking about 100 rows, and if your MessageRow is more complex than a simple TextView(and I think it is) you could get in some performances problems. I suggest you take a look at the wonderful ListView widget.
Don't have a programming environment here, but I'll try and answer some of your questions.
The reason your header row (button) is taller than your test based rows is because the button requires more space and the row accomodates it. The default button has padding on both the top/bottom of the text. I think your best option is to create your own button, which gives you the additional benefit of being able to control the look and feel. It seems like other people have had this issue before: Can't get rid of bottom padding on button
Your button is set to wrap_content which means it won't be any bigger than it needs to be (It will grow/shrink so it can fit the text "Column1" or whatever you put there). Instead of making the Button WRAP, I suspect you'll need to make it FILL_PARENT.
It's not your Table Row that needs to fill the screen width, it's your table that needs to fill the screen. Wherever you define your table, it's probably set to WRAP_CONTENT for the Horizontal dimension. Set it to FILL_PARENT and your table should expand to the full width of whatever it's container is (In this case, it should expand the full width of the screen)
There are probably several different ways you can do this. One method I used somewhat recently is to utilize the View tag which essentially looks like a horizontal bar across the screen. Below is a link to how to implement it.
http://sonnygill.net/android/horizontal-rule/
I created on loop 5 TextViews, set to them some text and added they to LinearLayout.
After that I need to change text in them. I want to delete all of them and create new one on loop again. But before TextView deleting I must to be sure that its exists. How to do it?
for(int i=0; i<5; i++){
TextView tv = new TextView(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(params);
tv.setId(i);
tv.setText("some data");
ll.addView(tv);
}
Thank you for help and your time!
If you want to delete all of them then just perform ll.removeAllViews().
You should keep a reference to each of the text views you create if you want to remove them.
If I understand your question correctly, simply create an array of TextViews with 5 elements and run the loop to do what you want with them.
To "delete" them you can call:
tv[i].setVisibility(View.GONE);
To change text and re-add them:
tv[i].setText("New Text");
tv[i].setVisibility(View.VISIBLE);
Better solution is to hold references to your TextViews in a list, so you can interact with them later on after you've created them. Otherwise you won't be able to see the objects.
Suppose I have a view inside TableLayout, like this:
TableLayout tableLayout;
View view = (View)tableLayout.findViewById(R.id.control);
How can I find out the view's row/column within the TableLayout?
A view that is within a TableRow should have TableRow.LayoutParams as its LayoutParams. From that you can get the layout_column.
The row seems to be a bit harder. I'd expect the TableLayout.LayoutParams (gotten from the TableRow) to have that information, but it doesn't seem to. You could try using tableLayout.getIndexOfChild(rowView).
There is no such getIndexOfChild(view) in TableLayout class, but a indexOfChild()!
While designing the tablerow in code, you can use setTag() to set it to row number. Later it can be retrieved by tableRow.getTag(). In xml you may use android:tag="2".