2017-11-13 2 views
1

UIViewController 내부에 하위 뷰를 추가했습니다. 이 하위 뷰 (PlayerView)에는 두 가지 상태가 있어야합니다. 하나는 높이가 56 인 축소 상태입니다. 펼쳐진 상태의 높이는 385입니다. 하위보기가 축소에서 확장으로 변경되면 PlayerView 내의 하위보기에서 모양과 위치를 변경해야합니다. PlayerView가있는 UIViewController (MasterViewController)에 추가 될 때버튼을 눌렀을 때 앵커/제약 조건 변경

, 그것과 같이() layoutSubviews를 사용하여 축소 된보기를 누르면

override func layoutSubviews() { 
    super.layoutSubviews() 

    backgroundColor = UIColor(red: 24/255, green: 24/255, blue: 24/255, alpha: 1) 

    roundCorners([.topLeft, .topRight], radius: 10) 


    addSubview(albumImage) 
    addSubview(songTitleLabel) 
    addSubview(songArtistLabel) 
    addSubview(playPauseButton) 

    _ = albumImage.anchor(nil, left: leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 20, bottomConstant: 0, rightConstant: 0, widthConstant: 40, heightConstant: 40) 
    albumImage.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true 
    _ = playPauseButton.anchor(nil, left: nil, bottom: nil, right: rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 30, widthConstant: 22, heightConstant: 22) 
    _ = songTitleLabel.anchor(albumImage.topAnchor, left: albumImage.rightAnchor, bottom: nil, right: playPauseButton.leftAnchor, topConstant: 0, leftConstant: 8, bottomConstant: 0, rightConstant: 8, widthConstant: songTitleLabel.frame.width, heightConstant: songTitleLabel.frame.height) 
    _ = songArtistLabel.anchor(songTitleLabel.bottomAnchor, left: songTitleLabel.leftAnchor, bottom: nil, right: playPauseButton.leftAnchor, topConstant: 2, leftConstant: 8, bottomConstant: 0, rightConstant: 8, widthConstant: songArtistLabel.frame.width, heightConstant: songArtistLabel.frame.height) 
    playPauseButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true 

} 

, 확장 할 예정이다.

let pv = PlayerView() 

func expandPlayerView() { 
    UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { 

     self.view.layoutIfNeeded() 
     self.pv.frame = CGRect(x: 0, y: CGFloat((self.view.frame.maxY) - 352), width: 375, height: 350) 
     self.pv.changePlayerView() 

     self.view.layoutSubviews() 
    }) { (true) in 

    } 
} 

changePlayerView() 기능은 다음과 같이 정의된다 :

실행되는 코드의 결국 어떻게됩니까
func changePlayerView() { 
    subviews.forEach({$0.removeFromSuperview()}) 
    addSubview(playPauseButton) 
    playPauseButton.removeConstraints(playPauseButton.constraints)   

    _ = playPauseButton.anchor(nil, left: nil, bottom: bottomAnchor, right: nil, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 22, heightConstant: 22) 
    playPauseButton.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true   
} 

는 : 여기 (이 내 MasterViewController 내부에) 그 일에 대해 가서 어떻게 1. playerView는 385로 정밀도가 확장됩니다. 2. 다른 모든 하위 뷰는 플레이어에서 제거됩니다.3. 재생 일시 중지 단추는 거의 전체 PlayerView 하위 뷰를 차지하며 너비와 높이 제한이 22

playPauseButton이 모든 제약 조건을 준수하도록하려면 어떻게해야합니까?

편집 :

.anchor 기능과 같이있는 UIView의 확장에 정의되어

func anchor(_ top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0) -> [NSLayoutConstraint] { 
    translatesAutoresizingMaskIntoConstraints = false 

    var anchors = [NSLayoutConstraint]() 

    if let top = top{ 
     anchors.append(topAnchor.constraint(equalTo: top, constant: topConstant)) 
    } 
    if let left = left{ 
     anchors.append(leftAnchor.constraint(equalTo: left, constant: leftConstant)) 
    } 
    if let bottom = bottom{ 
     anchors.append(bottomAnchor.constraint(equalTo: bottom, constant: -bottomConstant)) 
    } 
    if let right = right{ 
     anchors.append(rightAnchor.constraint(equalTo: right, constant: -rightConstant)) 
    } 
    if widthConstant > 0{ 
     anchors.append(widthAnchor.constraint(equalToConstant: widthConstant)) 
    } 
    if heightConstant > 0{ 
     anchors.append(heightAnchor.constraint(equalToConstant: heightConstant)) 
    } 
    anchors.forEach({$0.isActive = true}) 
    return anchors 
} 
+0

