服务器之家

服务器之家 > 正文

swift4.2实现新闻首页导航

时间:2021-01-16 15:15     来源/作者:海阔任月飞

对于仿照新闻首页的页面,已经有比较好用的OC版本,现在我们来写一个swift版本的。

设备:xcode 10.2     语言:swift 4.2

效果图:

swift4.2实现新闻首页导航

我们先创建一个多控制器的导航栏,直接上代码:

  1. // 
  2. // JHSBarItemView.swift 
  3. // ScrollBarController 
  4. // 
  5. // Created by yaojinhai on 2019/4/15. 
  6. // Copyright © 2019年 yaojinhai. All rights reserved. 
  7. // 
  8.   
  9. import UIKit 
  10.   
  11. enum BarItemBorderType { 
  12.   case defualt 
  13.   case barItem 
  14.   case maskView 
  15.   case customItem 
  16.   
  17. protocol JHSBarItemViewDelegate: NSObjectProtocol { 
  18.   func selectedIndexItem(view: JHSBarItemView,index: Int) -> Void 
  19.   
  20. class JHSBarItemView: UIView { 
  21.   
  22.   var minMargin: CGFloat = BarConfig.minMargin; 
  23.    
  24.   weak var delegate: JHSBarItemViewDelegate? 
  25.   var lineBarView: UIView! 
  26.    
  27.   var barType = BarItemBorderType.defualt { 
  28.     didSet{ 
  29.       configBarType(); 
  30.       removeBarItem(idx: selectedIndex); 
  31.     } 
  32.   } 
  33.    
  34.    
  35.    
  36.   var selectedIndex = 0; 
  37.   var titles: [String]!{ 
  38.     didSet{ 
  39.       caculateItemSize(); 
  40.   
  41.     } 
  42.   } 
  43.    
  44.   private var titlesView: UICollectionView! 
  45.   private var cachesSize = [String:CGSize](); 
  46.   
  47.    
  48.   override init(frame: CGRect) { 
  49.     super.init(frame: frame); 
  50.     createContentView(); 
  51.   } 
  52.    
  53.   convenience init(frame: CGRect,titles: [String]) { 
  54.     self.init(frame: frame); 
  55.     self.titles = titles; 
  56.     createContentView(); 
  57.     caculateItemSize(); 
  58.   
  59.   } 
  60.    
  61.   func progressWidth() -> Void { 
  62.      
  63.   } 
  64.    
  65.    
  66.   required init?(coder aDecoder: NSCoder) { 
  67.     fatalError("init(coder:) has not been implemented"
  68.   } 
  69.    
  70.    
  71.   
  72. extension JHSBarItemView: UICollectionViewDataSource,UICollectionViewDelegateFlowLayout { 
  73.    
  74.   private func caculateItemSize() -> Void { 
  75.   
  76.     guard let itemTitles = titles ,itemTitles.count > 0 else { 
  77.       return
  78.     } 
  79.      
  80.     var maxWidth: CGFloat = 0; 
  81.     for item in itemTitles { 
  82.       let size = item.textSize(size: CGSize(width: width, height: height), font: BarConfig.normalFont); 
  83.       cachesSize[item] = CGSize(width: size.width, height: height); 
  84.       maxWidth += size.width; 
  85.     } 
  86.     let gap = (width - maxWidth) / CGFloat(itemTitles.count + 1); 
  87.     minMargin = max(gap, BarConfig.minMargin); 
  88.     titlesView.reloadData(); 
  89.     removeBarItem(idx: selectedIndex); 
  90.   
  91.   } 
  92.    
  93.   private func createContentView() -> Void { 
  94.      
  95.     if titlesView != nil { 
  96.       return
  97.     } 
  98.     let layout = UICollectionViewFlowLayout(); 
  99.     layout.minimumLineSpacing = 0; 
  100.     layout.minimumInteritemSpacing = 0; 
  101.     layout.scrollDirection = .horizontal; 
  102.     titlesView = FMBaseCollectionView(frame: .init(x: 0, y: 0, width: width, height: height), collectionViewLayout: layout); 
  103.     addSubview(titlesView); 
  104.     titlesView.register(BarItemViewCell.self, forCellWithReuseIdentifier: "title"); 
  105.     titlesView.delegate = self; 
  106.     titlesView.dataSource = self; 
  107.      
  108.     let lineView = createView(rect: .init(x: 0, y: height - 1, width: width, height: 1)); 
  109.     lineView.backgroundColor = rgbColor(rgb: 234); 
  110.      
  111.      
  112.   } 
  113.    
  114.   // MARK: - collection view delegate and dataSource 
  115.    
  116.   func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
  117.     return titles?.count ?? 0; 
  118.   } 
  119.   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 
  120.     return UIEdgeInsets(top: 0, left: minMargin, bottom: 0, right: minMargin); 
  121.   } 
  122.   
  123.    
  124.   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
  125.     if titles == nil { 
  126.       return CGSize.zero; 
  127.     } 
  128.     let item = titles[indexPath.row]; 
  129.     if let size = cachesSize[item] { 
  130.       return CGSize(width: size.width + minMargin, height: height); 
  131.     } 
  132.     let size = titles[indexPath.row].textSize(size: CGSize.init(width: width, height: height), font: BarConfig.normalFont); 
  133.     let newSize = CGSize(width: size.width + minMargin, height: height); 
  134.     cachesSize[item] = size; 
  135.     return newSize; 
  136.   } 
  137.    
  138.    
  139.   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
  140.     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "title"for: indexPath) as! BarItemViewCell; 
  141.     cell.titleLabel.text = titles[indexPath.row]; 
  142.     cell.titleLabel.isHighlighted = selectedIndex == indexPath.row; 
  143.     return cell; 
  144.   } 
  145.    
  146.   func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 
  147.     didSelected(idx: indexPath.row); 
  148.     delegate?.selectedIndexItem(view: self, index: indexPath.row); 
  149.   } 
  150.    
  151.   func didSelected(idx: Int) -> Void { 
  152.     let indexPath = IndexPath(item: idx, section: 0); 
  153.     titlesView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true); 
  154.   
  155.      
  156.     let cell = titlesView.cellForItem(at: indexPath) as? BarItemViewCell; 
  157.     cell?.titleLabel.isHighlighted = true
  158.     cell?.RunAnimation(); 
  159.      
  160.     removeBarItem(idx: indexPath.row); 
  161.      
  162.      
  163.     if selectedIndex != indexPath.row { 
  164.       let preCell = titlesView.cellForItem(at: .init(row: selectedIndex, section: 0)) as? BarItemViewCell; 
  165.       preCell?.titleLabel.isHighlighted = false
  166.       preCell?.RunAnimation(); 
  167.       selectedIndex = indexPath.row; 
  168.        
  169.     } 
  170.   } 
  171.   
  172. extension JHSBarItemView { 
  173.    
  174.   private func removeBarItem(idx: Int) { 
  175.     if barType == .barItem { 
  176.       let size = getMaxWidthAt(index: idx); 
  177.       lineBarView.frame = .init(x: size.width, y: height - 2, width: size.height, height: 2); 
  178.     }else if barType == .maskView { 
  179.       let size = getMaxWidthAt(index: idx); 
  180.       lineBarView.frame = .init(x: size.width - minMargin/2, y: 0, width: size.height + minMargin, height: height); 
  181.     } 
  182.   } 
  183.   func getMaxWidthAt(index: Int) -> CGSize { 
  184.     if titles == nil || titles.count == 0 { 
  185.       return CGSize.zero; 
  186.     } 
  187.      
  188.     var maxWidth: CGFloat = minMargin; 
  189.     var sizeWidth: CGFloat = cachesSize[titles[0]]!.width; 
  190.     if index > 0 { 
  191.       for item in 1...index { 
  192.         let title = titles[item]; 
  193.         let size = cachesSize[title]!; 
  194.         maxWidth += size.width + minMargin; 
  195.         sizeWidth = size.width; 
  196.       } 
  197.     } 
  198.     return CGSize(width: maxWidth + minMargin/2, height: sizeWidth); 
  199.   } 
  200.    
  201.   private func configBarType() -> Void { 
  202.     if barType == .barItem { 
  203.       if lineBarView == nil { 
  204.         lineBarView = createView(rect: .init(x: 0, y: height - 2, width: 30, height: 2)); 
  205.         lineBarView.backgroundColor = UIColor.red; 
  206.         lineBarView.layer.cornerRadius = 2; 
  207.         lineBarView.layer.masksToBounds = true
  208.       } 
  209.       titlesView.addSubview(lineBarView); 
  210.     }else if barType == .maskView { 
  211.       if lineBarView == nil { 
  212.         lineBarView = createView(rect: .init(x: 0, y: 0, width: 30, height: height)); 
  213.         lineBarView.backgroundColor = UIColor.green.withAlphaComponent(0.2); 
  214.         lineBarView.isUserInteractionEnabled = false
  215.       } 
  216.       titlesView.addSubview(lineBarView); 
  217.     }else
  218.       titlesView?.removeFromSuperview(); 
  219.   
  220.     } 
  221.   } 
  222.   
  223. class BarItemViewCell: UICollectionViewCell { 
  224.   var titleLabel: UILabel! 
  225.   override init(frame: CGRect) { 
  226.     super.init(frame: frame); 
  227.     titleLabel = createLabel(rect: bounds, text: ""); 
  228.     titleLabel.textAlignment = .center; 
  229.     titleLabel.textColor = BarConfig.normalColor; 
  230.     titleLabel.highlightedTextColor = BarConfig.hlightedColor; 
  231.     titleLabel.font = BarConfig.normalFont; 
  232.   } 
  233.    
  234.   required init?(coder aDecoder: NSCoder) { 
  235.     fatalError("init(coder:) has not been implemented"
  236.   } 
  237.   func RunAnimation(animation: Bool = true) -> Void { 
  238.     self.titleLabel.font = self.titleLabel.isHighlighted ? BarConfig.hlightedFont : BarConfig.normalFont; 
  239.      
  240.      
  241.   } 

这个封装了导航栏的操作,并且实现了自动刷新功能。我们也可以自己扩展实现。

我们来定义一个控制器:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//
// JHSBarController.swift
// ScrollBarController
//
// Created by yaojinhai on 2019/4/15.
// Copyright © 2019年 yaojinhai. All rights reserved.
//
 
import UIKit
 
protocol JHSBarControllerDelegate: NSObjectProtocol {
  func barControllerAt(controller: JHSBarController, index: Int) -> UIViewController;
  func barControllerForTitle(controller: JHSBarController,index: Int) -> String?
  func numberOfController(controller: JHSBarController) -> Int
}
 
class JHSBarController: JHSBaseViewController {
  
  private var topBarView: JHSBarItemView!
  private var cachesController = [Int:UIViewController]();
  private var cachesTitles = [Int:String]();
  private var countOfContrller = 0;
  
  weak var delegate: JHSBarControllerDelegate?
  
  var currentViewController: UIViewController{
    return getControllerAt(idx: selectedIndex);
  }
  
  var selectedIndex: Int {
    get {
      let offSet = contentScrollView.contentOffset;
      let index = Int((offSet.x + 10)/width());
      let idx = max(0, min(index, countOfContrller - 1));
      return idx;
    }
    set{
      let idx = max(0, min(newValue, countOfContrller - 1));
      toScrollAtIndex(atIndx: idx);
    }
  }
  
 
  override func viewDidLoad() {
    super.viewDidLoad()
    
    
    
    topBarView = JHSBarItemView(frame: .init(x: 0, y: 64, width: width(), height: 40), titles: ["音乐","视频","旅游","新闻"]);
    topBarView.delegate = self;
    topBarView.barType = .maskView;
 
    addView(tempView: topBarView);
    
    configContentView();
  }
  
  func reloadData() -> Void {
    cachesController.removeAll();
    cachesTitles.removeAll();
    countOfContrller = delegate?.numberOfController(controller: self) ?? 0;
    setBarTitles();
    
    contentScrollView.setContentOffset(.init(x: selectedIndex.cgFloat * width(), y:0), animated: false);
    contentScrollView.contentSize = .init(width: countOfContrller.cgFloat * width(), height: 0);
    addSubController();
    
    
  }
  
  private func setBarTitles() -> Void {
    var titles = [String]();
    for idx in 0..<countOfContrller {
      let tempTitme = delegate?.barControllerForTitle(controller: self, index: idx);
      cachesTitles[idx] = tempTitme ?? "";
      titles.append(tempTitme ?? "");
    }
    topBarView.titles = titles;
  }
  
  func isInScreen(rect: CGRect) -> Bool {
    let offset = contentScrollView.contentOffset;
    let bounds = contentScrollView.convert(.init(x: offset.x, y: offset.y, width: width(), height: contentScrollView.height), to: self.view);
    return bounds.intersects(rect);
  }
  
  private func toScrollAtIndex(atIndx: Int) -> Void {
    
    let isRight = atIndx < selectedIndex;
 
    let currentCtr = currentViewController;
    let currentRect = currentViewController.view.frame;
    
    currentCtr.view.frame.origin.x = atIndx.cgFloat * width();
 
    contentScrollView.contentOffset = .init(x: atIndx.cgFloat * width(), y: 0);
 
    let atCtroller = getControllerAt(idx: atIndx);
    let orginRect = atCtroller.view.frame;
    atCtroller.view.frame.origin.x += isRight ? -width() : width();
    
    contentScrollView.bringSubviewToFront(currentCtr.view);
 
    UIView.animate(withDuration: 0.3, animations: {
      currentCtr.view.frame.origin.x += isRight ? self.width() : -self.width();
      atCtroller.view.frame = orginRect;
    }) { (finshed) in
      currentCtr.view.frame = currentRect;
 
    }
  }
  
  private func addSubController() -> Void {
    
    let start = max(selectedIndex - 1, 0);
    let end = max(min(selectedIndex + 1, countOfContrller - 1), 0);
    
    for idx in start...end {
      _ = getControllerAt(idx: idx);
    }
    
  }
  private func getControllerAt(idx: Int) -> UIViewController {
    var controller = cachesController[idx];
    if controller == nil {
      controller = delegate?.barControllerAt(controller: self, index: idx);
      cachesController[idx] = controller;
    }
    let rect = CGRect(x: idx.cgFloat * width(), y: 0, width: width(), height: contentScrollView.height);
    controller?.view.frame = rect;
    if controller!.view.superview == nil {
      contentScrollView.addSubview(controller!.view);
    }
    if controller!.parent == nil {
      addChild(controller!);
    }
    if let scrollView = controller?.view as? UIScrollView {
      scrollView.contentOffset.y = 0;
    }
    if let subViews = controller?.view.subviews {
      for item in subViews {
        guard let scroll = item as? UIScrollView else{
          continue;
        }
        scroll.contentOffset.y = 0;
      }
    }
    return controller!;
  }
  
  
  func configContentView() -> Void {
    setContentScrollView(rect: CGRect.init(x: 0, y: topBarView.maxY, width: width(), height: height() - topBarView.height));
    contentScrollView.delegate = self;
    contentScrollView.isPagingEnabled = true;
    
  }
  
  func scrollViewDidScroll(_ scrollView: UIScrollView) {
    addSubController();
  }
  
  func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    for item in children {
      if !isInScreen(rect: item.view.frame) {
        item.removeFromParent();
        item.view.removeFromSuperview();
      }
    }
    addSubController();
    topBarView.didSelected(idx: selectedIndex);
  }
  func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
    scrollViewDidEndDecelerating(scrollView);
  }
  func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
      scrollViewDidEndDecelerating(scrollView);
    }
  }
 
}
 
extension JHSBarController: JHSBarItemViewDelegate{
  
  func selectedIndexItem(view: JHSBarItemView, index: Int) {
    selectedIndex = index;
  }
}

我们只要继承这个就可以了:下面我们看使用方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//
// MainViewController.swift
// ScrollBarController
//
// Created by yaojinhai on 2019/4/15.
// Copyright © 2019年 yaojinhai. All rights reserved.
//
 
import UIKit
 
class MainViewController: JHSBarController {
 
  override func viewDidLoad() {
    super.viewDidLoad()
 
    delegate = self;
    reloadData();
 
  }
 
}
 
extension JHSBarController: JHSBarControllerDelegate {
  func barControllerAt(controller: JHSBarController, index: Int) -> UIViewController {
    let ctrl = DetialViewController()
    ctrl.index = index;
    return ctrl;
  }
  
  func barControllerForTitle(controller: JHSBarController, index: Int) -> String? {
    return "第(index)个页面";
  }
  
  func numberOfController(controller: JHSBarController) -> Int {
    return 5;
  }
  
  
}

最后付上demo地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/yaojinhai06/article/details/89333005

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-07-29
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部