UINavigationBar in a UIPopoverController looks ugly if created programatically - xamarin.ios

I want to open a Popover in code after a specific action happens (e.g. tap on a button).
The following Code let me open a Popover with a NavigationBar but it don't looks like the one I've done with IB. (IB approach was embedding a UIViewController in a UINavigationController and defining the the two buttons cancel and save). The only thing I want is having these two buttons on top of the Popover. I don't use any navigation functionality!
var cell = grid.VisibleCellAtCoordinate(coordinate) as SDataGridTextCell;
var viewController = new UIViewController();
var navBar = new UINavigationBar(new RectangleF(0, 0, viewController.View.Bounds.Width, 50))
{
AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
BarStyle = UIBarStyle.Black,
Translucent = true,
Items = new[]
{
new UINavigationItem("test")
{
LeftBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, (s, e) => { _popoverController.Dismiss(true); }),
RightBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Save, (s, e) => { _popoverController.Dismiss(true); })
}
}
};
var textField = new UITextField(new RectangleF(0, 50, viewController.View.Bounds.Width, viewController.View.Bounds.Height)) { Placeholder = "Mein Text...", BackgroundColor = UIColor.White };
textField.BecomeFirstResponder();
viewController.View.Add(navBar);
viewController.View.Add(textField);
viewController.View.SubviewAdded(textField);
_popoverController = new UIPopoverController(viewController);
_popoverController.SetPopoverContentSize(new SizeF(250, 200), false);
_popoverController.PresentFromRect(cell.Bounds, cell, UIPopoverArrowDirection.Any, false);
These buttons looks like this image (ugly):
And this image shows how it's look like when created in IB:

That's one of the caveats of using a standalone navigation bar in a popover. Embedding your view controller in a navigation controller is, as far as I know, the only way to avoid it.

Had some problem embedding the content view (UIViewController) correctly to the UINavigationController because I tried to add the navigation bar items (buttons) each time directly to the UINavigationController's NavigationItem property. But this must be done through the content view controller...
var contentViewController = new UIViewController();
var textField = new UITextField(contentViewController.View.Bounds)
{
BackgroundColor = UIColor.White,
AutoresizingMask = ~UIViewAutoresizing.None,
Placeholder = "My Text..."
};
contentViewController.View.Add(textField);
var navigationController = new UINavigationController(contentViewController);
contentViewController.Title = "Popover";
contentViewController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, (s, e) => { _popoverController.Dismiss(false); });
contentViewController.NavigationItem.RightBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Save, (s, e) => { _popoverController.Dismiss(false); });
_popoverController = new UIPopoverController(navigationController);
_popoverController.SetPopoverContentSize(new SizeF(300, 300), false);
_popoverController.PresentFromRect(button1.Bounds, button1, UIPopoverArrowDirection.Any, false);

Related

How to customize the UIContextualAction in tableview when swipe

