scrollViewDidEndDecelerating

本文探讨了UIScrollView中的两个重要代理方法:scrollViewDidEndDragging 和 scrollViewDidEndDecelerating 的区别及应用场景。前者在拖拽结束时触发,后者则在减速停止时执行。了解这两个方法的不同有助于开发者更精确地控制滚动视图的行为。
- (void) scrollViewDidScroll:(UIScrollView *)sender 

上面这句在滑动scrollview的时候会执行多次 在调用这个方法进行处理的时候 发现容易卡死  所以在这里面执行其他方法的时候要慎重

这个方法不行的话 找到了其他的一个函数

- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender 


手写好麻烦 帖别人的话  mark
看名字就不一样 第一个DidEndDragging 停止拖拽的时候开始执行

第二个:DidEndDecelerating 减速停止的时候开始执行


也就是说 它俩执行的时间不一样 scrollview 先是执行 停止拖住的代理 然后在执行减速停止的代理
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ [self at_searchViewShow:YES]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if(decelerate && self.selIndex < self.dataArray.count){ if(self.dataCount != self.dataArray.count){ self.dataCount = self.dataArray.count; [self.collectionView reloadData]; }else{ [UIView performWithoutAnimation:^{ [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:self.selIndex inSection:0]]];//初始化 }]; } } } -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ NSInteger page = ceil(scrollView.contentOffset.y /(self.collectionView.height>0?self.collectionView.height:kSCREEN_HEIGHT)); if(page < self.dataArray.count){ self.selIndex = page; if(self.selectListIndex){ self.selectListIndex(page); } ATGroupModel *model = self.dataArray[page]; if (!NSStringIsNullOrEmpty(self.at_searchKey)) { model.searchKeyWord = self.at_searchKey; } [[FNAppReviewConfig shareManager] addBrowseRecord:model.theID click_uuid:model.click_uuid];//浏览记录 } [self at_searchViewShow:NO]; ATLog(@"打印index页码%li",page); } -(void)at_searchViewShow:(BOOL)isStatue{ if(isStatue){ [[self class] cancelPreviousPerformRequestsWithTarget:self];//清除上一个 [self.searchView setHidden:YES]; [self.backBtn setHidden:YES]; [self.searchView setAlpha:0]; [self.backBtn setAlpha:0]; }else{ [self performSelector:@selector(dismissalert:) withObject:@"firstParameter" afterDelay:1.0]; } } - (void)dismissalert:(NSString*)alert { [self.searchView setHidden:NO]; [self.backBtn setHidden:NO]; [self.searchView setAlpha:0.3]; [self.backBtn setAlpha:0.3]; [UIView transitionWithView:self.searchView duration:1.0 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ } completion:^(BOOL finished) { [self.searchView setAlpha:1.0]; [self.backBtn setAlpha:1.0]; }]; }此代码,滑动时隐藏搜索框,停止滚动时显示搜索框,代码中,当前控制器销毁后是否会出现异常
07-27
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) { if (views.count <= 0) { return } var lastBtn : UIButton? = nil; var lrMargin : CGFloat = 0; let btnWH : CGFloat = 56.0; let btnH : CGFloat = 24.0; var itemMargin : CGFloat = 24.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 > 4 { 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 + 45 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 { //横屏特殊处理 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 { @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() } } 帮我修改整个代码,用方案2实现
最新发布
10-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值