UIbutton在UIScrollview中highlighted延迟

探讨了在UIScrollView上UIButton的高亮显示延迟问题及解决方案。通过调整UIScrollView的delaysContentTouches属性,并重写touchesShouldCancelInContentView:方法,使得UIButton能够立即响应点击并保持高亮,同时UIScrollView仍能正常滑动。

IOS开发之 ---- UIButton on the UIScrollView highlighted delay

 

最近做项目遇见一个问题:UIScrollView上有许多UIButton,要实现既能点击UIButton,又能滑动UIScrollView,这个实现没有问题,不需要做额外的touch管理,UIScrollView能识别是点击的UIButton还是滑动本身,但是有一个效果上的问题,就是点击UIButton时间短的话,不会高亮,但是确实是触发点击了,这样就造成了假象,给人一种UIButton没有被点击的感觉。如果点击时间长的话没有问题,会高亮。

这么看来,导致这样现象应该就是时间长短的问题,顺着这个问题想下去,就追寻到UIScrollView的touch原理,当UIScrollView接收到一个touch时,它会在一段时间(好像是150ms)内监听该touch是否移动了,假如移动了(应该有一个移动范围),则取消将touch发送到其子视图(例如UIButton),UIScrollView自身接受该touch,进行滑动。看来应该就是这段判断时间惹的祸了(这里其实我还想不明白为什么明明点击了Button,也确实触发了点击,却没有高亮状态,哪位大神知道的话请指教),那要解决问题是不是就应该把这段时间取消掉呢,不要这个判断时间,那么UIButton应该就会立即响应并产生高亮状态吧。正好UIScrollView中有一个属性叫delaysContentTouches,官方文档对它的解释是:If the value of this property is YES, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is NO , the scroll view immediately calls touchesShouldBegin:withEvent:inContentView:. The default value is YES.意思就是设置为NO就不会存在那个150ms的判断时间了,直接执行后续操作。那么咱们设置为NO来试试呗。结果确实如所想那样,UIButton立即响应并高亮。

但是…..别高兴太早,虽然这个问题解决了,但是新的麻烦又产生了,螳螂捕蝉黄雀在后!你会发现UIScrollView滑动不像以前那样了,假如touch down的那点落在UIButton上然后再滑动手指,UIScrollView不会滑动,但是UIButton仍然触发,当然,这样的结果也是应该的,你想想,设置delaysContentTouches为NO后,只要手指点在UIButton上,UIScrollView就会立即判定为这是点击UIButton,而不会再等待看手指是否移动来决定是否要滑动本身了。

那么如何解决这个问题呢?你会想,有没有什么方法可以在touch到UIbutton上并滑动时不触发UIButton而让UIScrollView自己滑动呢,强大的iOS没有让你失望,UIScrollView中有一个方法:touchesShouldCancelInContentView:,来看它的解释:The scroll view calls this method just after it starts sending tracking messages to the content view. If it receives NO from this method, it stops dragging and forwards the touch events to the content subview. The scroll view does not call this method if the value of the canCancelContentTouches property is NO.意思就是当UIScrollView将touch事件交给子view后,当手指发生滑动时,调用此方法,假如返回NO,则将touch事件交给子view,如果返回YES,则交给UIScrollView处理,产生滑动。(但是前提是UIScrollView的canCancelContentTouches属性是YES才会调用这个方法,只要不是UIControll的子类,这个属性默认是YES。)所以只要重写UIScrollView的这个方法并返回YES就可以啦,到此问题就解决了。既能立即响应UIButton,也能自由滑动UIScrollView。