난 당신의 코드를 살펴보기가 힘듭니다. 아마 코딩 스타일 차이 일 것입니다. 그러나 ** ** ** 정의되거나 명명 된 제약 조건이 없습니다. * 기존 제약 조건 배열을 활성화/비활성화하지 않습니다. 그것들은 정의 된 ** constraint **를 변경하는 두 가지 일반적인 방법입니다. 내가 놓친 게 있니? 바꾸어 말하면, 변경하고자하는 * 단일 * 제약 조건 (예 : 높이 또는 너비)을 변경하는 방법 (그리고 어쩌면)을 변경하려고합니다. – dfd

+0

하단 기능 '앵커'를보십시오. 그것이 제약 조건을 설정하는 방법입니다. –

+0

했습니다. 아직도 힘든 시간을 보내고 있습니다. * 구체적으로 당신이하려는 것은 무엇입니까? * 구체적으로 * 무엇이 문제입니까? 그리고 다시, 무엇이 변화하고 있습니까? (더 나은, 당신은 내가 실제로 재현 할 수있는 뭔가를 줄 수 있습니까? 편집 : 제약 조건을 변경했습니다. 슬라이딩 메뉴, 방향 변경 등. 게시 된 코드의 아무 것도 의미가 없습니다! ** ** ** 귀하의' anchor' 함수는'isActive = true'로 설정합니다. "버튼을 눌렀을 때의 제약 조건 변경"이라는 질문 제목에 간단히 표시되지 않습니다. – dfd

답변

0

난 당신의 코드에서 무슨 일이 일어나고 있는지 말할 수 없다,하지만 당신은 제약 조건을 매우 변경하려고 내가하는 것과는 다르게 여기에 내가 변화하는 제약 조건하는 경향이 작업은 다음과 같습니다

  • 선언 모든 consistant 또는 글로벌 제약 - isActive = true 설정 "평소와 같이"변경되지 않습니다 그 사람들은. 다시 쓰지 않아도됩니다.

  • 필요에 따라 한 번에 하나씩 배열로 변경되는 제약 조건을 명시 적으로 설정하십시오.

  • removeConstraints을 사용하지 마십시오! (아마도 개인적인 규칙 일 수도 있지만, 사용법을 잘 알지 못했습니다.) 대신 배열에 isActive을 설정하거나 NSLayoutConstraint.deactivateNSLayoutConstraint.activate을 사용하십시오.

  • 특정 필요가없는 한 하위 뷰를 제거하지 마십시오! 뷰 계층 구조에 문제가 생기면 누락되거나 불완전한 제약으로 끝날 위험이 있습니다. 대신 isHidden = true을 사용하십시오.

나는 그것이 당신의 결과의 원인이라고 생각하고 있습니다.

다음은 세로 및 가로 방향으로 두 개의 제약 조건 배열을 설정하는 예입니다.세로로 서로 위에 있지만 가로로 서로 옆에 있고 싶다는 두 가지 견해가 있다고 가정 해보십시오.

var p = [NSLayoutConstraint]() 
var l = [NSLayoutConstraint]() 
var initialOrientation = true 
var isInPortrait = false 

var greenView = UIView() 
var redView = UIView() 

override func viewDidLoad() { 
    super.viewDidLoad() 
    view.translatesAutoresizingMaskIntoConstraints = false 
    greenView.translatesAutoresizingMaskIntoConstraints = false 
    redView.translatesAutoresizingMaskIntoConstraints = false 

    greenView.backgroundColor = UIColor.green 
    redView.backgroundColor = UIColor.red 

    view.addSubview(greenView) 
    view.addSubview(redView) 

    setupConstraints() 

} 

override func viewWillLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    if initialOrientation { 
     initialOrientation = false 
     if view.frame.width > view.frame.height { 
      isInPortrait = false 
     } else { 
      isInPortrait = true 
     } 
     view.setOrientation(p, l) 
    } else { 
     if view.orientationHasChanged(&isInPortrait) { 
      view.setOrientation(p, l) 
     } 
    } 
} 

내가이 확장을 만들 : 내보기 컨트롤러에서

나는 두 가지보기가 있습니다. 다음은 뷰 컨트롤러의 확장입니다 :

