swift4.2实现新闻首页导航

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

设备:xcode 10.2     语言:swift 4.2

效果图:

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

//

// JHSBarItemView.swift

// ScrollBarController

//

// Created by yaojinhai on 2019/4/15.

// Copyright © 2019年 yaojinhai. All rights reserved.

//

import UIKit

enum BarItemBorderType {

case defualt

case barItem

case maskView

case customItem

}

protocol JHSBarItemViewDelegate: NSObjectProtocol {

func selectedIndexItem(view: JHSBarItemView,index: Int) -> Void

}

class JHSBarItemView: UIView {

var minMargin: CGFloat = BarConfig.minMargin;

weak var delegate: JHSBarItemViewDelegate?

var lineBarView: UIView!

var barType = BarItemBorderType.defualt {

didSet{

configBarType();

removeBarItem(idx: selectedIndex);

}

}

var selectedIndex = 0;

var titles: [String]!{

didSet{

caculateItemSize();

}

}

private var titlesView: UICollectionView!

private var cachesSize = [String:CGSize]();

override init(frame: CGRect) {

super.init(frame: frame);

createContentView();

}

convenience init(frame: CGRect,titles: [String]) {

self.init(frame: frame);

self.titles = titles;

createContentView();

caculateItemSize();

}

func progressWidth() -> Void {

}

required init?(coder aDecoder: NSCoder) {

fatalError("init(coder:) has not been implemented")

}

}

extension JHSBarItemView: UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {

private func caculateItemSize() -> Void {

guard let itemTitles = titles ,itemTitles.count > 0 else {

return;

}

var maxWidth: CGFloat = 0;

for item in itemTitles {

let size = item.textSize(size: CGSize(width: width, height: height), font: BarConfig.normalFont);

cachesSize[item] = CGSize(width: size.width, height: height);

maxWidth += size.width;

}

let gap = (width - maxWidth) / CGFloat(itemTitles.count + 1);

minMargin = max(gap, BarConfig.minMargin);

titlesView.reloadData();

removeBarItem(idx: selectedIndex);

}

private func createContentView() -> Void {

if titlesView != nil {

return;

}

let layout = UICollectionViewFlowLayout();

layout.minimumLineSpacing = 0;

layout.minimumInteritemSpacing = 0;

layout.scrollDirection = .horizontal;

titlesView = FMBaseCollectionView(frame: .init(x: 0, y: 0, width: width, height: height), collectionViewLayout: layout);

addSubview(titlesView);

titlesView.register(BarItemViewCell.self, forCellWithReuseIdentifier: "title");

titlesView.delegate = self;

titlesView.dataSource = self;

let lineView = createView(rect: .init(x: 0, y: height - 1, width: width, height: 1));

lineView.backgroundColor = rgbColor(rgb: 234);

}

// MARK: - collection view delegate and dataSource

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return titles?.count ?? 0;

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

return UIEdgeInsets(top: 0, left: minMargin, bottom: 0, right: minMargin);

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

if titles == nil {

return CGSize.zero;

}

let item = titles[indexPath.row];

if let size = cachesSize[item] {

return CGSize(width: size.width + minMargin, height: height);

}

let size = titles[indexPath.row].textSize(size: CGSize.init(width: width, height: height), font: BarConfig.normalFont);

let newSize = CGSize(width: size.width + minMargin, height: height);

cachesSize[item] = size;

return newSize;

}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "title", for: indexPath) as! BarItemViewCell;

cell.titleLabel.text = titles[indexPath.row];

cell.titleLabel.isHighlighted = selectedIndex == indexPath.row;

return cell;

}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

didSelected(idx: indexPath.row);

delegate?.selectedIndexItem(view: self, index: indexPath.row);

}

func didSelected(idx: Int) -> Void {

let indexPath = IndexPath(item: idx, section: 0);

titlesView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true);

let cell = titlesView.cellForItem(at: indexPath) as? BarItemViewCell;

cell?.titleLabel.isHighlighted = true;

cell?.RunAnimation();

removeBarItem(idx: indexPath.row);

if selectedIndex != indexPath.row {

let preCell = titlesView.cellForItem(at: .init(row: selectedIndex, section: 0)) as? BarItemViewCell;

preCell?.titleLabel.isHighlighted = false;

preCell?.RunAnimation();

selectedIndex = indexPath.row;

}

}

}

extension JHSBarItemView {

private func removeBarItem(idx: Int) {

if barType == .barItem {

let size = getMaxWidthAt(index: idx);

lineBarView.frame = .init(x: size.width, y: height - 2, width: size.height, height: 2);

}else if barType == .maskView {

let size = getMaxWidthAt(index: idx);

lineBarView.frame = .init(x: size.width - minMargin/2, y: 0, width: size.height + minMargin, height: height);

}

}

func getMaxWidthAt(index: Int) -> CGSize {

if titles == nil || titles.count == 0 {

return CGSize.zero;

}

var maxWidth: CGFloat = minMargin;

var sizeWidth: CGFloat = cachesSize[titles[0]]!.width;

if index > 0 {

for item in 1...index {

let title = titles[item];

let size = cachesSize[title]!;

maxWidth += size.width + minMargin;

sizeWidth = size.width;

}

}

return CGSize(width: maxWidth + minMargin/2, height: sizeWidth);

}

private func configBarType() -> Void {

if barType == .barItem {

if lineBarView == nil {

lineBarView = createView(rect: .init(x: 0, y: height - 2, width: 30, height: 2));

lineBarView.backgroundColor = UIColor.red;

lineBarView.layer.cornerRadius = 2;

lineBarView.layer.masksToBounds = true;

}

titlesView.addSubview(lineBarView);

}else if barType == .maskView {

if lineBarView == nil {

lineBarView = createView(rect: .init(x: 0, y: 0, width: 30, height: height));

lineBarView.backgroundColor = UIColor.green.withAlphaComponent(0.2);

lineBarView.isUserInteractionEnabled = false;

}

titlesView.addSubview(lineBarView);

}else{

titlesView?.removeFromSuperview();

}

}

}

class BarItemViewCell: UICollectionViewCell {

var titleLabel: UILabel!

override init(frame: CGRect) {

super.init(frame: frame);

titleLabel = createLabel(rect: bounds, text: "");

titleLabel.textAlignment = .center;

titleLabel.textColor = BarConfig.normalColor;

titleLabel.highlightedTextColor = BarConfig.hlightedColor;

titleLabel.font = BarConfig.normalFont;

}

required init?(coder aDecoder: NSCoder) {

fatalError("init(coder:) has not been implemented")

}

func RunAnimation(animation: Bool = true) -> Void {

self.titleLabel.font = self.titleLabel.isHighlighted ? BarConfig.hlightedFont : BarConfig.normalFont;

}

}

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

我们来定义一个控制器:

//

// 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;

}

}

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

//

// 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地址

以上是 swift4.2实现新闻首页导航 的全部内容, 来源链接: utcz.com/z/311838.html

回到顶部