How to remove focus from LWUIT Textfield and resize Form correctly when Virtual Keyboard hides? - java-me

I'm facing a problem with the LWUIT's Textfield.
In some of my Forms I display a CategoryBar, while in others I hide it.
In some of the Forms I have Textfields, the problem presents itself when I focus on one and make the Virtual Keyboard (VKB) to appear. When the VKB appears, the screen components resize themselves to adjust to the Textfield to be visible while text is entered, but when I hide the VKB, either through the back button or the return key on the VKB, the Textfield remains with the focus, not only that, when the screen components resize themselves, the current visible Form resizes itself as if there was no CategoryBar present, so any components that are at the bottom of the Form are hidden by the CategoryBar.
This is fixed by displaying another Form (this includes PopupChoiceGroup and DatePicker) and then going back to the Form that is covered by the CategoryBar.
In other Forms where no CategoryBar is visible, sometimes the resizing when the VKB is shown causes the Forms to resize themselves as if the CategoryBar was visible, making it possible to interact with it when it shouldn't be available.
How can I make sure the focus is completely lost on the Textfield? Also, how to make sure a Form is resized correctly whether a CategoryBar is visible or not?
EDIT
I've been digging through the class reference for TextField, Form and VKB, in the later I found a method called autoAdjust which according to documentation:
Auto adjust size of the dialog. This method is triggered from a
sizeChanged event.
The method sizeChanged sounded like something I should check and in the Form's reference the description for this method is:
This method is only invoked when the underlying canvas for the form
gets a size changed event. This method will trigger a relayout of the
Form. This method will get the callback only if this Form is the
Current Form
This method seemed like the callback for resizing I was looking for, so I overrode it and placed a NotificatioBar to be displayed with the width and height values sent when the method was called.
What I found after testing this on my device was that when the Form was being resized after the VKB was shown or hidden, the height value sometimes instead of being 270 (the height for the Form when the CategoryBar is being displayed) it was sent as 320 (the full screen height, as if no CategoryBar was being displayed).
So far I haven't been able to understand why would the Form ignores the fact that the CategoryBar is being displayed or not when resizing the itself.
I tried to change the Form height inside its sizeChanged method but the Form wasn't affected by it. It seems to me what I have to modify is the canvas where the Form is being drawn, but I don't really know for sure since the canvas is hidden in LWUIT.
Could it be the canvas where my Form is being drawn is the one at fault? What is provoking this behaviour?

At the moment I found a workaround to avoid having my Components hidden by the CategoyBar because the Form resized wrongly after the VKB hid, for the scenario in which the Form resizes wrongly and displays the CategoryBar (which I don't know why is visible if I'm calling to its setVisibility method and passing false).
First I overrode the sizeChanged method:
protected void sizeChanged(int w, int h){
if(h > 270){
mainContainer.getStyle().setMargin(Component.BOTTOM, 50);
}
else{
mainContainer.getStyle().setMargin(Component.BOTTOM, 0);
}
}
I check the height value, if the value is greater than the expected height when the CategoryBar is being displayed then I set the bottom of my Container to 50, so it'll be visible.
But this wasn't enough because if I show again the same form and it resizes correctly then the Container will remain with a bottom of 50. So I overrode the onShow method too:
protected void onShow(){
int containerBottom = mainContainer.getStyle().getMargin(Component.BOTTOM);
if(this.getHeight() == 270 && containerBottom == 50){
mainContainer.getStyle().setMargin(Component.BOTTOM, 0);
}
}
I had to make sure if the height was 270 and my Container's bottom was 50 then the Container's bottom should be 0.
Since I haven't found a way to avoid having my Form to resize and show the CategoryBar when it shouldn't be displayed at all, I don't consider myself with a full answer. Will update if I find a workaround for this.
EDIT
I tried with explicitly setting the shown/hidden status by calling the setVisibility method inside the onShow method of every Form I have. So far I've been able to avoid the visual problems I experienced previously. I'm not sure if this problem was due to LWUIT or due to J2ME restrictions but this is how I worked around it.

Related

UILabel not wrapping in UITableView until device rotate (iOS8)

