QSLHomeFriendView.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. //
  2. // QSLHomeFriendView.swift
  3. // QuickSearchLocation
  4. //
  5. // Created by mac on 2024/4/12.
  6. //
  7. import UIKit
  8. import YYText
  9. import SnapKit
  10. enum FriendViewLocation {
  11. case ScrollTop
  12. case ScrollCenter
  13. case ScrollBottom
  14. }
  15. protocol QSLHomeFriendViewDelegate: NSObjectProtocol {
  16. func refreshBtnAction()
  17. func homeFriPhoneViewClick()
  18. func routeBtnAction(model: QSLUserModel)
  19. func locateBtnAction(model: QSLUserModel)
  20. func addFriendAction(isSmall: Bool)
  21. func viewDidScroll()
  22. }
  23. class QSLHomeFriendView: UIView {
  24. weak var delegate: QSLHomeFriendViewDelegate?
  25. // 动态约束处理
  26. var couponViewTopConstraint: Constraint? = nil
  27. private var friBgViewTopConstraint: Constraint? // 新增:保存friBgView的顶部约束
  28. var viewModel:QSLHomeViewModel? {
  29. didSet {
  30. friTableView.reloadData()
  31. }
  32. }
  33. /// 位置
  34. var scrollLocation: FriendViewLocation?
  35. /// 滑动到最后停下来的位置
  36. var scrollStopY: CGFloat?
  37. /// 滑动顶部距离顶部的距离
  38. var scrollTopHeight: CGFloat?
  39. /// 滑动中间距离顶部的距离
  40. var scrollCenterHeight: CGFloat?
  41. /// 滑动底部距离顶部的距离
  42. var scrollBottomHeight: CGFloat?
  43. lazy var friMapLogoImageView: UIImageView = {
  44. let imageView = UIImageView()
  45. imageView.isHidden = true
  46. imageView.image = UIImage(named: "home_friends_map_logo")
  47. return imageView
  48. }()
  49. lazy var friExpandButton: UIButton = {
  50. let button = UIButton(type: .custom)
  51. button.backgroundColor = UIColor.hexStringColor(hexString: "#333333", alpha: 0.6)
  52. button.addRadius(radius: 2)
  53. return button
  54. }()
  55. lazy var refreshButton: UIButton = {
  56. let button = UIButton(type: .custom)
  57. button.setBackgroundImage(UIImage(named: "home_refresh_btn"), for: .normal)
  58. button.addTarget(self, action: #selector(refreshBtnAction), for: .touchUpInside)
  59. return button
  60. }()
  61. lazy var couponView: UIImageView = {
  62. let view = UIImageView()
  63. view.image = UIImage(named: "home_activity_bg")
  64. view.isUserInteractionEnabled = true
  65. view.isHidden = true
  66. let tapG = UITapGestureRecognizer.init(target: self, action: #selector(unlockBtnAction))
  67. view.addGestureRecognizer(tapG)
  68. return view
  69. }()
  70. lazy var couponLabel: YYLabel = {
  71. let label = YYLabel()
  72. return label
  73. }()
  74. lazy var countdownLabel: QSLCountdownView = {
  75. let label = QSLCountdownView(frame: CGRectMake(0, 0, QSLConst.qsl_kScreenW - 24.rpx, 17.rpx),type: 1)
  76. return label
  77. }()
  78. lazy var couponBtn: UILabel = {
  79. let label = UILabel()
  80. label.gradientBackgroundColor(color1: UIColor.hexStringColor(hexString: "#FFFEF3", alpha: 1), color2: UIColor.hexStringColor(hexString: "#FFE6C0", alpha: 1), width: 65.rpx, height: 28.rpx, direction: .horizontal)
  81. label.text("去使用")
  82. label.textAlignment = .center
  83. label.font = UIFont.textM(14)
  84. label.textColor = (UIColor.hexStringColor(hexString: "#3A331C"))
  85. label.addRadius(radius: 14.rpx)
  86. return label
  87. }()
  88. lazy var friBgView: UIView = {
  89. let view = UIView()
  90. view.clipsToBounds = true
  91. view.backgroundColor = QSLColor.backGroundColor
  92. view.addRadius(radius: 12.rpx)
  93. return view
  94. }()
  95. lazy var friHeaderView: UIView = {
  96. let view = UIView(frame: CGRect(x: 0, y: 0, width: QSLConst.qsl_kScreenW, height: 61.rpx))
  97. 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) {
  98. view.backgroundColor = UIColor(patternImage: image)
  99. }
  100. view.addFourCorner(topLeft: 12.rpx, topRight: 12.rpx, bottomLeft: 0, bottomRight: 0)
  101. return view
  102. }()
  103. lazy var friHeaderTitleIcon: UIImageView = {
  104. let imageView = UIImageView()
  105. imageView.image = UIImage(named: "home_friends_header_title")
  106. return imageView
  107. }()
  108. lazy var friHeaderAddBtn: UIButton = {
  109. let btn = UIButton()
  110. btn.setBackgroundImage(UIImage(named: "home_friends_header_add_btn_bg"), for: .normal)
  111. btn.image(UIImage(named: "home_friends_header_add_icon"))
  112. btn.title("查找好友")
  113. btn.mediumFont(15)
  114. btn.textColor(.white)
  115. btn.setImageTitleLayout(.imgLeft, spacing: 0)
  116. btn.addTarget(self, action: #selector(topAddButtonAction), for: .touchUpInside)
  117. return btn
  118. }()
  119. lazy var friTableView: UITableView = {
  120. let tableView = UITableView(frame: .zero, style: .grouped)
  121. tableView.backgroundColor = .clear
  122. tableView.separatorStyle = .none
  123. tableView.showsVerticalScrollIndicator = false
  124. tableView.delegate = self
  125. tableView.dataSource = self
  126. tableView.tableViewNeverAdjustContentInset()
  127. tableView.bounces = false
  128. tableView.isUserInteractionEnabled = true
  129. tableView.isScrollEnabled = false
  130. tableView.contentInsetAdjustmentBehavior = .never
  131. tableView.register(cellClass: QSLHomeFriendTableViewCell.self)
  132. return tableView
  133. }()
  134. override init(frame: CGRect) {
  135. super.init(frame: frame)
  136. self.scrollCenterHeight = self.qsl_top
  137. self.scrollBottomHeight = qsl_kScreenH - qsl_kTabbarFrameH - 56 - 40
  138. self.setupUI()
  139. self.addPanAction()
  140. NotificationCenter.default.addObserver(
  141. self,
  142. selector: #selector(handleCouponNotification(_:)),
  143. name: Notification.Name("QSLHomeUpdateCouponViewNoti"),
  144. object: nil
  145. )
  146. //更新首页优惠券价格
  147. NotificationCenter.default.addObserver(
  148. self,
  149. selector: #selector(refreshCouponNotification(_:)),
  150. name: Notification.Name("QSLHomeRefreshCouponViewNoti"),
  151. object: nil
  152. )
  153. }
  154. required init?(coder: NSCoder) {
  155. fatalError("init(coder:) has not been implemented")
  156. }
  157. @objc func refreshBtnAction() {
  158. delegate?.refreshBtnAction()
  159. }
  160. }
  161. // MARK: - 设置UI
  162. extension QSLHomeFriendView {
  163. func setupUI() {
  164. addSubview(couponView)
  165. couponView.addSubview(couponBtn)
  166. couponView.addSubview(couponLabel)
  167. couponView.addSubview(countdownLabel)
  168. addSubview(friBgView)
  169. addSubview(friTableView)
  170. addSubview(friMapLogoImageView)
  171. addSubview(friExpandButton)
  172. addSubview(refreshButton)
  173. friBgView.addSubview(friHeaderView)
  174. friHeaderView.addSubview(friHeaderTitleIcon)
  175. friHeaderView.addSubview(friHeaderAddBtn)
  176. friMapLogoImageView.snp.makeConstraints { make in
  177. make.size.equalTo(CGSize(width: 62, height: 20))
  178. make.top.equalTo(0)
  179. make.left.equalTo(12)
  180. }
  181. friExpandButton.snp.makeConstraints { make in
  182. make.size.equalTo(CGSize(width: 80, height: 4))
  183. make.top.equalTo(friMapLogoImageView.snp.bottom).offset(8)
  184. make.centerX.equalTo(snp.centerX)
  185. }
  186. // couponView 的约束(初始时设为隐藏)
  187. couponView.snp.makeConstraints { make in
  188. make.left.equalTo(8.rpx)
  189. make.right.equalTo(-8.rpx)
  190. make.height.equalTo(58.rpx)
  191. couponViewTopConstraint = make.top.equalTo(friExpandButton.snp.bottom).offset(8.rpx).constraint
  192. }
  193. couponLabel.snp.makeConstraints { make in
  194. make.height.equalTo(22.rpx)
  195. make.top.equalTo(10.rpx)
  196. make.left.equalTo(60.rpx)
  197. make.right.equalTo(-12.rpx)
  198. }
  199. couponBtn.snp.makeConstraints { make in
  200. make.height.equalTo(28.rpx)
  201. make.width.equalTo(65.rpx)
  202. make.right.equalTo(-12.rpx)
  203. make.centerY.equalToSuperview()
  204. }
  205. countdownLabel.snp.makeConstraints { make in
  206. make.height.equalTo(17.rpx)
  207. make.top.equalTo(couponLabel.snp.bottom).offset(0)
  208. make.left.equalTo(60.rpx)
  209. make.right.equalTo(couponBtn.snp.left).offset(-10.rpx)
  210. }
  211. friBgView.snp.makeConstraints { make in
  212. friBgViewTopConstraint = make.top.equalTo(friExpandButton.snp.bottom).offset(8.rpx).constraint
  213. make.left.bottom.right.equalToSuperview()
  214. }
  215. refreshButton.snp.makeConstraints { make in
  216. make.size.equalTo(CGSize(width: 40.rpx, height: 40.rpx))
  217. make.right.equalTo(-8.rpx)
  218. make.bottom.equalTo(friBgView.snp.top).offset(-12.rpx)
  219. }
  220. friHeaderView.snp.makeConstraints { make in
  221. make.left.right.equalTo(0)
  222. make.height.equalTo(61.rpx)
  223. make.top.equalTo(0)
  224. }
  225. friHeaderTitleIcon.snp.makeConstraints { make in
  226. make.size.equalTo(CGSize(width: 82.rpx, height: 26.5.rpx))
  227. make.left.equalTo(16.rpx)
  228. make.top.equalTo(16.rpx)
  229. }
  230. friHeaderAddBtn.snp.makeConstraints { make in
  231. make.size.equalTo(CGSize(width: 106.rpx, height: 32.rpx))
  232. make.right.equalTo(-8.rpx)
  233. make.centerY.equalTo(friHeaderTitleIcon.snp.centerY)
  234. }
  235. friTableView.snp.makeConstraints { make in
  236. make.left.equalTo(0)
  237. make.right.equalTo(0)
  238. make.top.equalTo(friBgView.snp.top).offset(50.rpx)
  239. make.bottom.equalTo(-12.rpx)
  240. }
  241. }
  242. }
  243. // MARK: - 点击事件
  244. extension QSLHomeFriendView {
  245. @objc func unlockBtnAction(){
  246. gravityInstance?.track(QSLGravityConst.home_coupon_click, properties: [:])
  247. QSLJumpManager.shared.unlockBtnAction()
  248. }
  249. @objc func homeFriPhoneViewAction() {
  250. delegate?.homeFriPhoneViewClick()
  251. }
  252. @objc func topAddButtonAction() {
  253. delegate?.addFriendAction(isSmall: true)
  254. }
  255. }
  256. extension QSLHomeFriendView: QSLHomeFriendTableViewCellDelegate {
  257. func routeBtnAction(model: QSLUserModel) {
  258. delegate?.routeBtnAction(model: model)
  259. }
  260. func locateBtnAction(model: QSLUserModel) {
  261. delegate?.locateBtnAction(model: model)
  262. }
  263. @objc private func handleCouponNotification(_ notification: Notification) {
  264. guard let shouldShow = notification.userInfo?["showCoupon"] as? Bool else { return }
  265. updateCouponViewVisibility(show: shouldShow)
  266. }
  267. @objc private func refreshCouponNotification(_ notification: Notification) {
  268. refreshCouponView()
  269. }
  270. func refreshCouponView(){
  271. if let model = QSLCountdownManager.shared.selectGood {
  272. let amount : Int = Int((model.originalAmount - model.amount) / 100)
  273. let attr = NSMutableAttributedString()
  274. let firstText = "您有一订单未支付专属优惠券 "
  275. let firstAttr = NSMutableAttributedString(string: firstText)
  276. firstAttr.yy_font = UIFont.textM(10)
  277. firstAttr.yy_color = UIColor.white
  278. attr.append(firstAttr)
  279. if amount > 0 {
  280. let secondText = "-¥\(amount)"
  281. let secondAttr = NSMutableAttributedString(string: secondText)
  282. secondAttr.yy_font = UIFont.textB(18)
  283. secondAttr.yy_color = UIColor.hexStringColor(hexString: "#E1E3A3")
  284. attr.append(secondAttr)
  285. }
  286. self.couponLabel.attributedText = attr
  287. if(self.countdownLabel.label.text != nil){
  288. return
  289. }
  290. QSLCountdownManager.shared.updateHandler = { [weak self] timeString in
  291. self?.countdownLabel.updateCountdownText(timeString)
  292. }
  293. QSLCountdownManager.shared.finishHandler = { [weak self] in
  294. self?.updateCouponViewVisibility(show: false)
  295. }
  296. QSLCountdownManager.shared.startCountdown()
  297. }
  298. }
  299. private func updateCouponViewVisibility(show: Bool) {
  300. if(couponView.isHidden == !show){
  301. self.refreshCouponView()
  302. return
  303. }
  304. couponView.isHidden = !show
  305. if (show) {
  306. self.refreshCouponView()
  307. couponViewTopConstraint?.update(offset: 8.rpx)
  308. friBgViewTopConstraint?.update(offset: 8.rpx) // 修改这里
  309. friBgView.snp.remakeConstraints { make in
  310. make.top.equalTo(couponView.snp.bottom).offset(0)
  311. make.left.bottom.right.equalToSuperview()
  312. }
  313. refreshButton.snp.remakeConstraints { make in
  314. make.size.equalTo(CGSize(width: 40.rpx, height: 40.rpx))
  315. make.right.equalTo(-8.rpx)
  316. make.bottom.equalTo(couponView.snp.top).offset(-12.rpx)
  317. }
  318. } else {
  319. couponViewTopConstraint?.update(offset: 0)
  320. friBgView.snp.remakeConstraints { make in
  321. make.top.equalTo(friExpandButton.snp.bottom).offset(8.rpx)
  322. make.left.bottom.right.equalToSuperview()
  323. }
  324. refreshButton.snp.remakeConstraints { make in
  325. make.size.equalTo(CGSize(width: 40.rpx, height: 40.rpx))
  326. make.right.equalTo(-8.rpx)
  327. make.bottom.equalTo(friBgView.snp.top).offset(-12.rpx)
  328. }
  329. }
  330. UIView.animate(withDuration: 0.3) {
  331. self.layoutIfNeeded()
  332. }
  333. }
  334. }
  335. // MARK: - 添加滑动逻辑
  336. extension QSLHomeFriendView: UIGestureRecognizerDelegate {
  337. func addPanAction() {
  338. let pan = UIPanGestureRecognizer(target: self, action: #selector(panAction))
  339. pan.delegate = self
  340. self.addGestureRecognizer(pan)
  341. }
  342. @objc func panAction(pan: UIPanGestureRecognizer) {
  343. let point = pan.translation(in: self)
  344. if let scrollStopY = self.scrollStopY, scrollStopY > 0 {
  345. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  346. return
  347. }
  348. self.qsl_top += point.y
  349. if let scrollTopHeight = self.scrollTopHeight, self.qsl_top < scrollTopHeight {
  350. self.qsl_top = scrollTopHeight
  351. }
  352. if let scrollBottomHeight = self.scrollBottomHeight, self.qsl_top > scrollBottomHeight {
  353. self.qsl_top = scrollBottomHeight
  354. }
  355. if pan.state == .ended || pan.state == .cancelled {
  356. let velocity = pan.velocity(in: self)
  357. let speed = 350.0
  358. if let scrollLocation = self.scrollLocation {
  359. switch scrollLocation {
  360. case .ScrollTop:
  361. if velocity.y < -speed {
  362. self.scrollToLocation(type: .ScrollTop)
  363. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  364. return
  365. } else if velocity.y > speed {
  366. self.scrollToLocation(type: .ScrollCenter)
  367. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  368. return
  369. }
  370. break
  371. case .ScrollCenter:
  372. if velocity.y < -speed {
  373. self.scrollToLocation(type: .ScrollTop)
  374. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  375. return
  376. } else if velocity.y > speed {
  377. self.scrollToLocation(type: .ScrollBottom)
  378. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  379. return
  380. }
  381. break
  382. case .ScrollBottom:
  383. if velocity.y < -speed {
  384. self.scrollToLocation(type: .ScrollCenter)
  385. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  386. return
  387. } else if velocity.y > speed {
  388. self.scrollToLocation(type: .ScrollBottom)
  389. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  390. return
  391. }
  392. break
  393. }
  394. }
  395. if self.qsl_top < (qsl_kScreenH - qsl_kTabbarBottom) / 4 {
  396. self.scrollToLocation(type: .ScrollTop)
  397. } else if self.qsl_top < (qsl_kScreenH - qsl_kTabbarBottom) / 4 * 3 && self.qsl_top > (qsl_kScreenH - qsl_kTabbarBottom) / 4 {
  398. self.scrollToLocation(type: .ScrollCenter)
  399. } else {
  400. self.scrollToLocation(type: .ScrollBottom)
  401. }
  402. }
  403. pan.setTranslation(CGPoint(x: 0, y: 0), in: self)
  404. }
  405. func scrollToLocation(type: FriendViewLocation) {
  406. let animation = CASpringAnimation(keyPath: "position.y")
  407. animation.damping = 10
  408. animation.stiffness = 200
  409. animation.mass = 1
  410. animation.initialVelocity = 10
  411. animation.duration = animation.settlingDuration
  412. // animation.fromValue = self.friPhoneView.layer.position.y
  413. // animation.toValue = self.friPhoneView.layer.position.y + 2
  414. animation.isRemovedOnCompletion = false
  415. animation.fillMode = .forwards
  416. let animation1 = CASpringAnimation(keyPath: "position.y")
  417. animation1.damping = 10
  418. animation1.stiffness = 200
  419. animation1.mass = 1
  420. animation1.initialVelocity = 10
  421. animation1.duration = animation.settlingDuration
  422. animation1.fromValue = self.friTableView.layer.position.y
  423. animation1.toValue = self.friTableView.layer.position.y + 2
  424. animation1.isRemovedOnCompletion = false
  425. animation1.fillMode = .forwards
  426. self.scrollLocation = type
  427. if let topHeight = self.scrollTopHeight, let centerHeight = self.scrollCenterHeight, let bottomHeight = self.scrollBottomHeight {
  428. switch type {
  429. case .ScrollTop:
  430. UIView.animate(withDuration: 0.2) {
  431. self.qsl_top = topHeight
  432. } completion: { finished in
  433. self.friTableView.isScrollEnabled = true
  434. // self.friPhoneView.layer.add(animation, forKey: "animation")
  435. self.friTableView.layer.add(animation1, forKey: "animation")
  436. }
  437. break
  438. case .ScrollCenter:
  439. UIView.animate(withDuration: 0.2) {
  440. self.qsl_top = centerHeight
  441. } completion: { finished in
  442. self.friTableView.isScrollEnabled = false
  443. // self.friPhoneView.layer.add(animation, forKey: "animation")
  444. self.friTableView.layer.add(animation1, forKey: "animation")
  445. }
  446. break
  447. case .ScrollBottom:
  448. UIView.animate(withDuration: 0.2) {
  449. self.qsl_top = bottomHeight
  450. } completion: { finished in
  451. self.friTableView.isScrollEnabled = false
  452. // self.friPhoneView.layer.add(animation, forKey: "animation")
  453. self.friTableView.layer.add(animation1, forKey: "animation")
  454. }
  455. break
  456. }
  457. }
  458. delegate?.viewDidScroll()
  459. }
  460. func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
  461. return true
  462. }
  463. func scrollViewDidScroll(_ scrollView: UIScrollView) {
  464. let currentPostion = scrollView.contentOffset.y
  465. self.scrollStopY = currentPostion
  466. }
  467. }
  468. extension QSLHomeFriendView: QSLHomeFriendFooterViewDelegate {
  469. func addButtonAction() {
  470. delegate?.addFriendAction(isSmall: false)
  471. }
  472. }
  473. // MARK: - 设置Tableview
  474. extension QSLHomeFriendView: UITableViewDelegate, UITableViewDataSource {
  475. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  476. guard let friendList = viewModel?.friendList else { return 0 }
  477. return friendList.count
  478. }
  479. func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
  480. // if indexPath.row == 0 {
  481. //
  482. // cell.addCorner(conrners: [.topRight, .topLeft], radius: 6)
  483. // }
  484. //
  485. // if let friendList = viewModel?.friendList, indexPath.row == friendList.count - 1 {
  486. //
  487. // cell.addCorner(conrners: [.bottomLeft, .bottomRight], radius: 6)
  488. // }
  489. }
  490. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  491. let cell = tableView.dequeueReusableCell(cellType: QSLHomeFriendTableViewCell.self, cellForRowAt: indexPath)
  492. cell.selectionStyle = .none
  493. cell.delegate = self
  494. if let model = viewModel?.friendList[indexPath.row] {
  495. cell.config(model: model)
  496. }
  497. return cell
  498. }
  499. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  500. return 94.rpx
  501. }
  502. func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
  503. return 0.0001
  504. }
  505. func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
  506. return 200.rpx
  507. }
  508. func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
  509. let view = QSLHomeFriendFooterView()
  510. view.delegate = self
  511. return view
  512. }
  513. }