The button control in xamarin I am using has some very different issue that I haven't met before. The issue is that If I tap on the button very fast and continuously for many times it processing all the taps very slowly. It is visibly irritating that it keep on blinking even after I stopped.
Below is my code
UI Creation Code
QRButton = new Button
{
Text="Title",
TextColor = Color.White,
BackgroundColor = Color.FromHex("#0064A4"),
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Center,
WidthRequest = 250.0,
BorderRadius = 0
};
//add event handler
QRButton.Clicked += QRButtonPressed;
Button Action
private void QRButtonPressed(object sender, EventArgs e)
{
Console.WriteLine("QR Generation Started");
// Some long running process
Console.WriteLine("QR Generation Completed");
}
The Renderer Implementation
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if(e.NewElement!=null)
{
Control.TitleEdgeInsets = new UIEdgeInsets(4, 4, 4, 4);
Control.TitleLabel.LineBreakMode = UILineBreakMode.WordWrap;
Control.TitleLabel.TextAlignment = UITextAlignment.Center;
}
}
Related
I'm trying to create a Material Button programmatically in Xamarin.Android and attaching this to a TableRow which is in turn attached to a Table. In OnCreate, I SetContentView before calling the CreateButtons() function below. When I use SetMinHeight() inside the function, the button shows but the min height doesn't appear to work. However, when this code is added to the click event and the button is pressed, it updates the button correctly.
The function that loads with the Activity:
public void CreateButtons()
{
var tableLayout = FindViewById<TableLayout>(Resource.Id.tableLayout1);
TableRow.LayoutParams buttonParams = new TableRow.LayoutParams(
0,
TableRow.LayoutParams.WrapContent,
1.0f
);
buttonParams.SetMargins(3, 3, 3, 3);
TableRow tr = new TableRow(this);
tr.LayoutParameters = new TableRow.LayoutParams(
TableRow.LayoutParams.WrapContent,
TableRow.LayoutParams.WrapContent
);
MaterialButton button = new MaterialButton(this);
button.Text = "Test Button";
button.TextAlignment = TextAlignment.Center;
button.IconSize = 158;
button.Icon = GetDrawable(Resource.Drawable.goodsin);
button.IconGravity = 16;
button.Click += Button_Click;
button.LayoutParameters = buttonParams;
button.SetMinHeight(126);
tr.AddView(button);
tableLayout.AddView(tr);
}
The button after the function has generated it, cutting the text off:
The code inside the button click event:
private void Button_Click(object sender, EventArgs e)
{
var button = (MaterialButton)sender;
button.SetMinHeight(126);
}
The button after the click event has completed, now showing the correct size and text:
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:).
I'm trying to build a Chat app UI, the idea of the Layout was pretty simple:
When the input bar is focused, keyboard show up and "push" up the chat bar, as it's a grid, the ListView will resize to fit the screen:
I update the input bar's margin to "push" it up:
NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
CGSize keyboardSize = result.RectangleFValue.Size;
if (Element != null){
Element.Margin = new Thickness(0, 0, 0,keyboardSize.Height); //push the entry up to keyboard height when keyboard is activated
}
And this is the result:
https://drive.google.com/file/d/1S9yQ6ks15BRH3hH0j_M8awpDJFRFitUi/view?usp=sharing
The view did push up and the ListView also resized as expected, however there are two issues that I had no idea how to solve it:
How can I retain the ListView scroll position after resize?
Lack of animation to push up the view
I have search over the web, tried IQKeyboardManager and KeyboardOverLap, The push up animation is nice and smooth, however strange things happened:
https://drive.google.com/file/d/1Zm0lMKB3wq07ve67wlcvLuNM_6Waad7R/view?usp=sharing
Instead of resizing the ListView, this approach Push the entire ListView up, that I cannot see the first few items, of course the scroll bar can be scroll out of screen
Extra strange spaces at the bottom of the ListView
Any help will be appreciated, thank you!
Solution:
void OnKeyboardShow(object sender, UIKeyboardEventArgs args)
{
NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
CGSize keyboardSize = result.RectangleFValue.Size;
if (Control != null)
{
int bottomMargin = 0;
var sa = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets;
bottomMargin = (int)sa.Bottom;
CGPoint offset = Control.ContentOffset;
var difference = keyboardSize.Height - bottomMargin;
if (Control.ContentSize.Height > Control.Frame.Height)
{
offset.Y += difference;
Control.SetContentOffset(offset, true);
}
else if (Control.ContentSize.Height + keyboardSize.Height > Control.Frame.Height)
{
offset.Y += Control.ContentSize.Height + keyboardSize.Height - Control.Frame.Height - bottomMargin;
Control.SetContentOffset(offset, true);
}
Control.ContentInset = new UIEdgeInsets(0, 0, difference, 0);
Control.ScrollIndicatorInsets = Control.ContentInset;
}
}
void OnKeyboardHide(object sender, UIKeyboardEventArgs args)
{
if (Control != null)
{
Control.ContentInset = new UIEdgeInsets(0, 0, 0, 0);
Control.ScrollIndicatorInsets = new UIEdgeInsets(0, 0, 0, 0);
}
}
Solution:
Refer the following code
in iOS Custom Renderer
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.KeyboardDismissMode = UIScrollViewKeyboardDismissMode.OnDrag;
NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("KeyBoardWillShow:"), new NSString("UIKeyboardWillShowNotification"), null);
NSNotificationCenter.DefaultCenter.AddObserver(this, new Selector("KeyBoardWillHide:"), new NSString("UIKeyboardWillHideNotification"), null);
}
}
[Export("KeyBoardWillShow:")]
void KeyBoardWillShow(NSNotification note)
{
NSValue keyboardRect = (NSValue)note.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
Control.ContentInset = new UIEdgeInsets(0,0, keyboardRect.RectangleFValue.Size.Height,0);
}
[Export("KeyBoardWillHide:")]
void KeyBoardWillHide(NSNotification note)
{
Control.ContentInset = UIEdgeInsets.Zero;
}
I got a UIViewController that init a UIView.
This view containing Interactive Elements like UITextField or UIButton.
View is added on ViewDidLoad, at the bottom of the method to be sure that when I made it visible it can be reach by user interaction.
But when I show the view, no interaction can be done on this View.
Is this only possible? Am I doing something wrong?
The View
public class AddBusinessEventView : UIView
{
public UILabel LblTitle;
public UITextField TxtType;
public UIButton BtnClose;
public AddBusinessEventView(nfloat bw, nfloat bh)
{
//Bouton pour fermer le popup
BtnClose = new UIButton();
BtnClose.SetImage(UIImage.FromFile("Images/Boutons/lightbox_close.png"), UIControlState.Normal);
BtnClose.Frame = new CGRect(bw - 80, 30, BtnFermer.ImageView.Image.CGImage.Width * 0.5, BtnFermer.ImageView.Image.CGImage.Height * 0.5);
//Doit se trouver par dessus txtSite et ajouté après dans la vue pour se trouvé en premier plan
LblTitle = new UILabel();
LblTitle.Frame = new CGRect((bw - (lw + 200)) / 2, 100, lw + 200, 30);
LblTitle.Text = "Fill with your event elements";
LblTitle.Font = UIFont.FromName("GillSans-Bold", 22);
LblTitle.TextColor = UIColor.FromRGB(211, 3, 67);
LblTitle.TextAlignment = UITextAlignment.Center;
TxtType = new UITextField(new CGRect((bw - 750) / 2, 140, 350, 40));
TxtType.BackgroundColor = UIColor.White;
TxtType.TextAlignment = UITextAlignment.Center;
TxtType.BorderStyle = UITextBorderStyle.RoundedRect;
TxtType.AutocorrectionType = UITextAutocorrectionType.No;
TxtType.AutocapitalizationType = UITextAutocapitalizationType.AllCharacters;
TxtType.Placeholder = "Type";
AddSubviews(BtnClose, LblTitle, TxtType);
}
}
The UIViewController
partial class EvenementViewController : EnhancedUIViewController
{
AddBusinessEventView AddBusinessEventView;
public EvenementViewController(IntPtr handle) : base(handle) { }
public EvenementViewController() : base() { }
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (myEvent == null)
{
ShowAddBusinessEventView();
}
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
nfloat bw = View.Bounds.Width;
nfloat bh = View.Bounds.Height;
//Another Elements are adding to view here
//...
AddBusinessEventView = new AddBusinessEventView(bw, bh);
AddBusinessEventView.Hidden = true;
//Much more View.Add with all elements here
//...
View.Add(AddBusinessEventView);
AddBusinessEventView.BtnType.TouchUpInside += BtnClose_TouchUpInside;
}
#region BusinessEventAdd
void ShowAddBusinessEventView()
{
UIView.Animate(duration: 1,
delay: 0,
options: UIViewAnimationOptions.CurveEaseInOut,
animation: () =>
{
AddBusinessEventView.Alpha = 1.0f;
},
completion: () =>
{
AddBusinessEventView.Hidden = false;
AddBusinessEventListener();
}
);
}
void HideAddBusinessEventView()
{
UIView.Animate(duration: 1,
delay: 0,
options: UIViewAnimationOptions.CurveEaseInOut,
animation: () =>
{
AddBusinessEventView.Alpha = 0.0f;
},
completion: () =>
{
AddBusinessEventView.Hidden = true;
RemoveBusinessEventListener();
}
);
}
void BtnClose_TouchUpInside(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Touching myself");
}
#endregion
}
please concidere EnhancedViewController as standard UIViewController, I'm juste adding some enhancements to show users a message from an Overlay.
As I said, we can't interact neither with TxtType nor BtnClose.
Edit :
Don't sure if it can help; but when the View is added to the Main View on the UIViewController, it display well, but all user interaction are catches on element under this View
i.e : The AddBusinessEventView act as a popup, so it covered all other element, when i press an element, if another element adding prior of this View is under, it's this element rather than the AddBusinessEventView element that catch the touch event.
As said, the main purpose is to cut View element on different file for more readability and maintenability of this application.enter code here
There is no reason you can't do that.
You can architect your code like
UIViewController
Controller1
Controller2
...
Views
View1
View2
...
And then use View1 and View2 in any of Controller.
I tried your code and I got all the things popup correctly.
As you said, if view show up on screen but it's element from another View from below that interact with user maybe you can try to bring your View to front.
Try this
View.BringSubviewToFront(AddBusinessEventView);
At the end of your ViewDidLoad function.
I need to be able to select day and month and leave the option to the user to select the year or not. For example I was thinking a list with all the years and at the end an added option "no selection".
Any ideas how to do that?
I suppose that using the picker view is one solution but not sure.
Thanks
Using xamarin.ios what I did was create a toolbar on top of the thumbwheel with a Done and a Cancel buttons. When you click done the value is set, and you click cancel what you need to do is set the Datepicker value to a value like 1900-1-1 and change the uitextfield value to something like "Not set".
I'm using xamarin forms. This is what I have in my custom renderer:
public override void Draw (CGRect rect)
{
base.Draw (rect);
DatePicker elem = (DatePicker)Element;
UITextField textField = (UITextField)Control;
var toolbar = new UIToolbar(new CGRect(0.0f, 0.0f, Control.Frame.Size.Width, 44.0f));
toolbar.Items = new[]
{
new UIBarButtonItem(UIBarButtonSystemItem.Cancel,(object sender, EventArgs e) => {
if (elem.SetValueNullAction!=null){
elem.SetValueNullAction();
textField.Text = DefaultNotSetText;
}
}),
new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace),
new UIBarButtonItem(UIBarButtonSystemItem.Done,(object sender, EventArgs e) => {
elem.Unfocus();
})
};
textField.InputAccessoryView = toolbar;
textField.BorderStyle = UITextBorderStyle.None;
textField.TextColor = Color.FromHex ("999999").ToUIColor ();
CGRect frame = textField.Frame;
frame.Width = 100;
textField.Frame = frame;
if (elem.Date == elem.MinimumDate) {
textField.Text = ((DatePicker)this.Element).Label;
}
}
Hope this helps!
You can have a try of CKPickerView, it allows very easy customization on UIDatePicker.