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.
Related
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)
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());
I am using JavaFX8.
I have a tree view and it contains some objects.
The tree view gets displayed with all the nodes expanded.
I would like to have a default item on the treeview selected when the UI startsup.
I have tried the following but it doesn't work.
rootNode.setExpanded(true);
popupTree.setShowRoot(false);
popupTree.setRoot(rootNode);
popupTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
popupTree.requestFocus();
popupTree.getSelectionModel().select(new TreeItem<FinancialAccount>(selectedAccount));
popupTree.getFocusModel().focus(popupTree.getSelectionModel().getSelectedIndex());
If I replace the code with a static integer value like this
popupTree.requestFocus();
popupTree.getSelectionModel().select(5);
popupTree.getFocusModel().focus(5);
This selects the 5th item on the tree and its highlighted on the UI.
To determine the index of the object in the tree, I am using the methods in my first snippet, they always return -1
Obviously the select(object) method in the SelectionModel class is not correctly evaluating the passed object. I tried overriding the equals method in my FinancialAccount Object but it doesn't make a difference.
Any thoughts on how to get this working
I have a question about GUI design, specifically with Java Swing and creating clean separation between presentation and model.
It's a bit difficult to describe, but essentially we have lots of reference data in our system (i.e. that would correspond to lookup tables in the DB). We want people to be able to edit them all from one screen.
So, in an ideal world what we'd like is a combo box in the top-left corner with a list of 'types' of reference data (so each corresponding to one table in the DB).
Then, when selected, a list of the data is populated below, also a filter (or search box). When one of these items is selected, the panel to the right is activated which will allow the actual data to be edited.
Now, here's the problem: each type of data we need to edit is different, so it has different fields etc. We could go with a generic solution but I'm not really a fan of them - there are lots of different validation rules for each etc, even for different clients, and it would be a nightmare to manage.
We're using the Presentation Model pattern to achieve some degree of separation between GUI code and the model but I can't think of a clean way of doing this which doesn't somehow blur the line of responsibilities a bit.
What are the ways you have solved problems like this?
[Note: apologies for the long question, hope it's understandable, I can re-phrase if necessary]
You could use the Factory Pattern to create a UI widget for the element that you are selecting. You could also use it to create a validation rule object depending on the type. This would give you some of the flexibility you desire.
So you can have something like:
IWidget widget = UIFactory.createFor(myObject.getType())
That can be invoked on the selection event to create the right widget to edit the selected element.
The IWidget could have methods such as:
validateData()
refreshData()
setDataElement(IDataElement element)
That would allow you to treat all UI widgets generically, but still have a special UI widget for each element type. I am assuming that the elements that you are selecting from the table all implement some IDataElement interface that contains the getType() method.
I used this solution tied together with the Eclipse Extension mechanism to plug-in new UI elements into my "base" solution, to have an extensible core and a high level of reuse. You could achieve something similar by injecting types and widgets into your factory, either manually or with Spring.
If you dont want to go down the generic path, you could have your model hold a mapping of combobox item -> panel name for use with a CardLayout. You could then create custom panels for the editing each of the reference data types. When the combo box selection is changed, you can save the current state in your model, request the panel name of the current selection, prepare your next panel for display and then have your CardLayout show it.
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.