I have a custom MvxTableViewCell that is associated with an MvxStandardTableViewSource. That Source is then applied to a UITableView. The custom table cell is defined without any Storyboard or NIB. It is laid out in code and uses AutoLayout.
this.searchResultsTable = new UITableView();
this.searchResultsTable.AccessibilityIdentifier = "SearchView_SearchResultsTable";
this.searchResultsTable.TranslatesAutoresizingMaskIntoConstraints = false;
this.searchResultsTable.RowHeight = UITableView.AutomaticDimension;
this.searchResultsTable.EstimatedRowHeight = 44.0f;
this.searchResultsTable.RegisterClassForCellReuse(typeof(CustomerItemCell), new NSString("CustomerItemCell"));
this.searchResultsTable.AllowsMultipleSelectionDuringEditing = true;
this.searchResultsTable.TableFooterView = new UIView();
this.searchResultsTableDataSource = new MvxStandardTableViewSource(this.searchResultsTable, new NSString("CustomerItemCell"));
this.searchResultsTable.Source = this.searchResultsTableDataSource;
The MVxStandardTableViewSource is databound to a ViewModel property of type List
var set = this.CreateBindingSet<SearchView, SearchViewModel>();
set.Bind(this.searchResultsTableDataSource).To(vm => vm.SearchResults);
set.Bind(this.searchBar).For(x => x.Text).To(vm => vm.CurrentSearchCriteria);
set.Apply();
This all works fine until an item in the data source causes some text wrapping in one of the UILabels and consequently a different height to the other cells.
The cell height is mostly correctly calculated but the UILabel within the
cell does not get redrawn until the device is rotated. I am using iOS AutoLayout to layout the various UIViews in the Cell.
Here are some examples of the large cell in my layout, see the
person "THISISAPATIENTWITHA-" (note this is test data not real people's data)
Initial display of cells
Same cells but device has been rotated
Still the same cells with device rotated back to original
How do I get the UILabel to redraw? We only need to support iOS8 and above.
I cannot see an event or method that gets called when the data binding has happened that would allow me to effectively tell the custom cell "You now have your subviews populated with bound data so redraw them"
The table has another issue too that is covered by this question, Implementing cell reuse for varying height cells in UITableView
Simple Repro on Github
https://github.com/munkii/TableCellResizeIssue
UPDATE:
I've forked your GitHub project and submitted a pull request. But here's my updates to your project.
https://github.com/SharpMobileCode/TableCellResizeIssue
First, you're using FluentLayout for your constraints. Nothing wrong with that actually, but that's some good info to tell others. :)
Second, in order for UITableView.AutomaticDimension to work on TableView Cells, there must be enough autolayout constraints defined in order for the cell to calculate the height of the cell. UITableView.AutomaticDimension depends on proper AutoLayout constraints.
Since you were using FluentLayout to abstract iOS AutoLayout constraints, this was not obvious as no warnings were present in the application output window. Though FluentLayout was technically correct, it however wasn't enough for UITableView.AutomaticDimension to automatically calculate each cell height.
So what I did was added a few more constraints. Look in CustomerItemCell.CreateView() in the pull request (or my github link). You can see that I added additional constraints for all the bottom labels so that they add a Bottom Constraint to the ContentView (Just like you did with this.bornLabel). This had to be applied to all the labels on the bottom of the cell. This gives AutoLayout enough information to properly calculate the cell height.
Third, This almost works, but if you rotate to Landscape, you'll notice that the long name cells will be bigger and have extra padding. To fix this, I created another class called AutoLayoutLabel that inherits from UILabel. I overrode the Bounds property so that it changes the PreferredMaxLayoutWidth to the proper width when rotated to Landscape, and back to Portrait. You then will need to use AutoLayoutLabel instead of UILabel. You'll need this for all labels that need to wrap. I'm not sure how to set PreferredMaxLayoutWidth to auto in code, but this is how to do it programmatically (which also works for iOS 7).
public class AutoLayoutLabel : UILabel
{
public override CGRect Bounds
{
get
{
return base.Bounds;
}
set
{
base.Bounds = value;
if(this.Lines == 0 && Bounds.Size.Width != PreferredMaxLayoutWidth)
{
PreferredMaxLayoutWidth = Bounds.Size.Width;
SetNeedsUpdateConstraints();
}
}
}
}
Well, that should do it!
I now have a solution to this part of my issue. Prompted by #SharpMobileCode reference to PreferredMaxLayoutWidth I decided to give that another go. Rather that setting it to Automatic (which seems impossible in code) I am setting it Explicitly, once AutoLayout has done its thing. Like this
/// <summary>
/// Lays out subviews.
/// </summary>
public override void LayoutSubviews()
{
base.LayoutSubviews();
this.nameLabel.PreferredMaxLayoutWidth = this.nameLabel.Frame.Size.Width;
}
I am no longer seeing the Labels not wrap (hurrah!) however I am seeing an issue with what looks like cell reuse. Once I scroll all of the cell off the top of the screen I can scroll it back on and it has reverted to the same height as all the other cells. I can see the label is still wrapping but the cell height is wrong.
The standard table views in MvvmCross date back to iOS4 - while the new UITableViewAutomaticDimension sizing wasn't really added until much more recently (iOS8?)
Most real apps tend to use custom cells rather than the standard ones, but if you do want to use the standard ones, then I'd guess you could try adding some code to the setters in the cell which would trigger resize recalculations - e.g. to setters in https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Touch/Views/MvxStandardTableViewCell.cs#L73
I would guess that judiciously placed calls in there to request layout recalc would cause the parent cell and table to redraw.

