0

이 샘플 코드를 사용하여 간단한 채팅을 만듭니다.Xamarin.iOS : 키보드 위 툴바 이동

Chat

이 예는있는 navigationController없이 모든 것이 잘 작동합니다. 키보드가 나타나면 도구 모음이 위로 이동합니다. 그러나 NavigationController에 넣으면 키보드가 움직이지 않지만 View는 움직입니다. 키보드에 textview inputAccessoryView를 설정하려고했지만 작동하지 않습니다. 스택 오버 플로우의 다른 솔루션은 탐색 컨트롤러의 툴바를 사용할 때 포함됩니다. 그러나 이것은

public class ChatViewController : UIViewController 
{ 
    public MessageContacts chatWith; 

    NSObject willShowToken; 
    NSObject willHideToken; 

    List<Message> messages; 
    ChatSource chatSource; 

    UITableView tableView; 
    UIToolbar toolbar; 

    NSLayoutConstraint toolbarBottomConstraint; 
    NSLayoutConstraint toolbarHeightConstraint; 

    ChatInputView chatInputView; 

    UIButton SendButton 
    { 
     get 
     { 
      return chatInputView.SendButton; 
     } 
    } 

    UITextView TextView 
    { 
     get 
     { 
      return chatInputView.TextView; 
     } 
    } 

    bool IsInputToolbarHasReachedMaximumHeight 
    { 
     get 
     { 
      return toolbar.Frame.GetMinY() == TopLayoutGuide.Length; 
     } 
    } 

    public ChatViewController(IntPtr handle) 
     : base(handle) 
    { 
     messages = new List<Message>() { 
      new Message { Type = MessageType.Incoming, Text = "Hello!" }, 
      new Message { Type = MessageType.Outgoing, Text = "Hi!" }, 
      new Message { Type = MessageType.Incoming, Text = "Do you know about Xamarin?" }, 
      new Message { Type = MessageType.Outgoing, Text = "Yes! Sure!" }, 
      new Message { Type = MessageType.Incoming, Text = "And what do you think?" }, 
      new Message { Type = MessageType.Outgoing, Text = "I think it is the best way to develop mobile applications." }, 
      new Message { Type = MessageType.Incoming, Text = "Wow :-)" }, 
      new Message { Type = MessageType.Outgoing, Text = "Yep. Check it out\nhttp://Xamarin.com" }, 
      new Message { Type = MessageType.Incoming, Text = "Will do. Thanks" }, 
     }; 
    } 

    #region Life cycle 

    public override void ViewDidLoad() 
    { 
     base.ViewDidLoad(); 
     Title = chatWith.name; 
     SetUpTableView(); 
     SetUpToolbar(); 

     SendButton.TouchUpInside += OnSendClicked; 
     TextView.Started += OnTextViewStarted; 
     TextView.Changed += OnTextChanged; 

     TextView.InputAccessoryView = toolbar; 
    } 

    public override void ViewWillAppear(bool animated) 
    { 
     base.ViewWillAppear(animated); 

     willShowToken = UIKeyboard.Notifications.ObserveWillShow(KeyboardWillShowHandler); 
     willHideToken = UIKeyboard.Notifications.ObserveWillHide(KeyboardWillHideHandler); 

     UpdateTableInsets(); 
     UpdateButtonState(); 
     ScrollToBottom(false); 
    } 

    public override void ViewDidAppear(bool animated) 
    { 
     base.ViewDidAppear(animated); 
     AddObservers(); 
    } 

    #endregion 

    #region Initialization 

    void SetUpTableView() 
    { 
     tableView = new UITableView 
     { 
      TranslatesAutoresizingMaskIntoConstraints = false, 
      AllowsSelection = false, 
      SeparatorStyle = UITableViewCellSeparatorStyle.None, 
     }; 
     tableView.RegisterClassForCellReuse(typeof(IncomingCell), IncomingCell.CellId); 
     tableView.RegisterClassForCellReuse(typeof(OutgoingCell), OutgoingCell.CellId); 
     View.AddSubview(tableView); 

     var pinLeft = NSLayoutConstraint.Create(tableView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, View, NSLayoutAttribute.Leading, 1f, 0f); 
     View.AddConstraint(pinLeft); 

     var pinRight = NSLayoutConstraint.Create(tableView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, View, NSLayoutAttribute.Trailing, 1f, 0f); 
     View.AddConstraint(pinRight); 

     var pinTop = NSLayoutConstraint.Create(tableView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, TopLayoutGuide, NSLayoutAttribute.Bottom, 1f, 0f); 
     View.AddConstraint(pinTop); 

     var pinBottom = NSLayoutConstraint.Create(tableView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, View, NSLayoutAttribute.Bottom, 1f, 0f); 
     View.AddConstraint(pinBottom); 

     chatSource = new ChatSource(messages); 
     tableView.Source = chatSource; 
    } 

