I'm running into a strange issue when adding a Toolbar to my Form in my Codenameone app. If I set a toolbar on my form, it shows another title with the toolbar hamburger and new title below the title of the previous form instead of replacing it like I would expect. It looks like this:
The functionality works fine replacing the old title like I would expect when I run in the Codenameone simulator, but I get this weird behavior shown in the image when I make an Android build and run it on a Nexus 5 (6.0.1). The back arrow and "12 of 12" is the title from the previousForm
This is my code, am I doing anything wrong here with the Toolbar usage?
void goShowResource(final Form previousForm) {
previous = previousForm;
final Toolbar bar = new Toolbar();
final Form rd = new Form("resource details");
final Resource thisResource = this;
rd.setToolbar(bar);
bar.addCommandToSideMenu(new Command("command 1") {
#Override
public void actionPerformed(ActionEvent evt) {
AddResources ar = new AddResources(settings, thisResource);
ar.goAddResources(rd);
}
});
bar.addCommandToSideMenu(new Command("command 2") {
#Override
public void actionPerformed(ActionEvent evt){
UpdateResource ur = new UpdateResource(settings);
ur.goUpdateResource(rd, thisResource);
}
});
rd.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
showDetails(rd);
rd.show();
}
edit: Additonal info, if I open the sidemenu once, the old title bar at the top shrinks away, and I'm left with the the single correct yet incorrectly formatted title area.
You should use the Toolbar for all the forms in the app or disable the default which is native menu bar when working with the toolbar. You can do the latter by editing the theme and selecting the constants tab then pressing "Add" and selecting commandBehavior=Side.
Android currently defaults to the native ActionBar behavior and Toolbar implicitly overrides that, however when a transition occurs from the native to the lightweight component things can get pretty hairy (and might also look unnatural) so we recommend picking one UI paradigm and going with it.
Since the ActionBar is a volatile API we recommend Toolbar going forward as its far more customizable and gives us a lot of control.
This can be fixed by removing all command from the form after setting the toolbar, then add a fresh back command to the toolbar if required.
void goShowResource(final Form previousForm) {
previous = previousForm;
final Toolbar bar = new Toolbar();
final Form rd = new Form("resource details");
final Resource thisResource = this;
rd.removeAllCommands();
rd.setBackCommand(null);
rd.setToolbar(bar);
//Add back command
Command back = new Command("back") {
#Override
public void actionPerformed(ActionEvent evt) {
previousForm.showBack();
}
};
bar.addCommandToSideMenu(back);
bar.addCommandToSideMenu(new Command("command 1") {
#Override
public void actionPerformed(ActionEvent evt) {
AddResources ar = new AddResources(settings, thisResource);
ar.goAddResources(rd);
}
});
bar.addCommandToSideMenu(new Command("command 2") {
#Override
public void actionPerformed(ActionEvent evt){
UpdateResource ur = new UpdateResource(settings);
ur.goUpdateResource(rd, thisResource);
}
});
rd.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
showDetails(rd);
rd.show();
}
Related
I am trying to load an Icon dinammically into my Bottom Navigation Bar.
Each time, the user clicks a new variable (in my case a new city) the icon for the variable shall be downloaded from the firebase server and be set to the bottom navigation bar.
My code till now looks like this:
// first I load the relevant Icon from firebase
iconRef = mFirebaseDatabase.getReference().child(city);
iconRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
cityIcon = (String) dataSnapshot.getValue();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
// this is for initiating bottom navigation bar
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_nav);
Menu menu = bottomNavigationView.getMenu();
// the following shall load the Id of the part in the bottom navigation bar, where the icon shall be passed to
ImageView iconView = findViewById(R.id.CityIcon);
Picasso.get().load(cityIcon).into(iconView);
menuItemCity.setTitle(cCity);
// the problem is, when I start the activity it crashes
Alternatively I thought this could help me:
// but the following gives me an error as I am only allowed to enter an Integer and I am entering a String
MenuItem menuItemCity = menu.getItem(0);
menuItemCity.setIcon(cityIcon);
I was also thinking about first saving all the icons into the drawable folder. But as I want to be able to change the Icons after launch of the App it wouldn't serve my requirements. Though there might be a possibility to save the Icons into the drawable folder after downloading them from the server - maybe some of you people have any ideas how to solve this problem.
I am using this tool to get a toggle button behavior, this is the library:
https://github.com/ceryle/SegmentedButton
I want the left and right buttons to have different colors when selected. When I change the color programmatically, it works fine except from inside the listener, any hin on why this would happen?
SegmentedButtonGroup toggle = dialogView.findViewById(R.id.my_toggle);
toggle.setSelectorColor(activity.getResources().getColor(R.color.green));
toggle.setRippleColor(activity.getResources().getColor(R.color.green));
toggle.setOnPositionChanged(new SegmentedButtonGroup.OnPositionChanged() {
#Override
public void onPositionChanged(int position) {
SegmentedButtonGroup toggle = dialogView.findViewById(R.id.my_toggle);
toggle.setSelectorColor(activity.getResources().getColor(R.color.red));
toggle.setRippleColor(activity.getResources().getColor(R.color.red));
}
});
I am also open to other implementations of this functionality, I am having a hard time with this...
I am struggling how I could replicate the drop-down ToolbarItem from Xamarin.Forms when a ToolbarItem's order is set to Secondary for IOS, in order for it to look like it does for Android.
Here are some images to better explain what I am looking for:
How it works on Android:
Code:
ToolbarItem toolbarItem = new ToolbarItem()
{
Text = "ToolbarItem",
Order = ToolbarItemOrder.Secondary
};
Images on how it looks on Android:
Image showing the "More" icon
Image showing the "More" icon expanded to show more toolbar items
There is no default "More" icon on the toolbar when setting the Order to Secondary in iOS. Instead what happens, is that a bar below the navigation bar is created, which includes all of the toolbar items - something I do not wish to have for my Application.
This is an example of how it has been achieved before on IOS:
A screenshot I took from one of my Apps that implements this
effect
In native iOS, you can use UIPopoverController to achieve your effect. But please notice that this control can only be used in iPad.
Since you are using Xamarin.Forms, we can create a custom renderer in iOS platform to get this.
Firstly, create a page renderer to display the UIPopoverController. We can show it from a UIBarButtonItem or a UIView depending on your request. Here I use UIBarButtonItem like:
//I defined the navigateItem in the method ViewWillAppear
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
rightItem = new UIBarButtonItem("More", UIBarButtonItemStyle.Plain, (sender, args) =>
{
UIPopoverController popView = new UIPopoverController(new ContentViewController());
popView.PopoverContentSize = new CGSize(200, 300);
popView.PresentFromBarButtonItem(rightItem, UIPopoverArrowDirection.Any, true);
});
NavigationController.TopViewController.NavigationItem.SetRightBarButtonItem(leftItem, true);
}
Secondly, construct the content ViewController in the UIPopoverController(just like the secondary list in android):
public class ContentViewController : UIViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
UITableView tableView = new UITableView(new CGRect(0, 0, 200, 300));
tableView.Source = new MyTableViewSource();
View.AddSubview(tableView);
}
}
public class MyTableViewSource : UITableViewSource
{
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell(new NSString("Cell"));
if (cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Default, new NSString("Cell"));
}
cell.TextLabel.Text = "Item" + indexPath.Row;
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return 10;
}
}
At last we can show it on the screen by calling PresentFromBarButtonItem.
This is a short question:
I'm trying to force the action bar (used by a Toolbar) to use LTR alignment. I've succeeded making the layout itself use LTR, but not the "up" button (as I've done here, before Toolbar was introduced) .
It seems this view doesn't have an ID, and I think using getChildAt() is too risky.
Can anyone help?
The answer
Here's one way I've found to solve this, based on this answer .
I made it so that it is guarranteed to find only the "up" button, and whatever it does, it will revert back to the previous state it was before.
Here's the code:
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
#Override
public boolean onCreateOptionsMenu(final Menu menu)
{
// <= do the normal stuff of action bar menu preparetions
if(VERSION.SDK_INT>=VERSION_CODES.JELLY_BEAN_MR1&&getResources().getConfiguration().getLayoutDirection()==View.LAYOUT_DIRECTION_RTL)
{
final ArrayList<View> outViews=new ArrayList<>();
final CharSequence previousDesc=_toolbar.getNavigationContentDescription();
for(int id=0;;++id)
{
final String uniqueContentDescription=Integer.toString(id);
_toolbar.findViewsWithText(outViews,uniqueContentDescription,View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if(!outViews.isEmpty())
continue;
_toolbar.setNavigationContentDescription(uniqueContentDescription);
_toolbar.findViewsWithText(outViews,uniqueContentDescription,View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty())
if (BuildConfig.DEBUG)
throw new RuntimeException(
"You should call this function only when the toolbar already has views");
else
break;
outViews.get(0).setRotation(180f);
break;
}
_toolbar.setNavigationContentDescription(previousDesc);
}
//
return super.onCreateOptionsMenu(menu);
}
It seems this view doesn't have an ID
You're right, the navigation view is created programmatically and never sets an id. But you can still find it by using View.findViewsWithText.
View.findViewsWithText comes with two flags:
View.FIND_VIEWS_WITH_TEXT
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
The navigation view's default content description is "Navigate up" or the resource id is abc_action_bar_up_description for AppCompat and action_bar_up_description for the framework's, but you can easily apply your own using Toolbar.setNavigationContentDescription.
Here's an example implementation:
final Toolbar toolbar = ...;
toolbar.setNavigationContentDescription("up");
setActionBar(toolbar);
final ArrayList<View> outViews = Lists.newArrayList();
toolbar.findViewsWithText(outViews, "up", View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
outViews.get(0).setRotation(180f);
Results
I have a problem with Xamarin.Forms (version 1.2.2) on Android (Nexus 5).
The alignment of Button.Text is often not centered after performing a click.
In a short project, I figured out, that updating the UI causes the problem.
public class App
{
public static Page GetMainPage()
{
var label = new Label {
Text = "label",
};
var buttonBad = new Button {
Text = "buttonBad",
Command = new Command(() => label.Text += "1"),
};
var buttonGood = new Button {
Text = "buttonGood",
};
return new ContentPage {
Content = new StackLayout {
Children = {
buttonBad,
buttonGood,
label,
}
}
};
}
}
A click on "buttonBad" (updating the label.Text) causes the text-alignment of this button to not be centered anymore. A click on "buttonGood" does not cause the problem.
Is there a good workaround to solve this problem?
This workaround seems to be too complicated:
http://forums.xamarin.com/discussion/20608/fix-for-button-layout-bug-on-android
edit:
A programatically edit of the UI also cases the bug. Changing the label.Text in an async method after a short waiting leads the "buttonGood" to align its text wrong after a click.
edit2:
I created an example / test project on GitHub:
https://github.com/perpetual-mobile/ButtonTextAlignmentBug.git
The alignment is correct, when the StackLayout is replaced by an AbsolutLayout, but i need the StackLayout to work well.
Ok, after hours of dealing with this silly bug, I resolved it by implementing a custom renderer and overriding ChildDrawableStateChanged:
public override void ChildDrawableStateChanged(Android.Views.View child)
{
base.ChildDrawableStateChanged(child);
Control.Text = Control.Text;
}