I need to create an action button with a image and text. below image provide
an example.
![1]: https://i.stack.imgur.com/KEuHn.png
i have created a method like
public UIContextualAction ContextualFlagAction(int row)
{
var action = UIContextualAction.FromContextualActionStyle(UIContextualActionStyle.Normal, "Flag", Handler);
(contextualAction, view, handler) =>
{
Console.WriteLine("Hello World!");
handler(false);
});
action.Image = UIImage.FromFile(ResourceIdentifiers.DocumentIcon);
return action;
}
but this is not what i need to do.
how can i customize this action as the image in the above.
Maybe your problem showed is the image result,your code have set action.image
If you have a image that contains picture and label , picture is up,label is down,there will be you want.
public UIContextualAction ContextualFlagAction(int row)
{
var action = UIContextualAction.FromContextualActionStyle(UIContextualActionStyle.Normal, "Flag", Handler);
(contextualAction, view, handler) =>
{
Console.WriteLine("Hello World!");
handler(false);
});
action.Image = UIImage.FromFile(ResourceIdentifiers.DocumentIcon);
//this is your setted image
return action;
}
More info:
You can custom a TableViewCell in Xamarin.ios.
Write the following method in UITableViewCell, Rewrite DidTransitionToState method in viewcell, you can replace the action with button
private UITableView tableViewThis;
public TableViewCellClass(UITableView tableView)
{
this.tableViewThis = tableView;
}
public override void DidTransitionToState(UITableViewCellState mask)
{
base.DidTransitionToState(mask);
if ((mask & UITableViewCellState.ShowingDeleteConfirmationMask) == UITableViewCellState.ShowingDeleteConfirmationMask)
{
foreach (UIView subview in tableViewThis.Subviews)
{
if (subview.Class.Equals("UIContextualAction"))
//Delete the delete button of the system
tableViewThis.WillRemoveSubview(subview);
subview.BackgroundColor = UIColor.Clear;
UIButton editBtn = new UIButton(UIButtonType.Custom);
editBtn.Frame = new CGRect(10, 4, 50, 65);
editBtn.SetBackgroundImage(UIImage.FromFile("1.png"), UIControlState.Normal);
editBtn.AdjustsImageWhenHighlighted = false;
editBtn.TouchUpInside += (sender, e) =>
{
//do something you need
};
subview.AddSubview(editBtn);
}
}
}
UIButton can set both Title and Image. UIButton has two properties:
titleEdgeInsets(top,left,bottom,right)
and imageEdgeInsets(top,left,bottom,right).
By setting these two, you can implement the style you need.

Xamarin.Forms Action Bar - Center Aligned Image

Using Xamarin.Forms, how do I get the same effect as the application pictured below, specifically to show a centred image on the Action Bar / page tool bar (the section in a blue box)?
I would like to have a long width image in that section, and the solution must work for Android, iOS, Windows Phone, and Universal Windows (even if it means writing custom renderers or platform specific xamarin code).
I suggest you create your own Xamarin.Forms view and handle the navigation by yourself something similar to this:
public class CustomBackNavigationBar : StackLayout
{
public Image BackIcon;
public Image Icon;
public Label IconTitle;
public StackLayout IconContainer;
public CustomBackNavigationBar(string title, string icon)
{
Padding = new Thickness(15,5);
HeightRequest = 40;
Orientation = StackOrientation.Horizontal;
VerticalOptions = LayoutOptions.Start;
BackgroundColor = StaticData.BlueColor;
Spacing = 15;
BackIcon = new Image
{
Source = StaticData.BackIcon,
HorizontalOptions = LayoutOptions.Start
};
Label Title = new Label
{
Text = title,
TextColor = Color.White,
FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)),
FontAttributes = FontAttributes.Bold,
VerticalTextAlignment = TextAlignment.Center
};
Icon = new Image
{
Source = icon
};
IconTitle = new Label
{
Text = StaticData.CallAgent,
TextColor = Color.White,
FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label)),
};
IconContainer = new StackLayout
{
HorizontalOptions = LayoutOptions.EndAndExpand,
Spacing = 2,
Children = { Icon, IconTitle }
};
Children.Add(BackIcon);
Children.Add(Title);
Children.Add(IconContainer);
#region Events
BackIcon.GestureRecognizers.Clear();
BackIcon.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(PopAsync)
});
#endregion
}
async void PopAsync()
{
await App.AppNavigation.PopAsync();
}
}

Hide the keyboard (blur) when clicking out of a textField inside a tableView in Titanium

