2016-10-03 36 views
5

Piszę od zera rozwijając UITextView w mojej aplikacji swift. kładę textView na view tak:dziwne pozycjonowanie kursora w UITextView

enter image description here

jest tuż nad klawiaturą.

textView ma ograniczeń dołączone do view: leading, bottom, top i trailing wszystkie równa się = 4.

view ma następujące ograniczenia:

trailing, leading, bottom, top i height

Height jest wylot w moim kodu. Sprawdzam ile linie są w textView i na tej podstawie mam modyfikując height:

func textViewDidChange(textView: UITextView) { //Handle the text changes here 
    switch(textView.numberOfLines()) { 
    case 1: 
     heightConstraint.constant = 38 
     break 
    case 2: 
     heightConstraint.constant = 50 
     break 
    case 3: 
     heightConstraint.constant = 70 
     break 
    case 4: 
     heightConstraint.constant = 90 
     break 
    default: 
     heightConstraint.constant = 90 
     break 
    } 
} 

Liczba linii wyżej wyliczonych w tym rozszerzeniu:

extension UITextView{ 

    func numberOfLines() -> Int{ 
     if let fontUnwrapped = self.font{ 
      return Int(self.contentSize.height/fontUnwrapped.lineHeight) 
     } 
     return 0 
    } 
} 

początkowej wysokości textView to 38. Początkowy rozmiar czcionki w textView to 15.

Teraz działa dobrze, gdy użytkownik zaczyna pisać nową linię, ale textView nie jest ustawiony w pełnym zakresie widoku. Mam na myśli fakt, że wygląda to tak:

enter image description here

i powinno to wyglądać tak:

enter image description here

Dlaczego jest to dodatkowe spacje są dodawane i jak można Pozbywam się tego?

Obecnie, gdy pojawia się nowa linia, pojawia się biała przestrzeń, ale kiedy użytkownik przewinie numer textView, aby wyśrodkować tekst i pozbyć się białej przestrzeni - zniknie na zawsze, użytkownik nie będzie mógł go ponownie przewinąć, więc biała linia jest tu. Dla mnie wygląda to na problem z odświeżaniem treści, ale może wiesz lepiej - czy możesz podać mi jakieś wskazówki?

+0

nie wiem dokładnie, zmieniając Domyślam ** ScrollingEnabled NO ** może pracować .. – Gokul

+0

hmm @Gokul może to pomóc, ale muszę 'scrollingEnabled' do' true' ponieważ jeśli istnieje więcej niż 4 wiersze tekstu, a "textView" nie rośnie i użytkownik może przewijać zawartość w nim ... – user3766930

+0

czy zbudowałeś aplikację do czatowania? –

Odpowiedz

3

Oto nieco inne podejście, którego używam w sekcji komentarzy jednej z aplikacji, które rozwijam. Działa to bardzo podobnie do pola wejściowego aplikacji Facebook Messenger iOS. Zmieniono nazwy placówek, aby pasowały do ​​nazw w pytaniu.

//Height constraint outlet of view which contains textView. 
@IBOutlet weak var heightConstraint: NSLayoutConstraint! 
@IBOutlet weak var textView: UITextView! 

//Maximum number of lines to grow textView before enabling scrolling. 
let maxTextViewLines = 5 
//Minimum height for textViewContainer (when there is no text etc.) 
let minTextViewContainerHeight = 40 

func textViewDidChange(textView: UITextView) { 
    let textViewVerticalInset = textView.textContainerInset.bottom + textView.textContainerInset.top 
    let maxHeight = ((textView.font?.lineHeight)! * maxTextViewLines) + textViewVerticalInset 
    let sizeThatFits = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max)) 

    if sizeThatFits.height < minTextViewContainerHeight { 
     heightConstraint.constant = minTextViewContainerHeight 
     textView.scrollEnabled = false 
    } else if sizeThatFits.height < maxHeight { 
     heightConstraint.constant = sizeThatFits.height 
     textView.scrollEnabled = false 
    } else { 
     heightConstraint.constant = maxHeight 
     textView.scrollEnabled = true 
    } 
} 

func textViewDidEndEditing(textView: UITextView) { 
    textView.text = "" 
    heightConstraint.constant = minTextViewContainerHeight 
    textView.scrollEnabled = false 
} 
-1

Używam ASTextInputAccessoryView.Obsługuje wszystko dla ciebie i jest bardzo łatwy do skonfigurowania:

enter image description here

import ASTextInputAccessoryView 

class ViewController: UIViewController { 

