2017-03-26 3 views
0

세계에 공유하고 싶은 첫 번째 오픈 소스 프로젝트를 빌드하기 시작했습니다. AudioProvidable 프로토콜로 작동하고 수신 된 오디오 데이터를 재생하는 간단한 오디오 플레이어보기입니다. 우리는 오디오가 수신 될 때 무엇을 가지고 그 결과iOS 동적 요소가있는 사용자 지정 컨트롤

override init(frame: CGRect) { 
     super.init(frame: frame) 
#if !TARGET_INTERFACE 
     translatesAutoresizingMaskIntoConstraints = false 
#endif 
     prepareView() 
     updateUI() 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     prepareView() 
     updateUI() 
    } 

    func prepareView() { 
      //Necessary in order to set our own constraints 
      //btnPlay is already doing the same inside buttonWithImage(_:) 
      spinner.translatesAutoresizingMaskIntoConstraints = false 
      sliderAudioProgress.translatesAutoresizingMaskIntoConstraints = false 

      //Add necessary subviews to start setting up layout 
      addSubview(sliderAudioProgress) 
      addSubview(lblAudioDuration) 
      addSubview(lblAudioProgress) 
      addSubview(spinner) 
      addSubview(btnPlay) 
      addSubview(lblTrackNumber) 
      addSubview(btnNextTrack) 
      addSubview(btnPreviousTrack) 

      //Height of play & next/previous track buttons defines AudioPlayerView height 
      let viewHeight:CGFloat = 48 * 2 

      //Setup UI layout using constraints 
      NSLayoutConstraint.activate([ 

       heightAnchor.constraint(equalToConstant: viewHeight), 

       //Play button constraints 
       btnPlay.topAnchor.constraint(equalTo: topAnchor), 
       btnPlay.leadingAnchor.constraint(equalTo: leadingAnchor), 

       //Spinner constraints 
       spinner.centerYAnchor.constraint(equalTo: btnPlay.centerYAnchor), 
       spinner.centerXAnchor.constraint(equalTo: btnPlay.centerXAnchor), 

       //Progress label constraints 
       lblAudioProgress.leadingAnchor.constraint(equalTo: btnPlay.trailingAnchor), 
       lblAudioProgress.centerYAnchor.constraint(equalTo: btnPlay.centerYAnchor), 

       //Duration label constraints 
       lblAudioDuration.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -spacing), 
       lblAudioDuration.centerYAnchor.constraint(equalTo: btnPlay.centerYAnchor), 

       //Audio Progress Slider constraints 
       sliderAudioProgress.leadingAnchor.constraint(equalTo: lblAudioProgress.trailingAnchor, constant: spacing), 
       sliderAudioProgress.trailingAnchor.constraint(equalTo: lblAudioDuration.leadingAnchor, constant: -spacing), 
       sliderAudioProgress.centerYAnchor.constraint(equalTo: btnPlay.centerYAnchor), 

       lblTrackNumber.centerXAnchor.constraint(equalTo: centerXAnchor), 

       btnPreviousTrack.topAnchor.constraint(equalTo: btnPlay.bottomAnchor), 
       btnPreviousTrack.trailingAnchor.constraint(equalTo: lblTrackNumber.leadingAnchor, constant: -spacing), 

       btnNextTrack.topAnchor.constraint(equalTo: btnPlay.bottomAnchor), 
       btnNextTrack.leadingAnchor.constraint(equalTo: lblTrackNumber.trailingAnchor, constant: spacing), 

       lblTrackNumber.centerYAnchor.constraint(equalTo: btnNextTrack.centerYAnchor) 
      ]) 

      //Spinner setup: 
      spinner.hidesWhenStopped = true 

      //btnPlay setup: 
      btnPlay.addTarget(self, action: #selector(AudioPlayerView.playButtonPressed), for: .touchUpInside) 

      //Slider setup 
      sliderAudioProgress.thumbTintColor = UIColor(keyFromAppColorPalette: "secondary_color") 
      sliderAudioProgress.addTarget(self, action: #selector(AudioPlayerView.durationSliderValueChanged), for: .valueChanged) 
      sliderAudioProgress.addTarget(self, action: #selector(AudioPlayerView.durationSliderReleased), for: .touchUpInside) 
      sliderAudioProgress.isEnabled = false 
      sliderAudioProgress.isContinuous = true 
      sliderAudioProgress.semanticContentAttribute = .playback 

      //View's UI effects to make it look better 
      layer.cornerRadius = 6 
      layer.masksToBounds = true 
      layer.borderColor = UIColor.black.cgColor 
      layer.borderWidth = 2 
      semanticContentAttribute = .playback 

      spinner.startAnimating() 
      btnPlay.isHidden = true 
     } 

: 지금은

나는 IBDesignable 클래스가 같은 서브 뷰에 대한 제약 조건을 정의하여 자신을 구축하는 UIView의 상속이

enter image description here

오디오받은 후 :

enter image description here

하단 부분을 재생할 오디오가 하나 뿐인 경우 트랙 간 전환이 중복됩니다. 내 UI를 재 설계하려면 오디오 트랙 수를 확인하는 코드를 어디에 두어야합니까? 기존 요소를 두 번 추가하고 싶지 않기 때문에 오디오 소스 배열의 didSet {}prepareView()을 호출하고 싶지 않습니다. 감사합니다.

+1

내가 무엇에 명확하지 않다 ... 내가 쉽게 어쩌면 좀 더 논리적 무엇을 발견, 코드가 처음으로 실행되고 있는지 확인하기 위해 부울 플래그를 추가하거나 수 너는 묻고있다. (1) IBDesignable은 * 디자인 타임 * 도구이므로 해당 시간에 트랙의 수를 알 수 없습니다. 그 부분 (적어도 당신이 말한 것과 함께)은 반드시 * 실행 시간 * 코드의 일부가되어야합니다. (2) 이것을 가정하면 어떤 종류의 컨테이너보기 (간단한 UIView 일 수 있음)와 처리의 적절한 순간에 밑 부분보기를 배치합니다. "오디오 수신"이후의 일종의 종결 일 것입니다. 전체를 숨 깁니다. (3) 따라서이 컨테이너 컨트롤을 IB에서 약간 다른 모양으로 만들어 재생할 트랙이 하나라도 있으면 숨길 것임을 나타냅니다. – dfd

+0

@dfd, 답 및 명확한 설명에 감사드립니다. 나는 단지 (3) d 절을 완전히 이해하지 못했다. 이 동작을 어떻게 구현할 수 있도록 'UIView'는 _run-time_이 아닌 IB에서 다른 모양을 갖습니다. 감사. – GeRyCh

+0

좋은 질문 - 나는 그것을 통해 생각하지 않았다. :-) 내 정신적 인 그림은 IB에서 약간 더 가벼운 것처럼 보이지만 코드에서 바뀌 었습니다. 그러나 다른 검토 자에게 혼란 스러울 수 있습니다. 두 가지 다른 아이디어 : (1) 하나의 트랙 만있는 경우 맨 아래에 실제로 * 잘못된 * 표시가 없다는 것을 고려하여 * IB에서 * hideTrackCount *와 같은 속성을 노출하지 않으시겠습니까? (2) 바닥 모양을 약간 변경하는 대신 흐리게 처리하십시오. 다른 스타일과 동일한 스타일 (글꼴, 색상, 배경)을 사용합니다. [이 두 가지 아이디어 중 첫 번째 것이 더 마음에 듭니다.] – dfd

답변

1

당신은

func prepareView() { 

     //Necessary in order to set our own constraints 
     //btnPlay is already doing the same inside buttonWithImage(_:) 
     spinner.translatesAutoresizingMaskIntoConstraints = false 
     sliderAudioProgress.translatesAutoresizingMaskIntoConstraints = false 

     // if our subviews have not yet been added 
     if sliderAudioProgress.superview == nil { 

      //Add necessary subviews to start setting up layout 
      addSubview(sliderAudioProgress) 
      addSubview(lblAudioDuration) 
      ... etc 

     } 

     // continue here with any "every time" setup tasks 
    } 
+0

감사! 가능한 솔루션 중 하나로 받아 들여질 수 있는지 확인하십시오. – GeRyCh