I'm trying to get a table in Titanium where each row has a static text and a textField where I can input something.
So I go and create a row where it's left part is the static text and the right part it's my input text field.
Just a small problem, I can't hide the keyboard by clicking outside of it.
If it was a normal textField outside a table I would just use the blur method, but in this case I can't get that to work.
This is my code so far:
Any idea on how this works and if the solution is valid for both iOS and Android?
var winAddObjectView = Titanium.UI.currentWindow;
var tableAddObjectData = [
{title:'name', hintText:'item name (optional)'},
{title:'track no.', hintText:'object tracking code'}
];
var tableAddObjectRowData = [];
for (var i = 0; i < tableAddObjectData.length; i++) {
var title = Ti.UI.createLabel({
text:tableAddObjectData[i].title,
textAlign:"right",
left:"20",
height:'auto',
width:'68',
color:'#526691',
font:{fontSize:12, fontWeight:'bold'},
});
var textField = Ti.UI.createTextField({
hintText:tableAddObjectData[i].hintText,
textAlign:"left",
left:"96",
height:'auto',
width:'184',
color:'#4C4C4C',
font:{fontSize:12, fontWeight:'bold'},
});
winAddObjectView.addEventListener("click", function(e){
textField.blur();
});
var row = Ti.UI.createTableViewRow({
height:"45",
});
row.add(title);
row.add(textField);
tableAddObjectRowData.push(row);
}
var tableAddObjectView = Ti.UI.createTableView({
headerTitle:'Enter Tracking Information',
style:Titanium.UI.iPhone.TableViewStyle.GROUPED,
backgroundColor:'transparent',
data:tableAddObjectRowData,
});
winAddObjectView.add(tableAddObjectView)
I have made a few changes in your code. Please try this
var tableAddObjectRowData = [];
var textFields = []; //Created an array of textFields
for (var i = 0; i < tableAddObjectData.length; i++) {
var title = Ti.UI.createLabel({
text:tableAddObjectData[i].title,
textAlign:"right",
left:"20",
height:'auto',
width:'68',
color:'#526691',
font:{fontSize:12, fontWeight:'bold'},
});
textFields[i] = Ti.UI.createTextField({ //Creating the textField
hintText:tableAddObjectData[i].hintText,
textAlign:"left",
left:"96",
height:'auto',
width:'184',
color:'#4C4C4C',
font:{fontSize:12, fontWeight:'bold'},
});
var row = Ti.UI.createTableViewRow({
height:"45",
});
row.add(title);
row.add(textFields[i]);
tableAddObjectRowData.push(row);
}
var tableAddObjectView = Ti.UI.createTableView({
headerTitle:'Enter Tracking Information',
style:Titanium.UI.iPhone.TableViewStyle.GROUPED,
backgroundColor:'transparent',
data:tableAddObjectRowData,
height : (tableAddObjectRowData.length * 45) + 60 //Added the height property for the tableView
});
winAddObjectView.addEventListener("click", hideSoftKeyboard); //added event listener to the window, moved this to out of the loop
function hideSoftKeyboard(){ //Added function to hide the keyboard
for(var i=0; i<textFields.length; i++){
textFields[i].blur(); //Hiding each keyboards
}
}
winAddObjectView.add(tableAddObjectView);
Explanation
winAddObjectView.addEventListener("click", function(e){
textField.blur();
});
The above code segment in your program didn't worked because the click event for the window was not firing due to the height of tableView, the window was hidden and your clicks were firing on the tableView. You can see the difference if you set the backgroundColor property for your tableView. So I adjusted the height of the tableView and hence the click fired in the window and the keyboard has gone.
Creation of textField array : You can do the same without creating the textField array and inside the for loop you can create the textField as var textField = Ti.UI.createTextField();. But if you do so, you cannot hide keayboard all the times, since event will be fired for the last textField only. Hence I created the textField array
For Android you can also use Ti.UI.android.hideSoftKeybaord() method. For that just change the hideSoftkeyboard() method in our code as follows
function hideSoftKeyboard(){ //Added function to hide the keyboard
if(Ti.Platform.osname === 'android'){
Ti.UI.Android.hideSoftKeyboard();
} else {
for(var i=0; i<textFields.length; i++){
textFields[i].blur(); //Hiding each keayboards
}
}
}