import SnapKit final class TPMediaPlayerTooView : UIView, TPMediaViewRefreshDelegate { private(set) var clickAction : TPMediaPlayerClickAction?; private var viewBtns = [UIButton](); private var btnItems = [TPMediaPlayToolItem](); private let maxCnt : Int = 5; private lazy var contentView : UIScrollView = { let view = UIScrollView(); view.showsHorizontalScrollIndicator = false; view.showsVerticalScrollIndicator = false; view.backgroundColor = UIColor.clear; view.delegate = self; return view }() var isVertical : Bool = false { didSet { self.relaySubviews(views: self.viewBtns, isVertical: isVertical); } } var isInScreen: Bool = false { didSet { if (!isInScreen && !self.indicator.isHidden) { self.contentView.contentOffset = .zero; self.indicator.offset = 0; } } } var darkStyle : Bool = false; var enableIndicator : Bool = false; let indicatorWidth : CGFloat = 25; private(set) lazy var indicator : TPProgressIndicatorView = { let view = TPProgressIndicatorView(); view.clipsToBounds = true; view.backgroundColor = UIColor.tpbGrey//.tpbProgressBackground; view.isHidden = true; return view; }() init(items:[TPMediaPlayToolItem], downloadCenterViewModel: TPDownloadCenterViewModel? = nil, clickAction:@escaping TPMediaPlayerClickAction) { super.init(frame: CGRectZero); self.addSubview(self.contentView); self.contentView.snp.remakeConstraints { make in make.top.bottom.leading.trailing.equalToSuperview() }; self.clickAction = clickAction; self.downloadCenterViewModel = downloadCenterViewModel; self.downloadCenterViewModel?.reloadDownloadTaskNumberViewInToolViewAction = { [weak self](downloadTaskNumber: Int, failedTaskNumber: Int) in if let self = self { for (index, item) in items.enumerated() { if index >= 0 && index < self.viewBtns.count && item.type == .PlayBackDownload { reloadDownloadNumberSubScript(downloadTaskNumber: downloadTaskNumber, errorTaskNumber: failedTaskNumber); } } } } self.setItems(items: items); } var downloadCenterViewModel: TPDownloadCenterViewModel?; lazy var downloadingTaskNumberLabel: UILabel = { let downloadingTaskNumberLabel = UILabel(frame: .zero); downloadingTaskNumberLabel.textColor = UIColor.tpbTextWhite; downloadingTaskNumberLabel.font = .projectFont(ofSize: 12); downloadingTaskNumberLabel.textAlignment = .center; downloadingTaskNumberLabel.backgroundColor = .tpbRed; return downloadingTaskNumberLabel; }() lazy var downloadErrorImageView: UIImageView = { let imageView = UIImageView(frame: .zero) imageView.backgroundColor = .clear; imageView.image = UIImage(named: "playback_download_error"); return imageView; }() public func setItems(items:[TPMediaPlayToolItem]) { if self.btnItems.elementsEqual(items, by: { item1, item2 in return item1.type == item2.type }) { refresh(self.darkStyle); return } self.viewBtns.forEach({$0.removeFromSuperview()}); self.viewBtns.removeAll() self.btnItems.removeAll(); self.btnItems.append(contentsOf: items); for item in items { let btn = UIButton.init(type: .custom); btn.setImage(TPImageLiteral(item.normalImgUri), for: .normal); btn.imgUri = item.normalImgUri; btn.secondUri = item.secondUri; var img = TPImageLiteral(item.highImgUri) btn.setImage(img, for: .highlighted) img = TPImageLiteral(item.disableImgUri) btn.setImage(img, for: .disabled) btn.uriList = item.uriList; btn.tag = TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag + item.type.rawValue; btn.addTarget(self, action: #selector(clickViewAction), for: .touchUpInside); // 如果有图片变化的需要在变化的时候再次修改 btn.accessibilityLabel = item.accessibilityLabel self.contentView.addSubview(btn); self.viewBtns.append(btn); } relaySubviews(views: self.viewBtns, isVertical: isVertical) refresh(self.darkStyle); reloadDownloadNumberSubScript(downloadTaskNumber: self.downloadCenterViewModel?.downloadingTaskNumber ?? 0, errorTaskNumber: self.downloadCenterViewModel?.failedTaskNumber ?? 0) } func reloadDownloadNumberSubScript(downloadTaskNumber: Int, errorTaskNumber: Int){ relayoutDownloadingSubviews() if downloadTaskNumber > errorTaskNumber { // 存在正在下载的任务,优先显示正在下载的任务数 downloadingTaskNumberLabel.isHidden = false; downloadErrorImageView.isHidden = true; downloadingTaskNumberLabel.text = String(format: "%d", downloadTaskNumber - errorTaskNumber); } else if downloadTaskNumber == errorTaskNumber && errorTaskNumber > 0 { // 没有正在下载任务,但是有下载失败任务,显示error图标 downloadErrorImageView.isHidden = false; downloadingTaskNumberLabel.isHidden = true; } else { downloadingTaskNumberLabel.isHidden = true; downloadErrorImageView.isHidden = true; } } private func relayoutDownloadingSubviews() { guard let downBtn = self.viewWithType(type: .PlayBackDownload) else { return } let blk = { (view:UIView, clip:Bool) in if (view.superview != downBtn) { view.removeFromSuperview() downBtn.addSubview(view) let downloadingTaskNumberLabelHW = 16.0; view.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(30); make.top.equalToSuperview().offset(-6); make.width.height.equalTo(downloadingTaskNumberLabelHW); } if (clip) { view.layer.cornerRadius = downloadingTaskNumberLabelHW / 2.0; view.clipsToBounds = true; } } } blk(self.downloadErrorImageView, false); blk(self.downloadingTaskNumberLabel, true); } public func viewWithType(type:TPMediaPlayerFuncType) -> UIButton? { let tag = type.rawValue + TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag; return self.viewWithTag(tag) as? UIButton; } public func view(types:[TPMediaPlayerFuncType]) -> [UIButton]? { var items : [UIButton] = [UIButton](); for type in types { guard let btn = self.viewWithType(type: type) else { continue } items.append(btn); } return items; } public func setEnable(enable:Bool) { if enable { self.viewBtns.forEach({$0.isEnabled = true}) } else { self.viewBtns.forEach({$0.isEnabled = false}) } } public func setEnable(type:TPMediaPlayerFuncType, enable:Bool) { self.viewWithType(type: type)?.isEnabled = enable; } public func hitInBtn(point:CGPoint, parent:UIView) -> Bool { if (self.isHidden) { return false; } for btn in self.viewBtns { let btnFrame = btn.convert(btn.bounds, to: parent); if (btnFrame.contains(point)) { self.clickViewAction(btn); return true } } return false; } public func itemTypes() -> [TPMediaPlayerFuncType] { var types : [TPMediaPlayerFuncType] = []; self.btnItems.forEach({ types.append($0.type) }); return types; } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() relaySubviews(views: self.viewBtns, isVertical: isVertical) } override func didMoveToSuperview() { super.didMoveToSuperview() if !self.isInScreen, self.indicator.superview == nil, let superView = self.superview { superView.addSubview(self.indicator) self.indicator.snp.remakeConstraints { make in make.centerX.equalTo(self); make.size.equalTo(CGSize(width: indicatorWidth, height: 2)); make.top.equalTo(self.snp.bottom).offset(5); } self.indicator.layer.cornerRadius = 1; } } override func removeFromSuperview() { super.removeFromSuperview() self.indicator.removeFromSuperview() } //MARK: - TPMediaViewRefreshDelegate func refresh(_ darkStyle: Bool) { self.darkStyle = darkStyle; self.viewBtns.forEach({ $0.refresh(darkStyle)}) self.indicator.isHidden = self.isHidden || !enableIndicator || darkStyle || self.viewBtns.count <= maxCnt; if (!self.indicator.isHidden) { self.handleScroll(self.contentView); } } //MARK: - Private private func relaySubviews(views: [UIButton], isVertical: Bool) { guard views.count > 0 else { return } let squareSize: CGFloat = 70.0 // 小方块大小 let btnWH: CGFloat = 56.0 // 按钮大小 let itemMargin: CGFloat = 75 // 按钮间距(增大了) let lrMargin: CGFloat = 16.0 // 左右边距 let minVMargin: CGFloat = 8.0 // 垂直方向最小边距 var containerViewArray: [UIView] = [] // 存储带有背景的小方块容器 for i in 0..<views.count { let btn = views[i] // 创建小方块背景视图 let backgroundView = UIView() // 设置背景颜色:前五个为透明,其余为默认颜色 if i < 3 { backgroundView.backgroundColor = .clear // 透明 } else { backgroundView.backgroundColor = UIColor.tpbBackground // 默认颜色 } backgroundView.layer.cornerRadius = 8 // 将按钮从 contentView 中移除,并加入 backgroundView btn.removeFromSuperview() backgroundView.addSubview(btn) // 设置按钮在小方块中的位置和大小 btn.snp.remakeConstraints { make in make.center.equalTo(backgroundView) make.width.height.equalTo(btnWH) } // 将 backgroundView 添加到 contentView self.contentView.addSubview(backgroundView) containerViewArray.append(backgroundView) } // 创建一个中间容器视图,用于包裹所有按钮容器并实现整体居中 let buttonContainer = UIView() self.contentView.addSubview(buttonContainer) // 设置中间容器的约束 - 居中 buttonContainer.snp.makeConstraints { make in make.center.equalToSuperview() // 整体居中 } // 根据布局方向设置约束 if !isVertical { // 🎯 水平布局 - 居中对齐、间距大一些、宽度占满 for i in 0..<containerViewArray.count { let view = containerViewArray[i] // 将每个按钮添加到 buttonContainer 内部 buttonContainer.addSubview(view) if i == 0 { view.snp.makeConstraints { make in make.leading.equalTo(buttonContainer).offset(lrMargin) make.centerY.equalTo(buttonContainer) make.width.height.equalTo(squareSize) } } else { view.snp.makeConstraints { make in make.leading.equalTo(containerViewArray[i - 1].snp.trailing).offset(itemMargin) make.centerY.equalTo(buttonContainer) make.width.height.equalTo(squareSize) } } } // 确保最后一个按钮与右边有适当的边距 containerViewArray.last?.snp.makeConstraints { make in make.trailing.lessThanOrEqualTo(buttonContainer).offset(-lrMargin) } // 更新 contentSize let totalWidth = containerViewArray.reduce(0) { $0 + $1.frame.width } + (itemMargin * CGFloat(max(0, containerViewArray.count - 1))) self.contentView.contentSize = CGSize(width: totalWidth, height: self.contentView.frame.height) } else { // 垂直布局 for i in 0..<containerViewArray.count { let view = containerViewArray[i] // 将每个按钮添加到 buttonContainer 内部 buttonContainer.addSubview(view) if i == 0 { view.snp.makeConstraints { make in make.top.equalTo(buttonContainer).offset(minVMargin) make.centerX.equalTo(buttonContainer) make.width.height.equalTo(squareSize) } } else { view.snp.makeConstraints { make in make.top.equalTo(containerViewArray[i - 1].snp.bottom).offset(itemMargin) make.centerX.equalTo(buttonContainer) make.width.height.equalTo(squareSize) } } } // 更新 contentSize let totalHeight = containerViewArray.reduce(0) { $0 + $1.frame.height } + (itemMargin * CGFloat(max(0, containerViewArray.count - 1))) self.contentView.contentSize = CGSize(width: self.contentView.frame.width, height: totalHeight) } } @objc private func clickViewAction(_ sender:UIButton) { guard let type = TPMediaPlayerFuncType(rawValue: sender.tag - TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag) else { return } for item in self.btnItems { if (type == item.type) { guard let callback = item.clickAction else { self.clickAction?(type, false, nil); break } callback(type, false, nil); break; } } } } extension UIButton { @objc var textLable : UILabel { get { if let view = objc_getAssociatedObject(self, unsafeBitCast(#selector(setter: self.textLable), to: UnsafeRawPointer.self)) as? UILabel { return view; } let view = UILabel.init(); view.font = .projectFont(ofSize: 12) view.textColor = UIColor.tpbTextWhite; view.textAlignment = .center; view.backgroundColor = .clear; self.addSubview(view); view.snp.remakeConstraints { make in make.center.equalTo(self); }; self.textLable = view; return view; } set { objc_setAssociatedObject(self, unsafeBitCast(#selector(setter: textLable), to: UnsafeRawPointer.self), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } @objc var subTextLabel: UILabel { get { if let view = objc_getAssociatedObject(self, unsafeBitCast(#selector(setter: self.subTextLabel), to: UnsafeRawPointer.self)) as? UILabel { return view } let view = UILabel.init() view.font = .projectFont(ofSize: 12) view.textColor = .tpbRed view.textAlignment = .center view.backgroundColor = .clear self.addSubview(view) view.snp.remakeConstraints { make in make.centerX.equalTo(self) make.top.equalTo(self.snp.bottom) make.height.equalTo(15) }; self.subTextLabel = view return view; } set { objc_setAssociatedObject(self, unsafeBitCast(#selector(setter: subTextLabel), to: UnsafeRawPointer.self), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } } extension TPMediaPlayerTooView : UIScrollViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { handleScroll(scrollView) } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { handleScroll(scrollView, decelerate: decelerate) } func scrollViewDidScroll(_ scrollView: UIScrollView) { handleScroll(scrollView) } private func handleScroll(_ scrollView:UIScrollView, decelerate: Bool = false) { if (decelerate || self.indicator.isHidden) { return } let len = scrollView.contentSize.width - CGRectGetWidth(self.frame); let offset = scrollView.contentOffset.x; if (len >= 1) { self.indicator.offset = offset / len * (indicatorWidth - self.indicator.width); } } } final class TPProgressIndicatorView : UIView { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } var width : CGFloat = 11 { didSet { width != oldValue ? self.setNeedsDisplay() : nil; } } var color : UIColor = .tpbGreen { didSet { color != oldValue ? self.setNeedsDisplay() : nil } } var offset : CGFloat = 0 { didSet { if (offset != oldValue) { self.setNeedsDisplay() } } } init() { super.init(frame: .zero) } override func draw(_ rect: CGRect) { super.draw(rect) let pathH = CGRectGetHeight(rect); let path = UIBezierPath(rect: CGRect(x: offset, y: 0, width: width , height: pathH)) path.lineWidth = pathH; color.setStroke() path.stroke() } } 说一下图标按钮的相关逻辑
10-14
我现在想实现这样的:首先在所有的水平阶段(竖屏)保持现在的所有逻辑不变,然后在垂直(横屏)状态下,修改原来的布局逻辑,将除了按钮为item.type为case .LiveMultiPlay, .LiveQuality, .LivePlay, .LiveVolume, .LiveLandscape这五个按钮之外的需要用到的按钮排成双列显示(跟填充背景色的按钮一样,只有填充背景色按钮的才在横屏时排双列显示),请帮我修改整个代码,一次成功。 import SnapKit final class TPMediaPlayerTooView : UIView, TPMediaViewRefreshDelegate { private(set) var clickAction : TPMediaPlayerClickAction?; private var viewBtns = [UIButton](); private var btnItems = [TPMediaPlayToolItem](); private let maxCnt : Int = 5; private lazy var contentView : UIScrollView = { let view = UIScrollView(); view.showsHorizontalScrollIndicator = false; view.showsVerticalScrollIndicator = false; view.backgroundColor = UIColor.clear; view.delegate = self; return view }() var isVertical : Bool = false { didSet { self.relaySubviews(views: self.viewBtns, isVertical: isVertical); } } var isInScreen: Bool = false { didSet { if (!isInScreen && !self.indicator.isHidden) { self.contentView.contentOffset = .zero; self.indicator.offset = 0; } } } var darkStyle : Bool = false; var enableIndicator : Bool = false; let indicatorWidth : CGFloat = 25; private(set) lazy var indicator : TPProgressIndicatorView = { let view = TPProgressIndicatorView(); view.clipsToBounds = true; view.backgroundColor = UIColor.tpbGrey//.tpbProgressBackground; view.isHidden = true; return view; }() init(items:[TPMediaPlayToolItem], downloadCenterViewModel: TPDownloadCenterViewModel? = nil, clickAction:@escaping TPMediaPlayerClickAction) { super.init(frame: CGRectZero); self.addSubview(self.contentView); self.contentView.snp.remakeConstraints { make in make.top.bottom.leading.trailing.equalToSuperview() }; self.clickAction = clickAction; self.downloadCenterViewModel = downloadCenterViewModel; self.downloadCenterViewModel?.reloadDownloadTaskNumberViewInToolViewAction = { [weak self](downloadTaskNumber: Int, failedTaskNumber: Int) in if let self = self { for (index, item) in items.enumerated() { if index >= 0 && index < self.viewBtns.count && item.type == .PlayBackDownload { reloadDownloadNumberSubScript(downloadTaskNumber: downloadTaskNumber, errorTaskNumber: failedTaskNumber); } } } } self.setItems(items: items); } var downloadCenterViewModel: TPDownloadCenterViewModel?; lazy var downloadingTaskNumberLabel: UILabel = { let downloadingTaskNumberLabel = UILabel(frame: .zero); downloadingTaskNumberLabel.textColor = UIColor.tpbTextWhite; downloadingTaskNumberLabel.font = .projectFont(ofSize: 12); downloadingTaskNumberLabel.textAlignment = .center; downloadingTaskNumberLabel.backgroundColor = .tpbRed; return downloadingTaskNumberLabel; }() lazy var downloadErrorImageView: UIImageView = { let imageView = UIImageView(frame: .zero) imageView.backgroundColor = .clear; imageView.image = UIImage(named: "playback_download_error"); return imageView; }() public func setItems(items:[TPMediaPlayToolItem]) { if self.btnItems.elementsEqual(items, by: { item1, item2 in return item1.type == item2.type }) { refresh(self.darkStyle); return } self.viewBtns.forEach({$0.removeFromSuperview()}); self.viewBtns.removeAll() self.btnItems.removeAll(); self.btnItems.append(contentsOf: items); for item in items { let btn = UIButton.init(type: .custom); btn.setImage(TPImageLiteral(item.normalImgUri), for: .normal); btn.imgUri = item.normalImgUri; btn.secondUri = item.secondUri; var img = TPImageLiteral(item.highImgUri) btn.setImage(img, for: .highlighted) img = TPImageLiteral(item.disableImgUri) btn.setImage(img, for: .disabled) btn.uriList = item.uriList; btn.tag = TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag + item.type.rawValue; btn.addTarget(self, action: #selector(clickViewAction), for: .touchUpInside); // 如果有图片变化的需要在变化的时候再次修改 btn.accessibilityLabel = item.accessibilityLabel // 根据type判断是否添加背景圆角样式 switch item.type { case .LiveMultiPlay, .LiveQuality, .LivePlay, .LiveVolume, .LiveLandscape: // 屏幕上的五个按钮不添加 break default: // 其他类型添加背景圆角 btn.backgroundColor = UIColor.tpbBackgroundForPopup btn.layer.cornerRadius = 12 btn.clipsToBounds = true btn.imageEdgeInsets = UIEdgeInsets(top: 6, left: 0, bottom: 6, right: 0) } self.contentView.addSubview(btn); self.viewBtns.append(btn); } relaySubviews(views: self.viewBtns, isVertical: isVertical) refresh(self.darkStyle); reloadDownloadNumberSubScript(downloadTaskNumber: self.downloadCenterViewModel?.downloadingTaskNumber ?? 0, errorTaskNumber: self.downloadCenterViewModel?.failedTaskNumber ?? 0) } func reloadDownloadNumberSubScript(downloadTaskNumber: Int, errorTaskNumber: Int){ relayoutDownloadingSubviews() if downloadTaskNumber > errorTaskNumber { // 存在正在下载的任务,优先显示正在下载的任务数 downloadingTaskNumberLabel.isHidden = false; downloadErrorImageView.isHidden = true; downloadingTaskNumberLabel.text = String(format: "%d", downloadTaskNumber - errorTaskNumber); } else if downloadTaskNumber == errorTaskNumber && errorTaskNumber > 0 { // 没有正在下载任务,但是有下载失败任务,显示error图标 downloadErrorImageView.isHidden = false; downloadingTaskNumberLabel.isHidden = true; } else { downloadingTaskNumberLabel.isHidden = true; downloadErrorImageView.isHidden = true; } } private func relayoutDownloadingSubviews() { guard let downBtn = self.viewWithType(type: .PlayBackDownload) else { return } let blk = { (view:UIView, clip:Bool) in if (view.superview != downBtn) { view.removeFromSuperview() downBtn.addSubview(view) let downloadingTaskNumberLabelHW = 16.0; view.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(30); make.top.equalToSuperview().offset(-6); make.width.height.equalTo(downloadingTaskNumberLabelHW); } if (clip) { view.layer.cornerRadius = downloadingTaskNumberLabelHW / 2.0; view.clipsToBounds = true; } } } blk(self.downloadErrorImageView, false); blk(self.downloadingTaskNumberLabel, true); } public func viewWithType(type:TPMediaPlayerFuncType) -> UIButton? { let tag = type.rawValue + TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag; return self.viewWithTag(tag) as? UIButton; } public func view(types:[TPMediaPlayerFuncType]) -> [UIButton]? { var items : [UIButton] = [UIButton](); for type in types { guard let btn = self.viewWithType(type: type) else { continue } items.append(btn); } return items; } public func setEnable(enable:Bool) { if enable { self.viewBtns.forEach({$0.isEnabled = true}) } else { self.viewBtns.forEach({$0.isEnabled = false}) } } public func setEnable(type:TPMediaPlayerFuncType, enable:Bool) { self.viewWithType(type: type)?.isEnabled = enable; } public func hitInBtn(point:CGPoint, parent:UIView) -> Bool { if (self.isHidden) { return false; } for btn in self.viewBtns { let btnFrame = btn.convert(btn.bounds, to: parent); if (btnFrame.contains(point)) { self.clickViewAction(btn); return true } } return false; } public func itemTypes() -> [TPMediaPlayerFuncType] { var types : [TPMediaPlayerFuncType] = []; self.btnItems.forEach({ types.append($0.type) }); return types; } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() relaySubviews(views: self.viewBtns, isVertical: isVertical) } override func didMoveToSuperview() { super.didMoveToSuperview() if !self.isInScreen, self.indicator.superview == nil, let superView = self.superview { superView.addSubview(self.indicator) self.indicator.snp.remakeConstraints { make in make.centerX.equalTo(self); make.size.equalTo(CGSize(width: indicatorWidth, height: 2)); make.top.equalTo(self.snp.bottom).offset(5); } self.indicator.layer.cornerRadius = 1; } } override func removeFromSuperview() { super.removeFromSuperview() self.indicator.removeFromSuperview() } //MARK: - TPMediaViewRefreshDelegate func refresh(_ darkStyle: Bool) { self.darkStyle = darkStyle; self.viewBtns.forEach({ $0.refresh(darkStyle)}) self.indicator.isHidden = self.isHidden || !enableIndicator || darkStyle || self.viewBtns.count <= maxCnt; if (!self.indicator.isHidden) { self.handleScroll(self.contentView); } } //MARK: - Private private func relaySubviews(views:[UIButton], isVertical:Bool) { if (views.count <= 0) { return } var lastBtn : UIButton? = nil var lrMargin : CGFloat = 0 let btnWH : CGFloat = 130.0 let btnH : CGFloat = 60.0 var itemMargin : CGFloat = 15.0 var vContH : CGFloat = 0 var minVMargin : CGFloat = isVertical && views.count > 3 ? 10 : 24 // 竖屏状态下 if (!isVertical) { // 恢复竖屏下非Live类型按钮的默认背景色 for subView in contentView.subviews { if let btn = subView as? UIButton, !btn.isLiveButtonType() { btn.backgroundColor = UIColor.tpbBackgroundForPopup } } if isInScreen { let itemCnt = views.count// > 5 ? 5 : views.count lrMargin = views.count <= 2 ? (CGRectGetWidth(self.frame) - btnWH * CGFloat(itemCnt)) / CGFloat(itemCnt + 1) : lrMargin let totalMargin = CGRectGetWidth(self.frame) - 2.0 * lrMargin - btnWH * CGFloat(itemCnt) itemMargin = totalMargin / CGFloat(max(1, (itemCnt - 1))) } else { if (CGFloat((views.count - 1) * 24) + CGFloat(views.count) * btnWH) > CGRectGetWidth(UIScreen.main.bounds) || views.count > 5 { let itemCnt : CGFloat = views.count > maxCnt ? (CGFloat(maxCnt) + 0.5) : CGFloat(views.count) lrMargin = views.count <= 2 ? (CGRectGetWidth(self.frame) - btnWH * CGFloat(itemCnt)) / CGFloat(itemCnt + 1) : lrMargin + 15 let totalMargin = CGRectGetWidth(self.frame) - 2.0 * lrMargin - btnWH * CGFloat(itemCnt) itemMargin = abs(totalMargin / CGFloat(max(1, itemCnt - (CGFloat(views.count) > itemCnt ? 0.5 : 1)))) } else { lrMargin = (CGRectGetWidth(self.frame) - (CGFloat((views.count - 1) * 24) + CGFloat(views.count) * btnWH)) / 2 } } } else { // 横屏特殊处理 for subView in contentView.subviews { if let btn = subView as? UIButton, !btn.isLiveButtonType() { btn.backgroundColor = UIColor.tpbCardDark } } minVMargin = isVertical && views.count > 3 ? 0 : 24; let itemCnt = CGFloat(views.count); let vMargin : CGFloat = 32; let contH = max(0, itemCnt - 1) * itemMargin + (btnH + vMargin) * itemCnt; if contH > CGRectGetHeight(self.frame) { let totalMargin = CGRectGetHeight(self.frame) - 2.0 * lrMargin - btnH * CGFloat(itemCnt) itemMargin = totalMargin / CGFloat(max(1, (itemCnt - 1))) vContH = max(0, itemCnt - 1) * itemMargin + btnH * itemCnt lrMargin = max(minVMargin, (CGRectGetHeight(self.frame) - vContH) / 2) } else { itemMargin = itemMargin + vMargin vContH = max(0, itemCnt - 1) * itemMargin + (btnH + vMargin) * itemCnt; lrMargin = max(minVMargin, (CGRectGetHeight(self.frame) - vContH) / 2) } } for i in 0..<views.count { let btn = views[i]; guard let lastView = lastBtn else { btn.snp.remakeConstraints { make in if (isVertical) { make.top.equalToSuperview().offset(lrMargin / 2); make.centerX.equalToSuperview(); } else { make.leading.equalToSuperview().offset(lrMargin); make.centerY.equalToSuperview(); } make.width.equalTo(btnWH); make.height.lessThanOrEqualTo(btnWH); make.height.greaterThanOrEqualTo(btnH) }; lastBtn = btn; continue } btn.snp.remakeConstraints { make in make.width.height.equalTo(lastView); if (isVertical) { make.centerX.equalTo(lastView); make.top.equalTo(lastView.snp_bottomMargin).offset(itemMargin); if (i == views.count - 1) { make.bottom.equalToSuperview().offset(0 - itemMargin); } } else { make.centerY.equalTo(lastView); make.leading.equalTo(lastView.snp.trailing).offset(itemMargin); if (i == views.count - 1) { if (isVertical) { make.bottom.equalToSuperview(); } else { make.trailing.equalToSuperview().offset(0 - lrMargin); } } } } lastBtn = btn; } let itemCnt : CGFloat = CGFloat(self.viewBtns.count); if (isVertical) { self.contentView.contentSize = CGSizeMake(CGRectGetWidth(self.frame), max(CGRectGetHeight(self.frame) - 2 * minVMargin, vContH)) } else { let gap = enableIndicator && self.viewBtns.count > self.maxCnt ? 5.0 : 0.0; self.contentView.contentSize = CGSize(width: max(CGRectGetWidth(self.frame), lrMargin * 2 + max(0, itemCnt - 1) * itemMargin + itemCnt * btnWH) + gap, height: CGRectGetHeight(self.frame)); } } @objc private func clickViewAction(_ sender:UIButton) { guard let type = TPMediaPlayerFuncType(rawValue: sender.tag - TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag) else { return } for item in self.btnItems { if (type == item.type) { guard let callback = item.clickAction else { self.clickAction?(type, false, nil); break } callback(type, false, nil); break; } } } } extension UIButton { func isLiveButtonType() -> Bool { let tag = self.tag - TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag guard let type = TPMediaPlayerFuncType(rawValue: tag) else { return false } switch type { case .LiveMultiPlay, .LiveQuality, .LivePlay, .LiveVolume, .LiveLandscape: return true default: return false } } @objc var textLable : UILabel { get { if let view = objc_getAssociatedObject(self, unsafeBitCast(#selector(setter: self.textLable), to: UnsafeRawPointer.self)) as? UILabel { return view } let view = UILabel.init() view.font = .projectFont(ofSize: 12) view.textColor = UIColor.tpbTextWhite view.textAlignment = .center view.backgroundColor = .clear self.addSubview(view) view.snp.remakeConstraints { make in make.center.equalTo(self) } self.textLable = view return view } set { objc_setAssociatedObject(self, unsafeBitCast(#selector(setter: textLable), to: UnsafeRawPointer.self), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } @objc var subTextLabel: UILabel { get { if let view = objc_getAssociatedObject(self, unsafeBitCast(#selector(setter: self.subTextLabel), to: UnsafeRawPointer.self)) as? UILabel { return view } let view = UILabel.init() view.font = .projectFont(ofSize: 12) view.textColor = .tpbRed view.textAlignment = .center view.backgroundColor = .clear self.addSubview(view) view.snp.remakeConstraints { make in make.centerX.equalTo(self) make.top.equalTo(self.snp.bottom) make.height.equalTo(15) } self.subTextLabel = view return view } set { objc_setAssociatedObject(self, unsafeBitCast(#selector(setter: subTextLabel), to: UnsafeRawPointer.self), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } extension TPMediaPlayerTooView : UIScrollViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { handleScroll(scrollView) } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { handleScroll(scrollView, decelerate: decelerate) } func scrollViewDidScroll(_ scrollView: UIScrollView) { handleScroll(scrollView) } private func handleScroll(_ scrollView:UIScrollView, decelerate: Bool = false) { if (decelerate || self.indicator.isHidden) { return } let len = scrollView.contentSize.width - CGRectGetWidth(self.frame); let offset = scrollView.contentOffset.x; if (len >= 1) { self.indicator.offset = offset / len * (indicatorWidth - self.indicator.width); } } } final class TPProgressIndicatorView : UIView { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } var width : CGFloat = 11 { didSet { width != oldValue ? self.setNeedsDisplay() : nil; } } var color : UIColor = .tpbGreen { didSet { color != oldValue ? self.setNeedsDisplay() : nil } } var offset : CGFloat = 0 { didSet { if (offset != oldValue) { self.setNeedsDisplay() } } } init() { super.init(frame: .zero) } override func draw(_ rect: CGRect) { super.draw(rect) let pathH = CGRectGetHeight(rect); let path = UIBezierPath(rect: CGRect(x: offset, y: 0, width: width , height: pathH)) path.lineWidth = pathH; color.setStroke() path.stroke() } }
最新发布
10-16
import SnapKit final class TPMediaPlayerTooView : UIView, TPMediaViewRefreshDelegate { private(set) var clickAction : TPMediaPlayerClickAction?; private var viewBtns = [UIButton](); private var btnItems = [TPMediaPlayToolItem](); private let maxCnt : Int = 5; private lazy var contentView : UIScrollView = { let view = UIScrollView(); view.showsHorizontalScrollIndicator = false; view.showsVerticalScrollIndicator = false; view.backgroundColor = UIColor.clear; view.delegate = self; return view }() var isVertical : Bool = false { didSet { self.relaySubviews(views: self.viewBtns, isVertical: isVertical); } } var isInScreen: Bool = false { didSet { if (!isInScreen && !self.indicator.isHidden) { self.contentView.contentOffset = .zero; self.indicator.offset = 0; } } } var darkStyle : Bool = false; var enableIndicator : Bool = false; let indicatorWidth : CGFloat = 25; private(set) lazy var indicator : TPProgressIndicatorView = { let view = TPProgressIndicatorView(); view.clipsToBounds = true; view.backgroundColor = UIColor.tpbGrey//.tpbProgressBackground; view.isHidden = true; return view; }() init(items:[TPMediaPlayToolItem], downloadCenterViewModel: TPDownloadCenterViewModel? = nil, clickAction:@escaping TPMediaPlayerClickAction) { super.init(frame: CGRectZero); self.addSubview(self.contentView); self.contentView.snp.remakeConstraints { make in make.top.bottom.leading.trailing.equalToSuperview() }; self.clickAction = clickAction; self.downloadCenterViewModel = downloadCenterViewModel; self.downloadCenterViewModel?.reloadDownloadTaskNumberViewInToolViewAction = { [weak self](downloadTaskNumber: Int, failedTaskNumber: Int) in if let self = self { for (index, item) in items.enumerated() { if index >= 0 && index < self.viewBtns.count && item.type == .PlayBackDownload { reloadDownloadNumberSubScript(downloadTaskNumber: downloadTaskNumber, errorTaskNumber: failedTaskNumber); } } } } self.setItems(items: items); } var downloadCenterViewModel: TPDownloadCenterViewModel?; lazy var downloadingTaskNumberLabel: UILabel = { let downloadingTaskNumberLabel = UILabel(frame: .zero); downloadingTaskNumberLabel.textColor = UIColor.tpbTextWhite; downloadingTaskNumberLabel.font = .projectFont(ofSize: 12); downloadingTaskNumberLabel.textAlignment = .center; downloadingTaskNumberLabel.backgroundColor = .tpbRed; return downloadingTaskNumberLabel; }() lazy var downloadErrorImageView: UIImageView = { let imageView = UIImageView(frame: .zero) imageView.backgroundColor = .clear; imageView.image = UIImage(named: "playback_download_error"); return imageView; }() public func setItems(items:[TPMediaPlayToolItem]) { if self.btnItems.elementsEqual(items, by: { item1, item2 in return item1.type == item2.type }) { refresh(self.darkStyle); return } self.viewBtns.forEach({$0.removeFromSuperview()}); self.viewBtns.removeAll() self.btnItems.removeAll(); self.btnItems.append(contentsOf: items); for item in items { let btn = UIButton.init(type: .custom); btn.setImage(TPImageLiteral(item.normalImgUri), for: .normal); btn.imgUri = item.normalImgUri; btn.secondUri = item.secondUri; var img = TPImageLiteral(item.highImgUri) btn.setImage(img, for: .highlighted) img = TPImageLiteral(item.disableImgUri) btn.setImage(img, for: .disabled) btn.uriList = item.uriList; btn.tag = TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag + item.type.rawValue; btn.addTarget(self, action: #selector(clickViewAction), for: .touchUpInside); // 如果有图片变化的需要在变化的时候再次修改 btn.accessibilityLabel = item.accessibilityLabel // 根据type判断是否添加背景圆角样式 switch item.type { case .LiveMultiPlay, .LiveQuality, .LivePlay, .LiveVolume, .LiveLandscape: // 屏幕上的五个按钮不添加 break default: // 其他类型添加背景圆角 btn.backgroundColor = UIColor.tpbBackgroundForPopup btn.layer.cornerRadius = 12 btn.clipsToBounds = true btn.imageEdgeInsets = UIEdgeInsets(top: 6, left: 0, bottom: 6, right: 0) } self.contentView.addSubview(btn); self.viewBtns.append(btn); } relaySubviews(views: self.viewBtns, isVertical: isVertical) refresh(self.darkStyle); reloadDownloadNumberSubScript(downloadTaskNumber: self.downloadCenterViewModel?.downloadingTaskNumber ?? 0, errorTaskNumber: self.downloadCenterViewModel?.failedTaskNumber ?? 0) } func reloadDownloadNumberSubScript(downloadTaskNumber: Int, errorTaskNumber: Int){ relayoutDownloadingSubviews() if downloadTaskNumber > errorTaskNumber { // 存在正在下载的任务,优先显示正在下载的任务数 downloadingTaskNumberLabel.isHidden = false; downloadErrorImageView.isHidden = true; downloadingTaskNumberLabel.text = String(format: "%d", downloadTaskNumber - errorTaskNumber); } else if downloadTaskNumber == errorTaskNumber && errorTaskNumber > 0 { // 没有正在下载任务,但是有下载失败任务,显示error图标 downloadErrorImageView.isHidden = false; downloadingTaskNumberLabel.isHidden = true; } else { downloadingTaskNumberLabel.isHidden = true; downloadErrorImageView.isHidden = true; } } private func relayoutDownloadingSubviews() { guard let downBtn = self.viewWithType(type: .PlayBackDownload) else { return } let blk = { (view:UIView, clip:Bool) in if (view.superview != downBtn) { view.removeFromSuperview() downBtn.addSubview(view) let downloadingTaskNumberLabelHW = 16.0; view.snp.remakeConstraints { make in make.leading.equalToSuperview().offset(30); make.top.equalToSuperview().offset(-6); make.width.height.equalTo(downloadingTaskNumberLabelHW); } if (clip) { view.layer.cornerRadius = downloadingTaskNumberLabelHW / 2.0; view.clipsToBounds = true; } } } blk(self.downloadErrorImageView, false); blk(self.downloadingTaskNumberLabel, true); } public func viewWithType(type:TPMediaPlayerFuncType) -> UIButton? { let tag = type.rawValue + TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag; return self.viewWithTag(tag) as? UIButton; } public func view(types:[TPMediaPlayerFuncType]) -> [UIButton]? { var items : [UIButton] = [UIButton](); for type in types { guard let btn = self.viewWithType(type: type) else { continue } items.append(btn); } return items; } public func setEnable(enable:Bool) { if enable { self.viewBtns.forEach({$0.isEnabled = true}) } else { self.viewBtns.forEach({$0.isEnabled = false}) } } public func setEnable(type:TPMediaPlayerFuncType, enable:Bool) { self.viewWithType(type: type)?.isEnabled = enable; } public func hitInBtn(point:CGPoint, parent:UIView) -> Bool { if (self.isHidden) { return false; } for btn in self.viewBtns { let btnFrame = btn.convert(btn.bounds, to: parent); if (btnFrame.contains(point)) { self.clickViewAction(btn); return true } } return false; } public func itemTypes() -> [TPMediaPlayerFuncType] { var types : [TPMediaPlayerFuncType] = []; self.btnItems.forEach({ types.append($0.type) }); return types; } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() relaySubviews(views: self.viewBtns, isVertical: isVertical) } override func didMoveToSuperview() { super.didMoveToSuperview() if !self.isInScreen, self.indicator.superview == nil, let superView = self.superview { superView.addSubview(self.indicator) self.indicator.snp.remakeConstraints { make in make.centerX.equalTo(self); make.size.equalTo(CGSize(width: indicatorWidth, height: 2)); make.top.equalTo(self.snp.bottom).offset(5); } self.indicator.layer.cornerRadius = 1; } } override func removeFromSuperview() { super.removeFromSuperview() self.indicator.removeFromSuperview() } //MARK: - TPMediaViewRefreshDelegate func refresh(_ darkStyle: Bool) { self.darkStyle = darkStyle; self.viewBtns.forEach({ $0.refresh(darkStyle)}) self.indicator.isHidden = self.isHidden || !enableIndicator || darkStyle || self.viewBtns.count <= maxCnt; if (!self.indicator.isHidden) { self.handleScroll(self.contentView); } } //MARK: - Private private func relaySubviews(views:[UIButton], isVertical:Bool) { if (views.count <= 0) { return } var lastBtn : UIButton? = nil var lrMargin : CGFloat = 0 let btnWH : CGFloat = 130.0 let btnH : CGFloat = 60.0 var itemMargin : CGFloat = 15.0 var vContH : CGFloat = 0 var minVMargin : CGFloat = isVertical && views.count > 3 ? 10 : 24 // 竖屏状态下 if (!isVertical) { if isInScreen { let itemCnt = views.count// > 5 ? 5 : views.count lrMargin = views.count <= 2 ? (CGRectGetWidth(self.frame) - btnWH * CGFloat(itemCnt)) / CGFloat(itemCnt + 1) : lrMargin let totalMargin = CGRectGetWidth(self.frame) - 2.0 * lrMargin - btnWH * CGFloat(itemCnt) itemMargin = totalMargin / CGFloat(max(1, (itemCnt - 1))) } else { if (CGFloat((views.count - 1) * 24) + CGFloat(views.count) * btnWH) > CGRectGetWidth(UIScreen.main.bounds) || views.count > 5 { let itemCnt : CGFloat = views.count > maxCnt ? (CGFloat(maxCnt) + 0.5) : CGFloat(views.count) lrMargin = views.count <= 2 ? (CGRectGetWidth(self.frame) - btnWH * CGFloat(itemCnt)) / CGFloat(itemCnt + 1) : lrMargin + 15 let totalMargin = CGRectGetWidth(self.frame) - 2.0 * lrMargin - btnWH * CGFloat(itemCnt) itemMargin = abs(totalMargin / CGFloat(max(1, itemCnt - (CGFloat(views.count) > itemCnt ? 0.5 : 1)))) } else { lrMargin = (CGRectGetWidth(self.frame) - (CGFloat((views.count - 1) * 24) + CGFloat(views.count) * btnWH)) / 2 } } } else { //横屏特殊处理 for subView in contentView.subviews { if let btn = subView as? UIButton { if !btn.isLiveButtonType() { btn.backgroundColor = UIColor.tpbCardDark } } } minVMargin = isVertical && views.count > 3 ? 0 : 24; let itemCnt = CGFloat(views.count); let vMargin : CGFloat = 32; let contH = max(0, itemCnt - 1) * itemMargin + (btnH + vMargin) * itemCnt; if contH > CGRectGetHeight(self.frame) { let totalMargin = CGRectGetHeight(self.frame) - 2.0 * lrMargin - btnH * CGFloat(itemCnt) itemMargin = totalMargin / CGFloat(max(1, (itemCnt - 1))) vContH = max(0, itemCnt - 1) * itemMargin + btnH * itemCnt lrMargin = max(minVMargin, (CGRectGetHeight(self.frame) - vContH) / 2) } else { itemMargin = itemMargin + vMargin vContH = max(0, itemCnt - 1) * itemMargin + (btnH + vMargin) * itemCnt; lrMargin = max(minVMargin, (CGRectGetHeight(self.frame) - vContH) / 2) } } for i in 0..<views.count { let btn = views[i]; guard let lastView = lastBtn else { btn.snp.remakeConstraints { make in if (isVertical) { make.top.equalToSuperview().offset(lrMargin / 2); make.centerX.equalToSuperview(); } else { make.leading.equalToSuperview().offset(lrMargin); make.centerY.equalToSuperview(); } make.width.equalTo(btnWH); make.height.lessThanOrEqualTo(btnWH); make.height.greaterThanOrEqualTo(btnH) }; lastBtn = btn; continue } btn.snp.remakeConstraints { make in make.width.height.equalTo(lastView); if (isVertical) { make.centerX.equalTo(lastView); make.top.equalTo(lastView.snp_bottomMargin).offset(itemMargin); if (i == views.count - 1) { make.bottom.equalToSuperview().offset(0 - itemMargin); } } else { make.centerY.equalTo(lastView); make.leading.equalTo(lastView.snp.trailing).offset(itemMargin); if (i == views.count - 1) { if (isVertical) { make.bottom.equalToSuperview(); } else { make.trailing.equalToSuperview().offset(0 - lrMargin); } } } } lastBtn = btn; } let itemCnt : CGFloat = CGFloat(self.viewBtns.count); if (isVertical) { self.contentView.contentSize = CGSizeMake(CGRectGetWidth(self.frame), max(CGRectGetHeight(self.frame) - 2 * minVMargin, vContH)) } else { let gap = enableIndicator && self.viewBtns.count > self.maxCnt ? 5.0 : 0.0; self.contentView.contentSize = CGSize(width: max(CGRectGetWidth(self.frame), lrMargin * 2 + max(0, itemCnt - 1) * itemMargin + itemCnt * btnWH) + gap, height: CGRectGetHeight(self.frame)); } } @objc private func clickViewAction(_ sender:UIButton) { guard let type = TPMediaPlayerFuncType(rawValue: sender.tag - TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag) else { return } for item in self.btnItems { if (type == item.type) { guard let callback = item.clickAction else { self.clickAction?(type, false, nil); break } callback(type, false, nil); break; } } } } extension UIButton { func isLiveButtonType() -> Bool { let tag = self.tag - TPMediaPreviewUtils.kMediaPlayerSubviewBaseTag guard let type = TPMediaPlayerFuncType(rawValue: tag) else { return false } switch type { case .LiveMultiPlay, .LiveQuality, .LivePlay, .LiveVolume, .LiveLandscape: return true default: return false } } @objc var textLable : UILabel { get { if let view = objc_getAssociatedObject(self, unsafeBitCast(#selector(setter: self.textLable), to: UnsafeRawPointer.self)) as? UILabel { return view } let view = UILabel.init() view.font = .projectFont(ofSize: 12) view.textColor = UIColor.tpbTextWhite view.textAlignment = .center view.backgroundColor = .clear self.addSubview(view) view.snp.remakeConstraints { make in make.center.equalTo(self) } self.textLable = view return view } set { objc_setAssociatedObject(self, unsafeBitCast(#selector(setter: textLable), to: UnsafeRawPointer.self), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } @objc var subTextLabel: UILabel { get { if let view = objc_getAssociatedObject(self, unsafeBitCast(#selector(setter: self.subTextLabel), to: UnsafeRawPointer.self)) as? UILabel { return view } let view = UILabel.init() view.font = .projectFont(ofSize: 12) view.textColor = .tpbRed view.textAlignment = .center view.backgroundColor = .clear self.addSubview(view) view.snp.remakeConstraints { make in make.centerX.equalTo(self) make.top.equalTo(self.snp.bottom) make.height.equalTo(15) } self.subTextLabel = view return view } set { objc_setAssociatedObject(self, unsafeBitCast(#selector(setter: subTextLabel), to: UnsafeRawPointer.self), newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } extension TPMediaPlayerTooView : UIScrollViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { handleScroll(scrollView) } func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { handleScroll(scrollView, decelerate: decelerate) } func scrollViewDidScroll(_ scrollView: UIScrollView) { handleScroll(scrollView) } private func handleScroll(_ scrollView:UIScrollView, decelerate: Bool = false) { if (decelerate || self.indicator.isHidden) { return } let len = scrollView.contentSize.width - CGRectGetWidth(self.frame); let offset = scrollView.contentOffset.x; if (len >= 1) { self.indicator.offset = offset / len * (indicatorWidth - self.indicator.width); } } } final class TPProgressIndicatorView : UIView { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } var width : CGFloat = 11 { didSet { width != oldValue ? self.setNeedsDisplay() : nil; } } var color : UIColor = .tpbGreen { didSet { color != oldValue ? self.setNeedsDisplay() : nil } } var offset : CGFloat = 0 { didSet { if (offset != oldValue) { self.setNeedsDisplay() } } } init() { super.init(frame: .zero) } override func draw(_ rect: CGRect) { super.draw(rect) let pathH = CGRectGetHeight(rect); let path = UIBezierPath(rect: CGRect(x: offset, y: 0, width: width , height: pathH)) path.lineWidth = pathH; color.setStroke() path.stroke() } } 现在的代码中,切换一次横屏是对的背景颜色,但再切换回竖屏的时候,还是横屏状态下的背景颜色,没有变成竖屏该有的
10-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值