    var iaView: ASResizeableInputAccessoryView!  
    var messageView = ASTextComponentView() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let photoComponent = UINib 
      .init(nibName: "PhotosComponentView", bundle: nil) 
      .instantiateWithOwner(self, options: nil) 
      .first as! PhotosComponentView 

     messageView = ASTextComponentView(frame: CGRect(x: 0, y: 0, width: screenSize.width , height: 44)) 
     messageView.backgroundColor = UIColor.uIColorFromHex(0x191919) 
     messageView.defaultSendButton.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside) 

     iaView = ASResizeableInputAccessoryView(components: [messageView, photoComponent]) 
     iaView.delegate = self   
    } 
} 

//MARK: Input Accessory View 
extension ViewController { 
    override var inputAccessoryView: UIView? { 
     return iaView 
    } 

    // IMPORTANT Allows input view to stay visible 
    override func canBecomeFirstResponder() -> Bool { 
     return true 
    } 

    // Handle Rotation 
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 
     super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 

     coordinator.animateAlongsideTransition({ (context) in 
      self.messageView.textView.layoutIfNeeded() 
     }) { (context) in 
      self.iaView.reloadHeight() 
     } 
    } 
} 

// MARK: ASResizeableInputAccessoryViewDelegate 
extension ViewController: ASResizeableInputAccessoryViewDelegate { 

    func updateInsets(bottom: CGFloat) { 
     var contentInset = tableView.contentInset 
     contentInset.bottom = bottom 
     tableView.contentInset = contentInset 
     tableView.scrollIndicatorInsets = contentInset 
    } 

    func inputAccessoryViewWillAnimateToHeight(view: ASResizeableInputAccessoryView, height: CGFloat, keyboardHeight: CGFloat) -> (() -> Void)? { 

     return { [weak self] in 
      self?.updateInsets(keyboardHeight) 
      self?.tableView.scrollToBottomContent(false) 
     } 
    } 

    func inputAccessoryViewKeyboardWillPresent(view: ASResizeableInputAccessoryView, height: CGFloat) -> (() -> Void)? { 
     return { [weak self] in 
      self?.updateInsets(height) 
      self?.tableView.scrollToBottomContent(false) 
     } 
    } 

    func inputAccessoryViewKeyboardWillDismiss(view: ASResizeableInputAccessoryView, notification: NSNotification) -> (() -> Void)? { 
     return { [weak self] in 
      self?.updateInsets(view.frame.size.height) 
     } 
    } 

    func inputAccessoryViewKeyboardDidChangeHeight(view: ASResizeableInputAccessoryView, height: CGFloat) { 
     let shouldScroll = tableView.isScrolledToBottom 
     updateInsets(height) 
     if shouldScroll { 
      self.tableView.scrollToBottomContent(false) 
     } 
    } 
} 

Teraz wystarczy skonfigurować akcje dla przycisków na AccessoryView.

// MARK: Actions 
extension ViewController { 

    func buttonAction(sender: UIButton!) { 

     // do whatever you like with the "send" button. for example post stuff to firebase or whatever 
     // messageView.textView.text <- this is the String inside the textField 

     messageView.textView.text = "" 
    } 

    @IBAction func dismissKeyboard(sender: AnyObject) { 
     self.messageView.textView.resignFirstResponder() 
    } 

    func addCameraButton() { 

     let cameraButton = UIButton(type: .Custom) 
     let image = UIImage(named: "camera")?.imageWithRenderingMode(.AlwaysTemplate) 
     cameraButton.setImage(image, forState: .Normal) 
     cameraButton.tintColor = UIColor.grayColor() 

     messageView.leftButton = cameraButton 

     let width = NSLayoutConstraint(
      item: cameraButton, 
      attribute: .Width, 
      relatedBy: .Equal, 
      toItem: nil, 
      attribute: .NotAnAttribute, 
      multiplier: 1, 
      constant: 40 
     ) 
     cameraButton.superview?.addConstraint(width) 

     cameraButton.addTarget(self, action: #selector(self.showPictures), forControlEvents: .TouchUpInside) 
    } 

    func showPictures() { 

     PHPhotoLibrary.requestAuthorization { (status) in 
      NSOperationQueue.mainQueue().addOperationWithBlock({ 
       if let photoComponent = self.iaView.components[1] as? PhotosComponentView { 
        self.iaView.selectedComponent = photoComponent 
        photoComponent.getPhotoLibrary() 
       } 
      }) 
     } 
    } 
} 
+1

downvote przynajmniej troszczy się o komentarz? Przysięgam, że to było "taktyczne pochylenie" przez współbieżną odpowiedź, karma cię zniszczy –