    void SetUpToolbar() 
    { 
     toolbar = new UIToolbar 
     { 
      TranslatesAutoresizingMaskIntoConstraints = false 
     }; 
     chatInputView = new ChatInputView 
     { 
      TranslatesAutoresizingMaskIntoConstraints = false 
     }; 

     View.AddSubview(toolbar); 

     var pinLeft = NSLayoutConstraint.Create(toolbar, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, View, NSLayoutAttribute.Leading, 1f, 0f); 
     View.AddConstraint(pinLeft); 

     var pinRight = NSLayoutConstraint.Create(toolbar, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, View, NSLayoutAttribute.Trailing, 1f, 0f); 
     View.AddConstraint(pinRight); 

     toolbarBottomConstraint = NSLayoutConstraint.Create(View, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, toolbar, NSLayoutAttribute.Bottom, 1f, 0f); 
     View.AddConstraint(toolbarBottomConstraint); 

     toolbarHeightConstraint = NSLayoutConstraint.Create(toolbar, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 0f, 44f); 
     View.AddConstraint(toolbarHeightConstraint); 

     toolbar.AddSubview(chatInputView); 
     var c1 = NSLayoutConstraint.FromVisualFormat("H:|[chat_container_view]|", 
      (NSLayoutFormatOptions)0, 
      "chat_container_view", chatInputView 
     ); 
     var c2 = NSLayoutConstraint.FromVisualFormat("V:|[chat_container_view]|", 
      (NSLayoutFormatOptions)0, 
      "chat_container_view", chatInputView 
     ); 
     toolbar.AddConstraints(c1); 
     toolbar.AddConstraints(c2); 


    } 

    #endregion 

    void AddObservers() 
    { 
     TextView.AddObserver(this, "contentSize", NSKeyValueObservingOptions.OldNew, IntPtr.Zero); 
    } 

    public override void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context) 
    { 
     if (keyPath == "contentSize") 
      OnSizeChanged(new NSObservedChange(change)); 
     else 
      base.ObserveValue(keyPath, ofObject, change, context); 
    } 

    void OnSizeChanged(NSObservedChange change) 
    { 
     CGSize oldValue = ((NSValue)change.OldValue).CGSizeValue; 
     CGSize newValue = ((NSValue)change.NewValue).CGSizeValue; 

     var dy = newValue.Height - oldValue.Height; 
     AdjustInputToolbarOnTextViewSizeChanged(dy); 
    } 

    void AdjustInputToolbarOnTextViewSizeChanged(nfloat dy) 
    { 
     bool isIncreasing = dy > 0; 
     if (IsInputToolbarHasReachedMaximumHeight && isIncreasing) 
     { 
      // TODO: scroll to bottom 
      return; 
     } 

     nfloat oldY = toolbar.Frame.GetMinY(); 
     nfloat newY = oldY - dy; 
     if (newY < TopLayoutGuide.Length) 
      dy = oldY - TopLayoutGuide.Length; 

     AdjustInputToolbar(dy); 
    } 

    void AdjustInputToolbar(nfloat change) 
    { 
     toolbarHeightConstraint.Constant += change; 

     if (toolbarHeightConstraint.Constant < ChatInputView.ToolbarMinHeight) 
      toolbarHeightConstraint.Constant = ChatInputView.ToolbarMinHeight; 

     View.SetNeedsUpdateConstraints(); 
     View.LayoutIfNeeded(); 
    } 

    void KeyboardWillShowHandler(object sender, UIKeyboardEventArgs e) 
    { 
     UpdateButtomLayoutConstraint(e); 
    } 

    void KeyboardWillHideHandler(object sender, UIKeyboardEventArgs e) 
    { 
     UpdateButtomLayoutConstraint(e); 
    } 

    void UpdateButtomLayoutConstraint(UIKeyboardEventArgs e) 
    { 
     UIViewAnimationCurve curve = e.AnimationCurve; 
     UIView.Animate(e.AnimationDuration, 0, ConvertToAnimationOptions(e.AnimationCurve),() => 
     { 
      nfloat offsetFromBottom = tableView.Frame.GetMaxY() - e.FrameEnd.GetMinY(); 
      offsetFromBottom = NMath.Max(0, offsetFromBottom); 
      SetToolbarContstraint(offsetFromBottom); 
     }, null); 
    } 

    void SetToolbarContstraint(nfloat constant) 
    { 
     toolbarBottomConstraint.Constant = constant; 
     View.SetNeedsUpdateConstraints(); 
     View.LayoutIfNeeded(); 

     UpdateTableInsets(); 
    } 

    void UpdateTableInsets() 
    { 
     nfloat bottom = tableView.Frame.GetMaxY() - toolbar.Frame.GetMinY(); 
     UIEdgeInsets insets = new UIEdgeInsets(0f, 0f, bottom, 0f); 
     tableView.ContentInset = insets; 
     tableView.ScrollIndicatorInsets = insets; 
    } 

    UIViewAnimationOptions ConvertToAnimationOptions(UIViewAnimationCurve curve) 
    { 
     // Looks like a hack. But it is correct. 
     // UIViewAnimationCurve and UIViewAnimationOptions are shifted by 16 bits 
     // http://stackoverflow.com/questions/18870447/how-to-use-the-default-ios7-uianimation-curve/18873820#18873820 
     return (UIViewAnimationOptions)((int)curve << 16); 
    } 

    void OnSendClicked(object sender, EventArgs e) 
    { 
     var text = TextView.Text; 
     TextView.Text = string.Empty; // this will not generate change text event 
     UpdateButtonState(); 

     if (string.IsNullOrWhiteSpace(text)) 
      return; 

     var msg = new Message 
     { 
      Type = MessageType.Outgoing, 
      Text = text.Trim() 
     }; 

     messages.Add(msg); 
     tableView.InsertRows(new NSIndexPath[] { NSIndexPath.FromRowSection(messages.Count - 1, 0) }, UITableViewRowAnimation.None); 
     ScrollToBottom(true); 
    } 

    void OnTextViewStarted(object sender, EventArgs e) 
    { 
     ScrollToBottom(true); 
    } 

    void OnTextChanged(object sender, EventArgs e) 
    { 
     UpdateButtonState(); 
    } 

    void UpdateButtonState() 
    { 
     SendButton.Enabled = !string.IsNullOrWhiteSpace(TextView.Text); 
    } 

    public override void ViewWillDisappear(bool animated) 
    { 
     base.ViewWillDisappear(animated); 

     willShowToken.Dispose(); 
     willHideToken.Dispose(); 
    } 

    void ScrollToBottom(bool animated) 
    { 
     if (tableView.NumberOfSections() == 0) 
      return; 

     int items = (int)tableView.NumberOfRowsInSection(0); 
     if (items == 0) 
      return; 

     int finalRow = (int)NMath.Max(0, tableView.NumberOfRowsInSection(0) - 1); 
     NSIndexPath finalIndexPath = NSIndexPath.FromRowSection(finalRow, 0); 
     tableView.ScrollToRow(finalIndexPath, UITableViewScrollPosition.Top, animated); 
    } 
} 