onDraw called twice when View added dynamically by addView method

I want to add a new View to a Layout dynamically by layout.addView(view) method. The new View is not supposed to be visible, but I want it's Display List to be created so it doesn't have to redraw (call onDraw method) itself when I decide to show it (by animation, for example fade in).
I run this code:
customView = new CustomView(this.getContext());
customView .setAlpha(0.0f);
this.addView(customView ); // 'this' is RelativeLayout instance in this case
onDraw method gets called for customView and everything is fine. However, when I change anything in my layout (push a button, scroll, anything that invalidates layout), the onDraw method for my customView is called second time. After that, it isn't called any more if I don't invalidate my customView (correct behaviour).
I don't know why Android behaves this way. I want it to create customView, call onDraw, create a Display List for it, and not call onDraw any more until I invalidate my view. To sum up, onDraw is supposed to be called once.
And it has nothing to do with initial invisibility of customView, if alpha is set to 0.5f, behaviour is the same.
My question is, how to make Android call onDraw only once?
And if Android really has to call onDraw twice, then what should I do to enforce it to do it in some code right after this.addView(view); without setting up any timers because THAT would be totally ugly.
The behavior you are describing is ok and is a part of the android framework for view object -
Drawing
Drawing is handled by walking the tree and rendering each view that
intersects the invalid region. Because the tree is traversed in-order,
this means that parents will draw before (i.e., behind) their
children, with siblings drawn in the order they appear in the tree. If
you set a background drawable for a View, then the View will draw it
for you before calling back to its onDraw() method. Note that the
framework will not draw views that are not in the invalid region. To
force a view to draw, call invalidate()
(Taken from the official google android API docs).
Meaning your custom view is contained by the same view that contains the button\scrollbar etc. If you don't want it to be rendered everytime the onDraw method is called for the subtree your view resides in you can set the view's boolean flag to false - use setWillNotDraw() to do that. (you should place it on the activity's onCreate in order to render the view set this flag to false (which is also the default) and use invalidate() whenever you want to render the view).You can read the official google docs for further information.

I don't want to change color of JButton when pressed

Color newColor = new Color(197,222,90);
JButton newButton;
newButton = new JButton(icon);
newButton.setBacgroundColor(newColor);
When it is pressed it changes color. How can I keep it from changing color? I have multiple buttons, so if there is solution in one or two rows please help me, and keep in mind that I'm beginner, writing some huge classes won't help me, because I have multiple buttons with different names to be affected with this.
EDIT: Solution in one line is:
UIManager.put("Button.select", newColor);
But it changes all button colors but I need another to have different a color.
EDIT2: After some research I figured out there isn't an easy solution (but it should be). How I see it I have 2 solutions, 1. is to break buttons to separate classes and set UIManager for them, and second is to make custom buttons. It is just too much work for button.
I've found nothing that can change that particular behavior on a normal JButton. The problem being, that whatever you write in your actionlistener for the button, will occur AFTER you've let go of the mousebutton, and not "while clicking".
There are workarounds, however.
My preferred choice is, to remove all graphics from the button, and then add your own images to the button's regular and pressed states. You could take a screenshot of your GUI, cut out the button, and set that image to be both states.
JButton myButton = new JButton();
// Sets button x, y, width, height. Make the size match the image.
myButton.setBounds(5, 30, 100, 30);
// Remove border-graphics.
myButton.setBorder(null);
// Remove default graphics from the button
myButton.setContentAreaFilled(false);
// Remove the focus-indicating dotted square when focused (optional)
myButton.setFocusPainted(false);
// Here, myImage is a simple BufferedImage object.
// You can set one like this, provided you have an "images" package,
// next to your main class (ex: com.somecompany.someprogram.images),
// that contains an image:
BufferedImage myImage = ImageIO.read(getClass().getResource("images/myImage.png"));
// Then we simply apply our image to both states for the button, and we're done.
myButton.setIcon(new ImageIcon(myImage));
myButton.setPressedIcon(new ImageIcon(myImage));
Obviously there are many ways to retain and load an image, but since that's not the issue here, I'll leave additional methods out of it.
There's no need to go through it all countless times, though. It should be pretty easy to write your own custom implementation of the JButton class, in which a custom constructor takes a single parameter, being the BufferedImage, and then the constructor sets it up accordingly (changes the icons). Then all you have to do when you create a new JButton, is to use your own class, and pass it an image:
JButton btn = new MyCustomJButton(myImage);
You could also easily get along with very few images. All you need is a HashMap which holds all the images, with a String as a key. Imagine you need 4 OK-buttons. You make a single image of a button with the text "OK" written on it. Then you put that image into the HashMap, like so:
myMap.put("OK", myImage);
Then you could do this when creating a button, over and over again if you'd like more:
JButton btn = new MyCustomJButton(myMap.get("OK"));
Alternatively:
Another way of achieving this, which is pretty elaborate, but probably considered "the right way", is to use ButtonUI, as presented in this answer to another post.
If the OP is referring to the temporary change of background colour on a button with an icon at the moment the mouse is pressed, the following statement does the trick:
button.setContentAreaFilled(false);
"If you wish to have a transparent button, such as an icon only button, for example, then you should set this to false."
This took me a long time to figure out. It seems to be a little known technique, perhaps since its name gives little clue as to its effect.
With only first lane we can still see that it is clicked. You need to combine those two:
button1.setContentAreaFilled(false);
button1.setEnabled(false);
and if you don't wanna in grey color you put another button under him.
panelname.add(button1,+5,+5); \\(first not clicable, not visible button, notice +5)
panelname.add(button2,-5,-5); \(-5,-5 means it is 5 points under panel)

Allowing For Scrollbar When Resizing Container

I'm developing an application using GWT 2.3.0 and GXT 2.2.5.
I've got a LayoutContainer with ScrollMode set to AUTO and layout set to RowLayout with a horizontal orientation. It's used as the display window for my application.
The problem is that when the browser is resized so that the vertical scrollbar is displayed, the contents do not resize to account for it, causing the horizontal scrollbar to also appear even if it's not needed.
Is there a way to have the layout account for the space taken up by the scrollbar when rendering the widgets?
Ok that is a bit tricky to accomplise. I would do it like this:
On the Entry point (so that you know it is always active) add a resize handler to the Window
Window.addResizeHandler(new ResizeHandler() {
#Override
public void onResize(ResizeEvent event) {
// Fire Event containing the new size informing the application of the change
// Or resize the Layout container
}
}
If you choose to fire the event and you are using the MVP pattern then it is pretty simple to fire the event via the event bus and catch it wherever you like in the application.
The only catch here is that you might want to run the functions in onResize() inside a timer as in many cases the Window width/height reported have not the final value, due to the event being fired before the resizing completes.

Menu on a EnhancedGrid behaves weird when the container takes 100% width and height

I've spent some time simplifying the code to get a simple example of the problem. I'm using Dojo 1.6.1. I've a TabContainer defined on my page. Dinamically, I add to it two tabs, each one of them contains an EnhancedGrid with a rowMenu(right click). The issue is that the menu does not work correctly on IE8 if the TabContainer is defined to use all the space available on the page. If I use a specific height and width, it works fine. By not working correctly I mean the following: The menu is pretty simple; it has just two MenuItem, one of them is a PopupMenu that shows a submenu, as follows:
If the TabContainer takes all the available width and height, the menu does something very strange. First, if you do a right click over a row, it does not do anything. You need to a second right click. Then the menu shows, but when you open the submenu, the main menu disapears, and the submenu does not work. It keeps floating around until you navigate to other page:
When it fails, it throws a javascript error saying "'undefined' is null or not an object", on the line 208 of dojox/grid/_FocusManager.js
[...]
_scrollHeader: function(currentIdx){
var info = null;
if(this._colHeadNode){
var cell = this.grid.getCell(currentIdx);
info = this._scrollInfo(cell, cell.getNode(0));
}
[...]
I've tried to create a jsfiddle sample, but Dojo 1.6.1 is not available there, and with Dojo .1.6.0 the behaviour is diferent (You need to do a left click on the row and then a right click, and then the menu works fine), so I've created a simple HTML sample you can see on http://pastebin.com/jDNFQxrP. To see the difference you just need to change the commented TabContainer at the bottom of the code. Has someone seen this before?
Thanks
JL

Resources