| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- //
- // QSLHomeFriendView.swift
- // QuickSearchLocation
- //
- // Created by mac on 2024/4/12.
- //
- import UIKit
- import YYText
- import SnapKit
- enum FriendViewLocation {
- case ScrollTop
- case ScrollCenter
- case ScrollBottom
- }
- protocol QSLHomeFriendViewDelegate: NSObjectProtocol {
-
- func refreshBtnAction()
-
- func homeFriPhoneViewClick()
-
- func routeBtnAction(model: QSLUserModel)
-
- func locateBtnAction(model: QSLUserModel)
-
- func addFriendAction(isSmall: Bool)
-
- func viewDidScroll()
- }
- class QSLHomeFriendView: UIView {
-
- weak var delegate: QSLHomeFriendViewDelegate?
- // 动态约束处理
- var couponViewTopConstraint: Constraint? = nil
- private var friBgViewTopConstraint: Constraint? // 新增:保存friBgView的顶部约束
-
- var viewModel:QSLHomeViewModel? {
- didSet {
- friTableView.reloadData()
- }
- }
-
- /// 位置
- var scrollLocation: FriendViewLocation?
- /// 滑动到最后停下来的位置
- var scrollStopY: CGFloat?
- /// 滑动顶部距离顶部的距离
- var scrollTopHeight: CGFloat?
- /// 滑动中间距离顶部的距离
- var scrollCenterHeight: CGFloat?
- /// 滑动底部距离顶部的距离
- var scrollBottomHeight: CGFloat?
-
- lazy var friMapLogoImageView: UIImageView = {
-
- let imageView = UIImageView()
- imageView.isHidden = true
- imageView.image = UIImage(named: "home_friends_map_logo")
- return imageView
- }()
-
- lazy var friExpandButton: UIButton = {
-
- let button = UIButton(type: .custom)
- button.backgroundColor = UIColor.hexStringColor(hexString: "#333333", alpha: 0.6)
- button.addRadius(radius: 2)
- return button
- }()
-
- lazy var refreshButton: UIButton = {
-
- let button = UIButton(type: .custom)
- button.setBackgroundImage(UIImage(named: "home_refresh_btn"), for: .normal)
- button.addTarget(self, action: #selector(refreshBtnAction), for: .touchUpInside)
- return button
- }()
- lazy var couponView: UIImageView = {
- let view = UIImageView()
- view.image = UIImage(named: "home_activity_bg")
- view.isUserInteractionEnabled = true
- view.isHidden = true
- let tapG = UITapGestureRecognizer.init(target: self, action: #selector(unlockBtnAction))
- view.addGestureRecognizer(tapG)
- return view
- }()
-
- lazy var couponLabel: YYLabel = {
- let label = YYLabel()
- return label
- }()
-
- lazy var countdownLabel: QSLCountdownView = {
- let label = QSLCountdownView(frame: CGRectMake(0, 0, QSLConst.qsl_kScreenW - 24.rpx, 17.rpx),type: 1)
- return label
- }()
-
- lazy var couponBtn: UILabel = {
- let label = UILabel()
- label.gradientBackgroundColor(color1: UIColor.hexStringColor(hexString: "#FFFEF3", alpha: 1), color2: UIColor.hexStringColor(hexString: "#FFE6C0", alpha: 1), width: 65.rpx, height: 28.rpx, direction: .horizontal)
- label.text("去使用")
- label.textAlignment = .center
- label.font = UIFont.textM(14)
- label.textColor = (UIColor.hexStringColor(hexString: "#3A331C"))
- label.addRadius(radius: 14.rpx)
- return label
- }()
-
- lazy var friBgView: UIView = {
-
- let view = UIView()
-
- view.clipsToBounds = true
- view.backgroundColor = QSLColor.backGroundColor
- view.addRadius(radius: 12.rpx)
-
- return view
- }()
-
- lazy var friHeaderView: UIView = {
-
- let view = UIView(frame: CGRect(x: 0, y: 0, width: QSLConst.qsl_kScreenW, height: 61.rpx))
- if let image = UIImage.gradient([UIColor.hexStringColor(hexString: "#FFFFFF", alpha: 1), UIColor.hexStringColor(hexString: "#FFFFFF", alpha: 0)], size: CGSize(width: qsl_kScreenW, height: 61.rpx), locations: [0, 1], direction: .vertical) {
- view.backgroundColor = UIColor(patternImage: image)
- }
- view.addFourCorner(topLeft: 12.rpx, topRight: 12.rpx, bottomLeft: 0, bottomRight: 0)
- return view
- }()
-
- lazy var friHeaderTitleIcon: UIImageView = {
-
- let imageView = UIImageView()
- imageView.image = UIImage(named: "home_friends_header_title")
- return imageView
- }()
-
- lazy var friHeaderAddBtn: UIButton = {
-
- let btn = UIButton()
- btn.setBackgroundImage(UIImage(named: "home_friends_header_add_btn_bg"), for: .normal)
- btn.image(UIImage(named: "home_friends_header_add_icon"))
- btn.title("查找好友")
- btn.mediumFont(15)
- btn.textColor(.white)
- btn.setImageTitleLayout(.imgLeft, spacing: 0)
- btn.addTarget(self, action: #selector(topAddButtonAction), for: .touchUpInside)
- return btn
- }()
-
- lazy var friTableView: UITableView = {
-
- let tableView = UITableView(frame: .zero, style: .grouped)
- tableView.backgroundColor = .clear
- tableView.separatorStyle = .none
- tableView.showsVerticalScrollIndicator = false
- tableView.delegate = self
- tableView.dataSource = self
- tableView.tableViewNeverAdjustContentInset()
- tableView.bounces = false
- tableView.isUserInteractionEnabled = true
- tableView.isScrollEnabled = false
- tableView.contentInsetAdjustmentBehavior = .never
- tableView.register(cellClass: QSLHomeFriendTableViewCell.self)
-
- return tableView
- }()
-
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- self.scrollCenterHeight = self.qsl_top
- self.scrollBottomHeight = qsl_kScreenH - qsl_kTabbarFrameH - 56 - 40
- self.setupUI()
- self.addPanAction()
-
- NotificationCenter.default.addObserver(
- self,
- selector: #selector(handleCouponNotification(_:)),
- name: Notification.Name("QSLHomeUpdateCouponViewNoti"),
- object: nil
- )
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- @objc func refreshBtnAction() {
-
- delegate?.refreshBtnAction()
- }
- }
- // MARK: - 设置UI
- extension QSLHomeFriendView {
-
- func setupUI() {
- addSubview(couponView)
- couponView.addSubview(couponBtn)
- couponView.addSubview(couponLabel)
- couponView.addSubview(countdownLabel)
-
- addSubview(friBgView)
- addSubview(friTableView)
-
- addSubview(friMapLogoImageView)
- addSubview(friExpandButton)
- addSubview(refreshButton)
-
- friBgView.addSubview(friHeaderView)
- friHeaderView.addSubview(friHeaderTitleIcon)
- friHeaderView.addSubview(friHeaderAddBtn)
-
- friMapLogoImageView.snp.makeConstraints { make in
- make.size.equalTo(CGSize(width: 62, height: 20))
- make.top.equalTo(0)
- make.left.equalTo(12)
- }
-
- friExpandButton.snp.makeConstraints { make in
- make.size.equalTo(CGSize(width: 80, height: 4))
- make.top.equalTo(friMapLogoImageView.snp.bottom).offset(8)
- make.centerX.equalTo(snp.centerX)
- }
- // couponView 的约束(初始时设为隐藏)
- couponView.snp.makeConstraints { make in
- make.left.equalTo(8.rpx)
- make.right.equalTo(-8.rpx)
- make.height.equalTo(58.rpx)
- couponViewTopConstraint = make.top.equalTo(friExpandButton.snp.bottom).offset(8.rpx).constraint
- }
-
- couponBtn.snp.makeConstraints { make in
- make.height.equalTo(28.rpx)
- make.width.equalTo(65.rpx)
- make.right.equalTo(-12.rpx)
- make.centerY.equalToSuperview()
- }
-
- couponLabel.snp.makeConstraints { make in
- make.height.equalTo(22.rpx)
- make.top.equalTo(10.rpx)
- make.left.equalTo(60.rpx)
- make.right.equalTo(couponBtn.snp.left).offset(-10.rpx)
- }
-
- countdownLabel.snp.makeConstraints { make in
- make.height.equalTo(17.rpx)
- make.top.equalTo(couponLabel.snp.bottom).offset(0)
- make.left.equalTo(60.rpx)
- make.right.equalTo(couponBtn.snp.left).offset(-10.rpx)
- }
- friBgView.snp.makeConstraints { make in
- friBgViewTopConstraint = make.top.equalTo(friExpandButton.snp.bottom).offset(8.rpx).constraint
- make.left.bottom.right.equalToSuperview()
- }
-
- refreshButton.snp.makeConstraints { make in
- make.size.equalTo(CGSize(width: 40.rpx, height: 40.rpx))
- make.right.equalTo(-8.rpx)
- make.bottom.equalTo(friBgView.snp.top).offset(-12.rpx)
- }
-
- friHeaderView.snp.makeConstraints { make in
- make.left.right.equalTo(0)
- make.height.equalTo(61.rpx)
- make.top.equalTo(0)
- }
-
- friHeaderTitleIcon.snp.makeConstraints { make in
- make.size.equalTo(CGSize(width: 82.rpx, height: 26.5.rpx))
- make.left.equalTo(16.rpx)
- make.top.equalTo(16.rpx)
- }
-
- friHeaderAddBtn.snp.makeConstraints { make in
- make.size.equalTo(CGSize(width: 106.rpx, height: 32.rpx))
- make.right.equalTo(-8.rpx)
- make.centerY.equalTo(friHeaderTitleIcon.snp.centerY)
- }
-
- friTableView.snp.makeConstraints { make in
- make.left.equalTo(0)
- make.right.equalTo(0)
- make.top.equalTo(friBgView.snp.top).offset(50.rpx)
- make.bottom.equalTo(-12.rpx)
- }
- }
- }
- // MARK: - 点击事件
- extension QSLHomeFriendView {
- @objc func unlockBtnAction(){
- gravityInstance?.track(QSLGravityConst.home_coupon_click, properties: [:])
- QSLJumpManager.shared.unlockBtnAction()
- }
-
- @objc func homeFriPhoneViewAction() {
- delegate?.homeFriPhoneViewClick()
- }
-
- @objc func topAddButtonAction() {
- delegate?.addFriendAction(isSmall: true)
- }
- }
- extension QSLHomeFriendView: QSLHomeFriendTableViewCellDelegate {
-
- func routeBtnAction(model: QSLUserModel) {
- delegate?.routeBtnAction(model: model)
- }
-
- func locateBtnAction(model: QSLUserModel) {
- delegate?.locateBtnAction(model: model)
- }
-
- @objc private func handleCouponNotification(_ notification: Notification) {
- guard let shouldShow = notification.userInfo?["showCoupon"] as? Bool else { return }
-
- updateCouponViewVisibility(show: shouldShow)
- }
-
- private func updateCouponViewVisibility(show: Bool) {
- if(couponView.isHidden == !show){
- return
- }
- couponView.isHidden = !show
-
- if show {
- if let model = QSLCountdownManager.shared.selectGood {
- let amount : Int = Int((model.originalAmount - model.amount) / 100)
-
- let attr = NSMutableAttributedString()
-
- let firstText = "您有一订单未支付专属优惠券 "
- let firstAttr = NSMutableAttributedString(string: firstText)
- firstAttr.yy_font = UIFont.textM(10)
- firstAttr.yy_color = UIColor.white
- attr.append(firstAttr)
-
- if amount > 0 {
- let secondText = "-¥\(amount)"
- let secondAttr = NSMutableAttributedString(string: secondText)
- secondAttr.yy_font = UIFont.textB(15)
- secondAttr.yy_color = UIColor.hexStringColor(hexString: "#E1E3A3")
- attr.append(secondAttr)
- }
-
- self.couponLabel.attributedText = attr
-
- QSLCountdownManager.shared.updateHandler = { [weak self] timeString in
- self?.countdownLabel.updateCountdownText(timeString)
- }
- QSLCountdownManager.shared.finishHandler = { [weak self] in
- self?.updateCouponViewVisibility(show: false)
- }
- QSLCountdownManager.shared.startCountdown()
-
- }
-
- couponViewTopConstraint?.update(offset: 8.rpx)
- friBgViewTopConstraint?.update(offset: 8.rpx) // 修改这里
- friBgView.snp.remakeConstraints { make in
- make.top.equalTo(couponView.snp.bottom).offset(0)
- make.left.bottom.right.equalToSuperview()
- }
-
- refreshButton.snp.remakeConstraints { make in
- make.size.equalTo(CGSize(width: 40.rpx, height: 40.rpx))
- make.right.equalTo(-8.rpx)
- make.bottom.equalTo(couponView.snp.top).offset(-12.rpx)
- }
-
- } else {
- couponViewTopConstraint?.update(offset: 0)
- friBgView.snp.remakeConstraints { make in
- make.top.equalTo(friExpandButton.snp.bottom).offset(8.rpx)
- make.left.bottom.right.equalToSuperview()
- }
-
- refreshButton.snp.remakeConstraints { make in
- make.size.equalTo(CGSize(width: 40.rpx, height: 40.rpx))
- make.right.equalTo(-8.rpx)
- make.bottom.equalTo(friBgView.snp.top).offset(-12.rpx)
- }
- }
-
- UIView.animate(withDuration: 0.3) {
- self.layoutIfNeeded()
- }
- }
- }
- // MARK: - 添加滑动逻辑
- extension QSLHomeFriendView: UIGestureRecognizerDelegate {
-
- func addPanAction() {
- let pan = UIPanGestureRecognizer(target: self, action: #selector(panAction))
- pan.delegate = self
- self.addGestureRecognizer(pan)
- }
-
- @objc func panAction(pan: UIPanGestureRecognizer) {
-
- let point = pan.translation(in: self)
- if let scrollStopY = self.scrollStopY, scrollStopY > 0 {
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- }
-
- self.qsl_top += point.y
- if let scrollTopHeight = self.scrollTopHeight, self.qsl_top < scrollTopHeight {
- self.qsl_top = scrollTopHeight
- }
-
- if let scrollBottomHeight = self.scrollBottomHeight, self.qsl_top > scrollBottomHeight {
- self.qsl_top = scrollBottomHeight
- }
-
- if pan.state == .ended || pan.state == .cancelled {
-
- let velocity = pan.velocity(in: self)
- let speed = 350.0
-
- if let scrollLocation = self.scrollLocation {
- switch scrollLocation {
- case .ScrollTop:
- if velocity.y < -speed {
- self.scrollToLocation(type: .ScrollTop)
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- } else if velocity.y > speed {
- self.scrollToLocation(type: .ScrollCenter)
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- }
- break
- case .ScrollCenter:
- if velocity.y < -speed {
- self.scrollToLocation(type: .ScrollTop)
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- } else if velocity.y > speed {
- self.scrollToLocation(type: .ScrollBottom)
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- }
- break
- case .ScrollBottom:
- if velocity.y < -speed {
- self.scrollToLocation(type: .ScrollCenter)
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- } else if velocity.y > speed {
- self.scrollToLocation(type: .ScrollBottom)
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- return
- }
- break
- }
- }
-
- if self.qsl_top < (qsl_kScreenH - qsl_kTabbarBottom) / 4 {
- self.scrollToLocation(type: .ScrollTop)
- } else if self.qsl_top < (qsl_kScreenH - qsl_kTabbarBottom) / 4 * 3 && self.qsl_top > (qsl_kScreenH - qsl_kTabbarBottom) / 4 {
- self.scrollToLocation(type: .ScrollCenter)
- } else {
- self.scrollToLocation(type: .ScrollBottom)
- }
- }
-
- pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
- }
-
- func scrollToLocation(type: FriendViewLocation) {
-
- let animation = CASpringAnimation(keyPath: "position.y")
- animation.damping = 10
- animation.stiffness = 200
- animation.mass = 1
- animation.initialVelocity = 10
- animation.duration = animation.settlingDuration
- // animation.fromValue = self.friPhoneView.layer.position.y
- // animation.toValue = self.friPhoneView.layer.position.y + 2
- animation.isRemovedOnCompletion = false
- animation.fillMode = .forwards
-
- let animation1 = CASpringAnimation(keyPath: "position.y")
- animation1.damping = 10
- animation1.stiffness = 200
- animation1.mass = 1
- animation1.initialVelocity = 10
- animation1.duration = animation.settlingDuration
- animation1.fromValue = self.friTableView.layer.position.y
- animation1.toValue = self.friTableView.layer.position.y + 2
- animation1.isRemovedOnCompletion = false
- animation1.fillMode = .forwards
-
- self.scrollLocation = type
-
- if let topHeight = self.scrollTopHeight, let centerHeight = self.scrollCenterHeight, let bottomHeight = self.scrollBottomHeight {
- switch type {
-
- case .ScrollTop:
-
- UIView.animate(withDuration: 0.2) {
- self.qsl_top = topHeight
- } completion: { finished in
- self.friTableView.isScrollEnabled = true
- // self.friPhoneView.layer.add(animation, forKey: "animation")
- self.friTableView.layer.add(animation1, forKey: "animation")
- }
- break
- case .ScrollCenter:
-
- UIView.animate(withDuration: 0.2) {
- self.qsl_top = centerHeight
- } completion: { finished in
- self.friTableView.isScrollEnabled = false
- // self.friPhoneView.layer.add(animation, forKey: "animation")
- self.friTableView.layer.add(animation1, forKey: "animation")
- }
- break
- case .ScrollBottom:
-
- UIView.animate(withDuration: 0.2) {
- self.qsl_top = bottomHeight
- } completion: { finished in
- self.friTableView.isScrollEnabled = false
- // self.friPhoneView.layer.add(animation, forKey: "animation")
- self.friTableView.layer.add(animation1, forKey: "animation")
- }
- break
- }
- }
-
- delegate?.viewDidScroll()
- }
-
- func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
- return true
- }
-
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
- let currentPostion = scrollView.contentOffset.y
- self.scrollStopY = currentPostion
- }
- }
- extension QSLHomeFriendView: QSLHomeFriendFooterViewDelegate {
-
- func addButtonAction() {
- delegate?.addFriendAction(isSmall: false)
- }
- }
- // MARK: - 设置Tableview
- extension QSLHomeFriendView: UITableViewDelegate, UITableViewDataSource {
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- guard let friendList = viewModel?.friendList else { return 0 }
- return friendList.count
- }
-
- func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
-
- // if indexPath.row == 0 {
- //
- // cell.addCorner(conrners: [.topRight, .topLeft], radius: 6)
- // }
- //
- // if let friendList = viewModel?.friendList, indexPath.row == friendList.count - 1 {
- //
- // cell.addCorner(conrners: [.bottomLeft, .bottomRight], radius: 6)
- // }
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-
- let cell = tableView.dequeueReusableCell(cellType: QSLHomeFriendTableViewCell.self, cellForRowAt: indexPath)
- cell.selectionStyle = .none
- cell.delegate = self
- if let model = viewModel?.friendList[indexPath.row] {
- cell.config(model: model)
- }
- return cell
- }
-
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 94.rpx
- }
-
- func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
- return 0.0001
- }
-
- func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
- return 200.rpx
- }
-
- func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
- let view = QSLHomeFriendFooterView()
- view.delegate = self
- return view
- }
-
- }
|