답변

0

이 샘플은 정말 형제 똥, 버그가 많이 존재입니다 ...

어떤 도움에 감사드립니다 ... 사용자 정의 만든 도구 모음입니다. viewDidLoad에 먼저 등록 이벤트에

: 키보드 문제에 대한

, 나는 당신이 그 코드를 사용하는 것이 좋습니다

[Action("keyboardWillShow:")] 
    private void KeyboardWillShow(NSNotification notification) 
    { 
     NSDictionary info = notification.UserInfo; 
     CGSize kbSize = (info.ObjectForKey(UIKeyboard.FrameEndUserInfoKey) as NSValue).CGRectValue.Size; 
     nfloat keyboardHeight = kbSize.Height; 

     CGRect tmpR = this.View.Frame; 
     tmpR.Y -= keyboardHeight; 
     this.View.Frame = tmpR; 
    } 

    [Action("keyboardWillHide:")] 
    private void KeyboardWillHide(NSNotification notification) 
    { 
     this.View.Frame = UIScreen.MainScreen.Bounds; 
    } 

:

public override void ViewDidLoad() 
    { 
     //Smaples codes 
     base.ViewDidLoad(); 

     SetUpTableView(); 
     SetUpToolbar(); 

     SendButton.TouchUpInside += OnSendClicked; 
     TextView.Started += OnTextViewStarted; 
     TextView.Changed += OnTextChanged; 

     //Create by me 
     this.View.AddGestureRecognizer(new UITapGestureRecognizer(()=>{ 
      this.View.EndEditing(true); 
     })); 

     NSNotificationCenter.DefaultCenter.AddObserver(this,new ObjCRuntime.Selector("keyboardWillShow:"),UIKeyboard.WillShowNotification,null); 
     NSNotificationCenter.DefaultCenter.AddObserver(this,new ObjCRuntime.Selector("keyboardWillHide:"),UIKeyboard.WillHideNotification,null); 
    } 

그런 다음 키보드 이벤트를 처리하는 사람들을 사용 그리고 제가 전에 썼던 chat view를위한 매우 간단한 모델이 Objective-C에 의해 만들어졌습니다. 아주 간단하게 보일 수 있습니다.

simple model for chat view

나는 그것이 후자 확인합니다, 당신이 여전히 도움이 필요하면, 그냥 여기두고, 당신을 도울 수 있기를 바랍니다.