I'm new to Xamaring and iOS, but I'm trying to create a view that when the UIBarButtonSystemItem.Add is pressed, it adds a record to the SQLite database, alerts the user and then refreshes the screen as the screen draws out a button for each of the records in the table in SQLite.
Currently the add button code is:
this.NavigationItem.SetRightBarButtonItem(new UIBarButtonItem(UIBarButtonSystemItem.Add, (sender,args) => {
conn.Query<Job>("INSERT INTO Job (Job) VALUES(0)");
UIAlertView alSQL = new UIAlertView("Jobs","New job added",null,"ok",null);AllJobsScreen(), true);
alSQL.Show ();
}), true);
At present the data is added and the alert is shown, but I'm not sure of anyway to get the screen to reflect this new record in the database and add a new button.
I've looked online for refreshing the screen and can't find anything so any help would be great. Or if I'm going about this the wrong way, please let me know.
I'm writing out buttons on the screen, but ideally I need to be able to refresh any view with anything on it. At present the buttons are written out in a loop from a SQLite query as below:
UIButton btnTest = new UIButton (UIButtonType.System);
btnTest.Frame = new RectangleF(iTopLeftx, iTopLefty, 300, 30);
btnTest.SetTitle("J00000" + s.mJobID.ToString(),UIControlState.Normal);
btnTest.BackgroundColor = UIColor.Clear;
this.View.Add (btnTest);
Try changing the TitleColor, BorderColor and BorderWidth of your newly created UIButtons. Maybe your buttons are displayed on the view but you just can't see them.
UIButton btnTest = UIButton.FromType(UIButtonType.Custom);
btnTest.Frame = new RectangleF(iTopLeftx, iTopLefty, 300, 30);
btnTest.SetTitle("J00000" + s.mJobID.ToString(), UIControlState.Normal);
btnTest.SetTitleColor(UIColor.Black, UIControlState.Normal);
btnTest.Layer.BorderColor = UIColor.Black.CGColor;
btnTest.Layer.BorderWidth = 1;
btnTest.BackgroundColor = UIColor.Clear;
this.View.Add(btnTest);
EDIT
Then the problem seems to be that you didn't remove previously added UIButtons. Try to hold your collection of UIButtons in a list or an array.
List<UIButton> buttonList;
Then populate your buttonList:
private void PopulateSubviews()
{
for (int i=0; i<count; i++)
{
UIButton btnTest = UIButton.FromType(UIButtonType.Custom);
// previous code withoud this.View.Add(...);
...
buttonList.Add(btnTest);
}
}
And have these two methods:
private void ClearView()
{
foreach (UIButton btn in buttonList)
{
btn.RemoveFromSuperview();
}
buttonList.Clear();
}
private void InitializeSubviews()
{
foreach (UIButton btn in buttonList)
{
this.View.AddSubview(btn);
}
}
And to refresh your views:
private void ReloadSubviews()
{
ClearView();
PopulateSubviews();
InitializeSubviews();
}
Related
How do I render a UIButton in Xamarin.iOS? See the current Code for the full list.
This is the code I'm using to create and add the button to the Xamarin.Forms.Platform.iOS.CellTableViewCell cell. I cannot get the button to display anything.
With the use of a Foundation.NSMutableAttributedString, it shows a cut-off section of text in the top left corner, regardless of anything I try (alignments, insets, bounds, various constraints, etc). I'm currently trying things from Xamarin.Forms.Platform.iOS.Renderers.ButtonRenderer, but still can't get anything to display at all, no text, no button, or its outline.
If you could fork the repo and fix it or post the solution here, I would be very grateful.
protected override void SetUpContentView()
{
var insets = new UIEdgeInsets(SVConstants.Cell.PADDING.Top.ToNFloat(), SVConstants.Cell.PADDING.Left.ToNFloat(), SVConstants.Cell.PADDING.Bottom.ToNFloat(), SVConstants.Cell.PADDING.Right.ToNFloat());
_Button = new UIButton(UIButtonType.RoundedRect)
{
AutoresizingMask = UIViewAutoresizing.All,
HorizontalAlignment = UIControlContentHorizontalAlignment.Center,
VerticalAlignment = UIControlContentVerticalAlignment.Center,
ContentEdgeInsets = insets,
// TitleEdgeInsets = insets
};
DefaultFontSize = _Button.TitleLabel.ContentScaleFactor;
DefaultTextColor = _Button.TitleLabel.TextColor;
_Recognizer = new UILongPressGestureRecognizer(RunLong);
_Button.TouchUpInside += OnClick; // https://stackoverflow.com/a/51593238/9530917
_Button.AddGestureRecognizer(_Recognizer); // https://stackoverflow.com/a/6179591/9530917
ContentView.AddSubview(_Button);
_Button.CenterXAnchor.ConstraintEqualTo(ContentView.CenterXAnchor).Active = true;
_Button.CenterYAnchor.ConstraintEqualTo(ContentView.CenterYAnchor).Active = true;
_Button.WidthAnchor.ConstraintEqualTo(ContentView.WidthAnchor).Active = true;
_Button.HeightAnchor.ConstraintEqualTo(ContentView.HeightAnchor).Active = true;
UpdateConstraintsIfNeeded();
LayoutIfNeeded();
}
Found out that you can't subclass it. Any button added to the view must be native (UIButton) or custom rendered, such as Xamarin.Forms.Platform.iOS.ButtonRenderer; It doesn't show up otherwise.
I have an application that from the main app "hamburger" menu, if an option is selected I want to show a PickerView for the user to select a number from.
Because it's needs to be accessible throughout the app from this menu I built the UIPickerView in the AppDelegate.cs (as that's where the UINavigationController code is and from that the menu).
Everything shows up correctly: User selected menu button -> menu displays -> User selects "Show Picker" button -> Picker displays with all items. But once the picker displays, you can't scroll the options, nor does the "Done" button I've added register clicks. In fact text fields from the ViewController behind this popup can be clicked on through the popup.
I'm not sure why this UIPickerView is non interactive, does anyone have some thoughts?
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// create a new window instance based on the screen size
window = new UIWindow(UIScreen.MainScreen.Bounds);
// instantiate the navigation controller
nav = new UINavigationController(new SplashController());
vwNav = new UIView(nav.NavigationBar.Bounds);
var pickerView = new UIPickerView(new CGRect(275f, (UIScreen.MainScreen.Bounds.Size.Height / 2) - (375f / 2), 275f, 375f));
pickerView.ShowSelectionIndicator = true;
var myPickerViewModel = new PickerViewModel(itemList);
pickerView.Model = myPickerViewModel;
myPickerViewModel.PickerChanged += (sender, e) => {
var temp = myPickerViewModel.SelectedItem;
};
// Set up toolbar
var toolbar = new UIToolbar();
toolbar.SizeToFit();
toolbar.Hidden = false;
UILabel titleLabel = new UILabel();
titleLabel.Text = "Select an Item";
titleLabel.Frame = new RectangleF(75, 13, 200, 20);
UIButton doneButton = new UIButton(UIButtonType.Custom);
doneButton.Frame = new RectangleF(40, 335, (float)200, 30);
doneButton.SetTitle("Done", UIControlState.Normal);
doneButton.TouchDown += (sender, e) =>
{
pickerView.Hidden = true;
};
toolbar.AddSubview(titleLabel);
toolbar.AddSubview(doneButton);
pickerView.AddSubview(toolbar);
pickerView.Hidden = true;
btnMenu = new UIButton(UIButtonType.Custom);
btnMenu.Frame = new CGRect(vwNav.Frame.Right - 45, 0, 45, nav.NavigationBar.Bounds.Height);
btnMenu.SetImage(imgMenu, UIControlState.Normal);
btnMenu.SetImage(imgMenu, UIControlState.Selected);
btnMenu.TouchUpInside += (object sender, EventArgs e) =>
{
UIAlertView alert = new UIAlertView();
alert.Title = "Settings";
alert.AddButton("Open PickerView");
alert.AddButton("Exit");
alert.Dismissed += delegate (object alertSender, UIButtonEventArgs args)
{
if (args.ButtonIndex == 0)
{
pickerView.Hidden = false;
}
else
return;
}
}
vwNav.AddSubviews(btnMenu, pickerView);
nav.NavigationBar.Layer.BorderWidth = 2f;
nav.NavigationBar.Layer.BorderColor = (UIColor.FromPatternImage(imgNavBar)).CGColor;
nav.NavigationBar.AddSubviews(vwNav);
// If you have defined a root view controller, set it here:
this.window.RootViewController = nav;
this.window.MakeKeyAndVisible();
return true;
}
I removed some of the unrelated code (a few nav.PushViewController() for different screens and other menu options) to keep it as clear as I could.
From your code, the frame of vwNav is nav.NavigationBar.Bounds, and the frame of pickerView is new CGRect(275f, (UIScreen.MainScreen.Bounds.Size.Height / 2) - (375f / 2), 275f, 375f), if you add pickView to vwNav, the pickerView is out of bounds of vwNav.
Remember that views don't receive touch events where they're outside the bounds of their superview.
That's the cause of your issue.
Solution:
I don't think you should built the UIPickerView in the AppDelegate.cs, create it in your ViewController instead.
You can also add buttons to Navigationbar in ViewController :
UIBarButtonItem btn = new UIBarButtonItem();
btn.Image = UIImage.FromFile("Image");
btn.Clicked += (sender, e) => { System.Diagnostics.Debug.WriteLine("show picker"); };
NavigationItem.RightBarButtonItem = btn;
And remember to add picker to the View of Viewcontroller.
Refer: uinavigationitem and add-uibarbuttonitem-to-navigation-bar-in-xamarin-ios
Feel free to ask me any question:).
How to have a tag bubbles like in the attached image.I have done this for android using TagView component but not sure how to do it for Xamarin iOS?Any component that I can refer?
You will have to write this custom component yourself .
I would recommend having this designed in XIB/Storyboard and place em at runtime .
very rough idea to create one such subview programmitically could be something like
var myView = new UIView(frame: new CoreGraphics.CGRect(10, 10, 120, 40));
myView.BackgroundColor = UIColor.Blue;
myView.Layer.CornerRadius = 20;
var mylabel = new UILabel(frame: new CoreGraphics.CGRect(10, 10, 80, 40));
mylabel.Text = "MUMBAI";
myView.Add(mylabel);
UIButton button = new UIButton();
button.Frame = new CoreGraphics.CGRect(mylabel.Frame.X + mylabel.Frame.Width, 10f, 40, 25);
button.SetTitle("Title", UIControlState.Normal);
button.SetBackgroundImage(UIImage.FromBundle("MyImage"),UIControlState.Normal);
myView.Add(button);
View.Add(myView);
Here frame calculation you need to do ,above are just some sample frame I put .
so ultimately you gonna make such views stack em horizontally ,and when user clicks "x" button , you change the frame with animation .
Try this
https://github.com/nmilcoff/TagsView
It's super simple to get started:
public class ViewController : UIViewController
{
private TagListView tagsView;
public override void ViewDidLoad()
{
// code
this.tagsView = new TagListView()
{
// you can customize properties here!
};
this.View.AddSubview(this.tagsView);
this.View.AddConstraints(
// Add your constraints!
);
// you can attach a source object to each tag
var myObject = new MyModel { Title = "I'm a MyModel!" };
this.tagsView.AddTag(myObject.Title, myObject);
// but, if none is provided, it will be the text string
this.tagsView.AddTag("I'm a simple tag!");
}
}
I tried to put the toolbar(with text field) above the keyboard. Initially, the toolbar was at the bottom.
I tried to use "inputAccessaryView" on the text field. The toolbar just disappear after I clicked inside the text field. I know this will work if I created a new toolbar for it. But like in the chat window, I want the same textfield/toolbar.
Here is the code
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
NavigationItem.Title = "Name";
ChatInput = new UITextField (new RectangleF(0,0,View.Bounds.Width - 104f,30f));
Toolbar = new UIToolbar (new RectangleF(0, View.Bounds.Height - 44.0f, View.Bounds.Width, 44f));
ChatInput.BorderStyle = UITextBorderStyle.RoundedRect;
Toolbar.SetItems( new UIBarButtonItem[] {
new UIBarButtonItem(UIBarButtonSystemItem.Refresh, (s,e) => {
Console.WriteLine("Refresh clicked");
})
, new UIBarButtonItem (ChatInput){Style = UIBarButtonItemStyle.Bordered,Width = View.Bounds.Width - 104f}
, new UIBarButtonItem(UIBarButtonSystemItem.Reply, (s,e) => {
Console.WriteLine ("Reply clicked");
})
}, false);
ChatInput.ReturnKeyType = UIReturnKeyType.Send;
ChatInput.ShouldBeginEditing = delegate {
ChatInput.InputAccessoryView = Toolbar;
return true;
};
ChatInput.ShouldReturn = delegate {
ChatInput.ResignFirstResponder();
return true;
};
View.AddSubview (Toolbar);
}
I don't know if there's a way to pin the toolbar on top of the keyboard, but what you could do it create some kind of method to move the toolbar (edit its .Frame property) when the keyboard pops up. I use this method to move an entire UIScrollView up. You can find the method I used here: (http://www.gooorack.com/2013/08/28/xamarin-moving-the-view-on-keyboard-show/).
This may not be the most "clean" solution, but if implemented correctly, it does its job. Another advantage is, is if you put the entire "moving of the keyboard" in a separate class-file, you can re-use it in other views.
Hope this helps. Good luck!
Love and regards,
Björn
I'm having an issue asynchronously loading several UIWebViews into one Section. I'm using MonoTouch.Dialog to generate the UI. I am loading data from a blog and showing 10 items which consist of an image plus some HTML text. What's happening is that the posts are not all showing up and the ones that are showing up are out of order. Here's what I'm doing:
public partial class BlogViewController : DialogViewController
{
private Section mainSection;
public BlogViewController () : base (UITableViewStyle.Grouped, null)
{
Root = new RootElement ("");
mainSection = new Section ("");
mainSection.Add(new ActivityElement ());
Root.Add (mainSection);
}
public override void ViewDidLoad()
{
base.ViewDidLoad ();
new Thread (new ThreadStart(PopulateBlog)).Start ();
}
private void PopulateBlog ()
{
var posts = service.GetPosts (currentOffset, 10);
InvokeOnMainThread (delegate {
foreach (var post in posts) {
//grab an appropriate image size
var altSize = post.photos [0].alt_sizes.Where (x => x.width < 401).OrderByDescending(x => x.width).FirstOrDefault ();
if (altSize != null) {
var img = LoadImageFromUri(altSize.url);
//scale the image, not really important
var imageView = new UIImageView (new RectangleF (0, 0, screenWidth, height));
imageView.Image = img;
var content = new UIWebView ();
//When the HTML finishes rendering figure out the size and add it to the section. Apparently can't figure the size ahead of time?
content.LoadFinished += (sender, e) =>
{
var contentHeight = Int32.Parse (content.EvaluateJavascript ("document.getElementById('content').offsetHeight;"));
content.Frame = new RectangleF (0, height + 10, screenWidth, contentHeight + 10);
//dynamically size this view to fit the content
var view = new UIView
(new RectangleF (0, 0,
screenWidth,
height + contentHeight));
view.AddSubview (content);
view.AddSubview (imageView);
//add the view to the Section which is later added to the Root
mainSection.Add(view);
};
var htmlString = #"some HTML here";
content.LoadHtmlString(someHtml);
content.ScrollView.ScrollEnabled = false;
content.ScrollView.Bounces = false;
}
}
});
Root.Reload(mainSection, UITableViewRowAnimation.None);
}
}
I'm guessing that A) the LoadFinished events are not happening in the same order that they are queued up, and that B) The Root.Reload gets called before they all fire. I tried spinning with a Thread.Sleep prior to the Root.Reload but then the LoadFinished events never even get fired.
I also tried putting all of the UIView elements in a Dictionary to be added after they are all populated but it seems like as soon as InvokeOnMainThread ends the LoadFinished event handler never gets called again.
Do you have to use MT.Dialog? I would personal try to use UITableView instead. Load the web view content, determine its size (maybe use sizeThatFits?) and push it to the data source at correct location. Then return the size on the UITableViewDelegate's heightForRowAtIndexPath call. UITableView should take care of the rest.