
- 這是我的問題:這是一個音頻播放器,我洗掉了所有其他行以便您閱讀。問題出在 MPVolumeView 中。當用戶一直滑動到最大時,滑塊的按鈕將懸停在連接按鈕上。當用戶將滑塊的按鈕一直滑動到最小時,滑塊的按鈕不會移動到最后。
- 親愛的 DonMag,我真的很感謝你,它有效!如何!我正在添加螢屏截圖。相信你的回答會對很多自緊身褲有幫助。


import UIKit
import AVFoundation
import MediaPlayer
import AVKit
class AudioPlayerViewControllerQ1: UIViewController {
@IBOutlet var holder: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if holder.subviews.count == 0 {
}
let volumeView = MPVolumeView(frame: CGRect(x: 20,
y: holder.frame.size.height - 80,
width: holder.frame.size.width-40,
height: 30))
holder.addSubview(volumeView)
}
private func setupView() {
setupConstraints()
}
private func setupConstraints() {
NSLayoutConstraint.activate([
holder.leadingAnchor.constraint(equalTo: view.leadingAnchor),
holder.trailingAnchor.constraint(equalTo: view.trailingAnchor),
holder.topAnchor.constraint(equalTo: view.topAnchor),
holder.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIApplication.shared.isIdleTimerDisabled = true
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
UIApplication.shared.isIdleTimerDisabled = false
}
}
uj5u.com熱心網友回復:
經過快速的研究和實驗——它看起來MPVolumeView相當有問題:(
實體化時,如果當前設備音量大于0,則拇指將在 x 軸上偏移。音量越大,偏移量越大。
此外,它在使用自動布局約束時根本不能很好地發揮作用。
我們可以通過子類MPVolumeView化和“修復”滑塊矩形來解決這個問題:
class MyVolumeView: MPVolumeView {
override func volumeSliderRect(forBounds bounds: CGRect) -> CGRect {
// this will avoid the thumb x-offset issue
// while keeping the route button vertically aligned
return bounds.insetBy(dx: 12.0, dy: 0.0).offsetBy(dx: -12.0, dy: -5.0)
}
}
然后,為了糾正垂直布局的問題,我們需要在設定它的框架時偏移 Y 位置。
這是一個快速示例,說明了一種方法。我嵌入MyVolumeView了一個“容器”視圖,并在容器視圖的邊界發生變化時使用屬性觀察器來更新框架:
class AudioPlayerViewControllerQ1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// let's give the view a background color so we can easily see its frame
view.backgroundColor = .systemYellow
// assuming "holder" view has buttons and other controls
// along with the MyVolumeView near the bottom
let holder = UIView()
holder.backgroundColor = .darkGray
holder.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(holder)
// create a separate "container" view for the MyVolumeView
let volumeViewContainer = UIView()
// we'll make it red for now so we can see it
volumeViewContainer.backgroundColor = .red
volumeViewContainer.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(volumeViewContainer)
// respect safe-area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// let's make the holder 20-points inset on leading/trailing
holder.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
holder.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
// holder height (for this example) is 240.0
holder.heightAnchor.constraint(equalToConstant: 240.0),
// let's put its bottom 60-points from the bottom (of the safe area)
holder.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -160.0),
// volume view container leading/trailing equal to holder
volumeViewContainer.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 0.0),
volumeViewContainer.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: 0.0),
// volume view container bottom equal to holder bottom
volumeViewContainer.bottomAnchor.constraint(equalTo: holder.bottomAnchor, constant: 0.0),
// volume view container height equal to 30-points
volumeViewContainer.heightAnchor.constraint(equalToConstant: 30.0),
])
// now we'll add a MPVolumeView to the container
let v = MyVolumeView()
volumeViewContainer.addSubview(v)
// we'll use a property observer to update the MyVolumeView frame
// whenever the container bounds changes
volumeViewContainer.addObserver(self, forKeyPath: "bounds", context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "bounds" {
// make sure we're getting notified of the MyVolumeView container view
if let cv = object as? UIView,
let mpv = cv.subviews.first as? MyVolumeView {
// set MyVolumeView frame to container view's bounds
// and offset its y-position by 4-points (because of its buggy layout)
mpv.frame = cv.bounds.offsetBy(dx: 0.0, dy: 4.0)
}
}
}
}
運行時是這樣的:

我們可以將拇指一直拖到左邊:

and to the right (without overlapping the route button):

Edit
Here are a couple simplified examples...
Using CGRect frames instead of constraints (as requested by the OP):
class AudioPlayerViewControllerQ1: UIViewController {
let holder = UIView()
let myVolumeView = MyVolumeView()
override func viewDidLoad() {
super.viewDidLoad()
// let's give the view a background color so we can easily see its frame
view.backgroundColor = .systemYellow
// assuming "holder" view has buttons and other controls
// along with the MPVolumeView near the bottom
holder.backgroundColor = .darkGray
view.addSubview(holder)
// now we'll add a MPVolumeView to the container
holder.addSubview(myVolumeView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// let's make sure this only executes if the holder view frame has not been set yet
if holder.frame.width != 320.0 {
// set holder view frame to 320 x 240
holder.frame = CGRect(x: 0, y: 0, width: 320.0, height: 240.0)
// center it in the view
holder.center = view.center
// set myVolumeView frame to same width as holder view
// 30-points height, at bottom of holder view
myVolumeView.frame = CGRect(x: 0.0, y: holder.frame.height - 30.0, width: holder.frame.width, height: 30.0)
}
}
}
and, this one using constraints:
class AudioPlayerViewControllerQ1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// let's give the view a background color so we can easily see its frame
view.backgroundColor = .systemYellow
// assuming "holder" view has buttons and other controls
// along with the MPVolumeView near the bottom
let holder = UIView()
holder.backgroundColor = .darkGray
holder.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(holder)
// now we'll add a MPVolumeView to the container
let myVolumeView = MyVolumeView()
myVolumeView.translatesAutoresizingMaskIntoConstraints = false
holder.addSubview(myVolumeView)
// respect safe-area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// set holder view frame to 320 x 240
holder.widthAnchor.constraint(equalToConstant: 320.0),
holder.heightAnchor.constraint(equalToConstant: 240.0),
// center it
holder.centerXAnchor.constraint(equalTo: g.centerXAnchor),
holder.centerYAnchor.constraint(equalTo: g.centerYAnchor),
// constrain myVolumeView leading/trailing/bottom equal to holder view
myVolumeView.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 0.0),
myVolumeView.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: 0.0),
myVolumeView.bottomAnchor.constraint(equalTo: holder.bottomAnchor, constant: 0.0),
// myVolumeView height
myVolumeView.heightAnchor.constraint(equalToConstant: 30.0),
])
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/512394.html
