带有动态元素的iOS自定义控件

时间:2017-03-26 15:03:25

标签: ios swift custom-controls avaudioplayer

我已经开始构建我想要与世界分享的第一个开源项目。它是一个简单的音频播放器视图,可与AudioProvidable协议配合使用,然后在收到后播放音频数据。

现在我有一个IBDesignable类继承自UIView,它通过为其子视图定义约束来构建自己:

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
        }

结果就是音频接收时的结果:

enter image description here

收到音频后:

enter image description here

如果只有一个音频播放底部,则曲目之间的切换是多余的。我必须在哪里设置音频轨道的检查代码才能重新设计我的UI?我不想在prepareView()音频源阵列中拨打didSet {},因为我不想要将现有元素添加两次。 问候。

1 个答案:

答案 0 :(得分:1)

你可以添加一个bool标志来查看代码是否第一次运行,或者,我发现更容易,也许更合乎逻辑......

protected AbstractJackson2HttpMessageConverter(ObjectMapper objectMapper) {
    init(objectMapper);
}

protected AbstractJackson2HttpMessageConverter(ObjectMapper objectMapper, MediaType supportedMediaType) {
    super(supportedMediaType);
    init(objectMapper);
}

protected AbstractJackson2HttpMessageConverter(ObjectMapper objectMapper, MediaType... supportedMediaTypes) {
    super(supportedMediaTypes);
    init(objectMapper);
}