Monotouch.Dialog StyledStringElement delegate always fires for the last element added

given the following code, I am having an issue when clicking on each element. If we assume I have 5 exercises and therefore create 5 elements in the foreach() loop, when the table is rendered and I click on any element, the delegate always gets the exercise of the 5th (last) element.
The elements are displayed properly, each showing the associated exercise's name. It is just the delegate that does not work as expected.
If I do not use a foreach loop and hardcode each element instead it works as expected. However if I cannot dynamically populate the dialogViewController and use the element tapped event for each one, is not good.
private void CreateExerciseTable()
{
Section section = new Section();
foreach (var exercise in exercises)
{
var element = new StyledStringElement(exercise.ExerciseName,
delegate { AddExercise(exercise); })
{
Font = Fonts.H3,
TextColor = UIColor.White,
BackgroundColor = RGBColors.LightBlue,
Accessory = UITableViewCellAccessory.DisclosureIndicator
};
section.Elements.Add(element);
}
var root = new RootElement("Selection") {
section
};
var dv = new DialogViewController(root, true);
dv.Style = UITableViewStyle.Plain;
//Remove the extra blank table lines from the bottom of the table.
UIView footer = new UIView(new System.Drawing.RectangleF(0,0,0,0));
dv.TableView.TableFooterView = footer;
dv.TableView.SeparatorColor = UIColor.White;
dv.TableView.BackgroundColor = UIColor.White;
tableFitnessExercises.AddSubview(dv.View);
}
private void AddExercise(FitnessExercise exercise)
{
NavigationManager.FitnessRoutine.Add(exercise);
PerformSegue(UIIdentifierConstants.SegAddExerciseToFitnessRoutine, this);
}
This is a classic closure bug!
The problem is that you are accessing the loop reference.
Try:
foreach (var exercise in exercises)
{
var localRef = exercise;
var element = new StyledStringElement(exercise.ExerciseName,
delegate { AddExercise(localRef); })
{
Font = Fonts.H3,
TextColor = UIColor.White,
BackgroundColor = RGBColors.LightBlue,
Accessory = UITableViewCellAccessory.DisclosureIndicator
};
section.Elements.Add(element);
}
For more on this see http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

Resizing MonoTouch.Dialog StyledMultilineElement after an async call

I'm playing with MonoTouch.Dialog and written some code to show some tweets. The problem is that the table cells are too small and the cells are all bunched up when I load the StyledMultilineElements asynchronously. They look absolutely perfect when I load them synchronously (i.e. without the QueueUserWorkItem/InvokeOnMainThread part)
Is there a way of getting the table cells to recalculate their height?
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window.AddSubview(navigation.View);
var tweetsSection = new Section("MonoTouch Tweets"){
new StringElement("Loading...") //placeholder
};
var menu = new RootElement("Demos"){
tweetsSection,
};
var dv = new DialogViewController(menu) { Autorotate = true };
navigation.PushViewController(dv, true);
window.MakeKeyAndVisible();
// Load tweets async
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
ThreadPool.QueueUserWorkItem(delegate {
var doc = XDocument.Load("http://search.twitter.com/search.atom?q=%23MonoTouch");
var atom = (XNamespace)"http://www.w3.org/2005/Atom";
var tweets =
from node in doc.Root.Descendants(atom + "entry")
select new {
Author = node.Element(atom + "author").Element(atom + "name").Value,
Text = node.Element(atom + "title").Value
};
var newElements =
from tweet in tweets
select new StyledMultilineElement(
tweet.Author,
tweet.Text);
InvokeOnMainThread(delegate {
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = false;
tweetsSection.Remove(0);
tweetsSection.Add(newElements.Cast<Element>().ToList());
});
});
return true;
}
Try setting the UnevenRows property on your top level Root element of your Dialog View Controller, in this case "menu":
menu.UnevenRows = true

Resources