public override void ViewWillAppear(bool animated) { base.ViewWillAppear(animated); View.AddGestureRecognizer(new UITapGestureRecognizer(() => View.EndEditing(true))); // https://gist.github.com/patridge/8984934 keyboardShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, (notification) => { NSValue nsKeyboardBounds = (NSValue)notification.UserInfo.ObjectForKey(UIKeyboard.BoundsUserInfoKey); RectangleF keyboardBounds = nsKeyboardBounds.RectangleFValue; float height = (float)(View.Bounds.Height - keyboardBounds.Height); if (NavigationController != null && NavigationController.TabBarController != null && NavigationController.TabBarController.TabBar != null) { // Re-add tab bar height since it is hidden under keyboard but still excluded from View.Bounds.Height. height += (float)NavigationController.TabBarController.TabBar.Frame.Height; } container.Frame = new RectangleF((System.Drawing.PointF)container.Frame.Location, new SizeF((float)View.Bounds.Width, height)); }); keyboardHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, (notification) => { UIApplication.EnsureUIThread(); container.Frame = new RectangleF((System.Drawing.PointF)container.Frame.Location, (System.Drawing.SizeF)View.Bounds.Size); }); }
public static void EnsureMainThread() { #if PLATFORM_IOS UIApplication.EnsureUIThread(); #elif PLATFORM_ANDROID if (Looper.MyLooper() != Looper.MainLooper) { throw new InvalidOperationException("Trying to run UI code from non-ui thread."); } #else throw new NotImplementedException("EnsureMainThread is not implemented on this platform."); #endif }
void resetupAll(IReadOnlyList <TSectionInfo> newSectionInfo) { this.Log().Debug("SectionInfo changed to {0}, resetup data and bindings...", newSectionInfo); UIApplication.EnsureUIThread(); if (newSectionInfo == null) { this.Log().Debug("Null SectionInfo, done!"); setupDisp.Disposable = Disposable.Empty; return; } // Disposable that holds garbage from this method. var disp = new CompositeDisposable(); setupDisp.Disposable = disp; // Disposable that holds the subscriptions to individual sections. var subscrDisp = new SerialDisposable(); disp.Add(subscrDisp); // Decide when we should check for section changes. var reactiveSectionInfo = newSectionInfo as IReactiveNotifyCollectionChanged; var sectionChanging = reactiveSectionInfo == null?Observable.Never <Unit>() : reactiveSectionInfo .Changing .Select(_ => Unit.Default); var sectionChanged = reactiveSectionInfo == null?Observable.Return(Unit.Default) : reactiveSectionInfo .Changed .Select(_ => Unit.Default) .StartWith(Unit.Default); if (reactiveSectionInfo == null) { this.Log().Warn("New section info {0} does not implement IReactiveNotifyCollectionChanged.", newSectionInfo); } // Add section change listeners. Always will run once right away // due to sectionChanged's construction. // // TODO: Instead of listening to Changed events and then reseting, // we could listen to more specific events and avoid some reloads. disp.Add(sectionChanging.Subscribe(_ => { // Dispose the old bindings. Ensures that old events won't // arrive while we morph into the new data. this.Log().Debug("{0} is about to change, disposing section bindings...", newSectionInfo); subscrDisp.Disposable = Disposable.Empty; })); disp.Add(sectionChanged.Subscribe(_ => { this.Log().Debug("{0} is changed, resetup section data and bindings...", newSectionInfo); UIApplication.EnsureUIThread(); var disp2 = new CompositeDisposable(); subscrDisp.Disposable = disp2; for (int i = 0; i < newSectionInfo.Count; i++) { var section = i; var current = newSectionInfo[i].Collection; this.Log().Debug("Setting up section {0} binding...", section); disp2.Add(current .Changed .Select(timestamped) .Buffer(TimeSpan.FromMilliseconds(250), RxApp.MainThreadScheduler) .Subscribe( xs => sectionCollectionChanged(section, xs), ex => this.Log().ErrorException("Error while watching section " + i + "'s Collection.", ex))); } this.Log().Debug("Done resetuping section data and bindings!"); // Tell the view that the data needs to be reloaded. this.Log().Debug("Calling ReloadData()...", newSectionInfo); adapter.ReloadData(); })); this.Log().Debug("Done resetuping all bindings!"); }
void AddObservers() { keyboardWillShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, (notification) => { // In iOS when there is a change of keyboard the WillShow and DidShow events are fired again without // the HideXXXX events. // If we are already visible then this is probably a change of keyboard so we will // not attach our event handlers again or we will get multiple events on key input. if (!IsVisible) { hiddenKeyInput.DeleteBackwardEvent += OnDeleteBackwardEvent; hiddenKeyInput.InsertTextEvent += OnInsertTextEvent; } OnKeyboardWillShow(); } ); keyboardDidShowObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.DidShowNotification, (notification) => { IsVisible = true; OnKeyboardDidShow(); } ); keyboardWillHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, (notification) => { UIApplication.EnsureUIThread(); OnKeyboardWillHide(); } ); keyboardDidHideObserver = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.DidHideNotification, (notification) => { UIApplication.EnsureUIThread(); // Remove our hiddenKeyInput event listeners. hiddenKeyInput.DeleteBackwardEvent -= OnDeleteBackwardEvent; hiddenKeyInput.InsertTextEvent -= OnInsertTextEvent; // Remove it from it's view hiddenKeyInput.RemoveFromSuperview(); hiddenKeyInput = null; // Remove the notifications NSNotificationCenter.DefaultCenter.RemoveObserver(keyboardWillShowObserver); NSNotificationCenter.DefaultCenter.RemoveObserver(keyboardDidShowObserver); NSNotificationCenter.DefaultCenter.RemoveObserver(keyboardWillHideObserver); NSNotificationCenter.DefaultCenter.RemoveObserver(keyboardDidHideObserver); IsVisible = false; OnKeyboardDidHide(); } ); }