How to add ID to programmed layout item (android) in JAVA - java

I am adding multiple elements to layout in Java code. For example java coded before imageview to known layout with some layoutparams.
layout.addView(imageview, layoutparams);
I asume that I can't do it in XML because I don't know how many elements will be added (determined by user).
I need to set and know IDs to those added elements so I can refer to them later on.
What I need is something like (before adding):
imageview.setId(??);
Is this a good method to use? If so how do I use it?
My main consern is that I am not sure how R.id works exactly.
Can I for example make those IDs like 100001, 100002, 100003... ? Won't I override any?
I will store those IDs in an list/array for use later in code.
public static int generateViewId ()
Added in API level 17 Generate a value suitable for use in setId(int).
This value will not collide with ID values generated at build time by
aapt for R.id.
What if it will colide during runtime because of multiple methods adding elements. Are there any sql-like transactions?
BTW: Going for API17 isn't exactly what I want. Slightly over 50% of the market.

If you need to get a reference to a certain View that is added dynamically to a bunch of other similar Views, you might want to use a loop similar to the one below:
for(int i = 0; i < parent.getChildCount(): i++) {
View view = parent.getChildAt(i);
}
If you need more control than that then you may want to check out the View.setTag() method. Using this, you can create a unique tag for each View and retrieve it later on in a loop.
final ImageView imageView = (ImageView) findViewById(R.id.imageview);
imageView.setTag("I'm a tag!");
for(int i = 0; i < parent.getChildCount(): i++) {
View view = parent.getChildAt(i);
if(view != null && view.getTag() == "I'm a tag!") {
// Do something with the View
}
}
Although the code above should work, I might suggest approaching the issue from a different angle depending on what you intend to do with the Views.

It is needed the ID to be unique for the findViewById method to work properly. However there is no guarantee that the ID is unique in the context of a ViewGroup. If you use the xml way to generate a layout, the android build tools generate unique IDs for all elements but if you create and add them manually to the container, the ID is not generated. If there are multiple views with equal IDs, the findViewById method will return the first view from the tree view structure with ID equal to the given one.
You can use safely the generateViewId() method. There is no need to synchronize its usage (transactions as you call them) because the android guys have already done this for you. You can use it safely without worrying for duplicate ids.
I hope this will help you understand the concept and the need of the IDs :)

AFAIK, imageview.setId(); won't harm your resource identification through getting this source from R file, but in your case, I'd prefer use tags:
imageview.setTag(100001);
and to get it:
int id = Integer.parseInt(imageview.getTag().toString().trim());
And if you are already using the view tag somehow, you can give it another tag with a key like your app-name:
imageview.setTag(R.string.app_name, 100001);
and to get the id:
int id = Integer.parseInt(imageview.getTag(R.string.app_name).toString().trim());

Related

Can Lazy Column live inside another Lazy Column?

I'm starting using Jetpack compose and i'm facing some issues with Lazy Column.
The problem is that i want to make a list that contains another list inside every root item (such as a card that containt another list inside).
Unfortunately, when i run the following code (below the snippet that resume what i'm trying to do).
I catch the exception:
java.lang.IllegalStateException: Vertically scrollable component was measured with an infinity maximum height constraints, which is disallowed. One of the common reasons is nesting layouts like LazyColumn and Column(Modifier.verticalScroll()). If you want to add a header before the list of items please add a header as a separate item() before the main items() inside the LazyColumn scope. There are could be other reasons for this to happen: your ComposeView was added into a LinearLayout with some weight, you applied Modifier.wrapContentSize(unbounded = true) or wrote a custom layout. Please try to remove the source of infinite constraints in the hierarchy above the scrolling container.
Code:
LazyColumn(modifier = Modifier.wrapContentHeight()) {
items(list.value) {
item -> LazyColumn(modifier = Modifier.wrapContentHeight()) {
//some Text
}
}
}
I don't need the nested Lazy Column to be scrollable, so i'm wondering if for this purpose there is another element to use instead of LazyColumn, or i'm making some other mistake.
I've also tried to put in item{} block other layout elements, as suggested by the Exception, but with the same result.
No, unfortunately, nesting scrollable composables in the same direction is not allowed.
It's not supported in jetpack compose, but I think it should be supported because many use cases need that. e.g e-commerce applications,food delivery (like DoorDash)

How to hide a field in the scaffolding view but still enforce it when adding a new row in Grails?

I have a simple Grails app and I'd like to hide some columns in the general scaffolding view, prevent the user from editing them but still enforce specifying them when adding a new item. I looked at the possible constraints but it looks like none quite fit the bill:
column display: false hides the column from the view but hides it everywhere, new item adding view included
column editable: false does prevent the column from being edited in the edit view but you can't define it when adding a new item either (+ it's not hidden at all)
How should I tackle it, then? I'd like to still be able to take advantage of the dynamic scaffolding capabilities but seems like there's no way to specify the column to not show up in the general view and yet still enforce it when adding something new. Is there any way to specify which view to hide it from, instead of going all or nothing?
Let's say we have the following domain:
class Thing {
String userName
String firstName
Integer userId
static constraints = {}
}
And we don't want the userName to be editable on the edit view, you create the following directory...
\views\thing\edit\userName
Then add a file named _widget.gsp to the directory above with the following contents...
${value}
Which will show the text value only of the userName.
As for the index view, I'm not 100% if you can hide the field easily.
I know the fields plugin will render the first 7 fields in the table as determined by the order in the domain class definition. So, if you have > 7 fields you could give the one you want hidden at an order > 7, clearly there are massive limitations here, you may not even have 8 fields or you may want more than one field hidden...
You can do as above for the list view but create a directory named \views\thing\index\userName then create a file named _displayWidget.gsp with nothing in it or maybe some text like 'Hidden', this will still render the column but show nothing as the value or whatever text you add to the file, again not great.