나는 /이 두 배열을 비활성화 활성화 진짜 마법은 UIView 확장에
extension ViewController { 
    func setupConstraints() { 

     // create generic layout guides 

     let layoutGuideTop = UILayoutGuide() 
     view.addLayoutGuide(layoutGuideTop) 

     let layoutGuideBottom = UILayoutGuide() 
     view.addLayoutGuide(layoutGuideBottom) 

     let margins = view.layoutMarginsGuide 
     view.addLayoutGuide(margins) 

     if #available(iOS 11, *) { 
      let guide = view.safeAreaLayoutGuide 
      layoutGuideTop.topAnchor.constraintEqualToSystemSpacingBelow(guide.topAnchor, multiplier: 1.0).isActive = true 
      layoutGuideBottom.bottomAnchor.constraintEqualToSystemSpacingBelow(guide.bottomAnchor, multiplier: 1.0).isActive = true 
     } else { 
      layoutGuideTop.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true 
      layoutGuideBottom.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true 
     } 

     p.append(greenView.topAnchor.constraint(equalTo: layoutGuideTop.topAnchor)) 
     p.append(greenView.leadingAnchor.constraint(equalTo: margins.leadingAnchor)) 
     p.append(greenView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)) 
     p.append(greenView.heightAnchor.constraint(equalTo: redView.heightAnchor)) 

     p.append(redView.topAnchor.constraint(equalTo: greenView.bottomAnchor)) 
     p.append(redView.leadingAnchor.constraint(equalTo: margins.leadingAnchor)) 
     p.append(redView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)) 
     p.append(redView.bottomAnchor.constraint(equalTo: layoutGuideBottom.bottomAnchor)) 

     l.append(greenView.topAnchor.constraint(equalTo: layoutGuideTop.topAnchor)) 
     l.append(greenView.leadingAnchor.constraint(equalTo: margins.leadingAnchor)) 
     l.append(greenView.widthAnchor.constraint(equalTo: redView.widthAnchor)) 
     l.append(greenView.bottomAnchor.constraint(equalTo: layoutGuideBottom.bottomAnchor)) 

     l.append(redView.topAnchor.constraint(equalTo: layoutGuideTop.topAnchor)) 
     l.append(redView.leadingAnchor.constraint(equalTo: greenView.trailingAnchor)) 
     l.append(redView.bottomAnchor.constraint(equalTo: layoutGuideBottom.bottomAnchor)) 
     l.append(redView.trailingAnchor.constraint(equalTo:margins.trailingAnchor)) 
    } 
} 

: 나는 제약 조건을 변경

extension UIView { 
    public func orientationHasChanged(_ isInPortrait:inout Bool) -> Bool { 
     if self.frame.width > self.frame.height { 
      if isInPortrait { 
       isInPortrait = false 
       return true 
      } 
     } else { 
      if !isInPortrait { 
       isInPortrait = true 
       return true 
      } 
     } 
     return false 
    } 
    public func setOrientation(_ p:[NSLayoutConstraint], _ l:[NSLayoutConstraint]) { 
     NSLayoutConstraint.deactivate(l) 
     NSLayoutConstraint.deactivate(p) 
     if self.bounds.width > self.bounds.height { 
      NSLayoutConstraint.activate(l) 
     } else { 
      NSLayoutConstraint.activate(p) 
     } 
    } 
} 

다른 방법은 직접 무언가를 선언하고 승수, 상수 또는 우선 순위 변경 주요 트릭은 isActive 플래그를 분리해야한다는 것을 기억하는 것입니다. 반대, 그냥 코드를 (. 그것은 잘못 엑스 코드에 입력 왜 안 함 나는 애플이 "행동"을 호출 겠지.)

var myButtonWidth = myButton.widthAnchor.constraint(equalToConstant: 100) 
myButtonWidth.isActive = true 

그리고 변경 :

func changeMyButton() { 
    myButtonWidth.constant = 200 
} 

이 도움이 되었기를 바랍니다.

+0

어디서 선언합니까? 'myButtonWidth' var? 함수 밖에서 선언 할 수 없으므로 선언 된 함수에서만 사용할 수 있다면 어떻게 바꿀 수 있습니까? (예 : viewDidLoad()) –

+0

함수보다 "넓은"범위. 제약 조건은 그 수준에 존재하는 뷰에 대해서도 경향이 있기 때문에 클래스 수준에서이를 호출하십시오. 나의 예제에서,'myButton'은 (필요한 경우)'UIViewController' 클래스의 어떤 함수에 사용 가능한 뷰인가? 따라서 제약 조건을 정확히 같은 방식으로 처리하십시오. 나는 실제로 함수 내외로 어떤 매개 변수처럼 그들을 통과하여 Framework 대상에서 제약 조건을 사용했습니다. – dfd

관련 문제