Adding data to a tree-view-list

I've started to use the tree-view-list to show my data. The tree-view-list can be found here:
http://code.google.com/p/tree-view-list-android/
The code that adds text to the tree view line is this:
private String getDescription(final long id) {
final Integer[] hierarchy = getManager().getHierarchyDescription(id);
return "Node " + id + Arrays.asList(hierarchy);
}
in the SimpleStandardAdapter.java file. The data shown in the demo is based on the row id and nothing external to the treeview.
How would I go about adding text for a line of the tree that is external to the tree view?
For example, an array of data that is filled at run time.
The adapter (pretty much as any other adapter) build views from the data provided by model. The AbstractTreeViewAdapter is written in the way that it provides implementation for a wrapped view - so it will either create a new child view (abstract getNewChildView) or reuse one (updateView) - and then adds it as a sub-view to cell item with the right padding/margin etc. (this provides automatically indenting in the tree).
So whenever you need to display something in your own way as a tree cell, you should build your own adapter (you can either extend SimpleStandardAdapter or build your own Adapter from the scratch in similar way to SimpleStandardAdapter and return appropriate view that you want to display as result of getNewChildView and updateView methods.
Both methods get TreeNodeInfo treeNodeInfo as parameter, so you can figure out which node of the tree you are about to render. The type is - unfortunately - not changeable, I tried at the beginning to make a generic solution where you will be able to use any object type but failed at that, and it has to be Long. Probably it should be changed to reflect that.
So you will get the Long id from TreeNodeInfo that will identify the node, and the best way to use it is to use the Long value as index to some Map where you will keep reference to your node's object(s) and this way to know which data to render.
I hope it helps.

How to translate ListView texts?

My android application includes ListView binded with SimpleCursorAdapter to the database. This database contains column, which contains data like
somenameofrow
anothername
thirdname
However instead of directly displaying these texts in the ListView, I would like to read according texts (actually - translations) from the Android resources.
How should I do it?
I think that I can use setViewValue for the same, name in the code below is TextView item, which displays my text:
case R.id.name:
TextView elName = (TextView) view;
elName.setText(getApplicationContext().getString(R.string.));
return true;
I am not sure how to understand what is correct id of the resource I am looking for (probably, cursor.getString(columnIndex) or elName.getText()) and how to get the value?
Upd. What if I exclude names from the database and will use ids instead. Will it help?
If you read the android guide ListView tutorial, you will find:
Note that using a hard-coded string array is not the best design practice. One is used in this tutorial for simplicity, in order to demonstrate the ListView widget. The better practice is to reference a string array defined by an external resource, such as with a resource in your project res/values/strings.xml file
Simply create different string-arrays items in res/values-XX, where XX are the locales you want to translate.
See the dev guide for more details about resources and i18n: http://developer.android.com/guide/topics/resources/localization.html
No you can't, since id's are generated in some basically sem-random way during compilation, so you can't be sure which id will have specific String resource.
I would suggest to use translation from DB or you can read translations from assets

In an ExpandableListView, how can I show one additional line at the end of the child results?

I have created a custom ExpandableListAdapter and everything works properly. What I'd like to be able to do is in each of the groups add a different type of child to the end. I have tried adding 1 to the getChildrenCount() number and then testing isLastChild in the getChildView() method, but that doesn't seem to work.
If a group has three children what I have working looks like this:
Group
NormalChild
NormalChild
NormalChild
But I'd really like something like this:
Group
NormalChild
NormalChild
NormalChild
AlternateChild
The idea being that the AlternateChild could be a link to more info about the group. Any Ideas?
EDIT:
ListView has addFooterView() which will allow you to add a footer to a whole ListView... wonder how to add them to the ExpandableListView's children, or if it's even possible
Perhaps you could try a slightly different approach.
Rather than trying to add an extra item to the ListView directly, maybe try adding an 'AlternateChild' object to the underlying data source using a 'isAlternateChild' flag (or subclassing NormalChild or creating an IChild interface that you extend with NormalChild and AlternateChild.
Then within getChildView you can check to see if the object being displayed within the view is normal or alternate and create or populate the appropriate View-type accordingly.
By adding your extra object to the underlying data/list directly you can let the ExtendedListView do its thing normally. As an added bonus this means you can make the AlternateChild data dynamic and easily make changes to the data displayed in the view by modifying the corresponding object.
In my opinion this is a better answer
I was trying to put an action bar below the last child of each group if needed, this works very nice for that. Since the action bar has nothing to do with my data, I couldn't use the same object.

Categories