| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- //
- // SlideSegmentView.swift
- // swift翻译
- //
- // Created by zhongyuan on 2018/3/20.
- // Copyright © 2018年 zhongyuan. All rights reserved.
- //
- import UIKit
- import SnapKit
- @IBDesignable
- class SlideSegmentView: UIView, UIScrollViewDelegate {
-
- /// MARK: -- 属性
- @IBOutlet weak var titleScrollViews: UIScrollView!
- @IBOutlet weak var titleStackViews: UIStackView!
- @IBOutlet weak var contentScrollViews: UIScrollView!
- @IBOutlet weak var contentStackViews: UIStackView!
- @IBOutlet weak var titleStackViewWidthConstraints: NSLayoutConstraint!
- @IBOutlet weak var titleStackViewLeftConstraints: NSLayoutConstraint!
- @IBOutlet weak var titleStackViewRightConstraints: NSLayoutConstraint!
- @IBOutlet weak var UnderlineView: UIView!
- @IBOutlet weak var contentView: UIView!
- @IBOutlet weak var contentStackWidth: NSLayoutConstraint!
-
- var titleColorNormal:UIColor = UIColor.orange//Color_SlideSegmentView_titleColorNormal
- var titleColorSelected:UIColor = UIColor.orange//Color_SlideSegmentView_titleColorSelected
- var titleFont:UIFont = UIFont.systemFont(ofSize: 15)
- var underlineViewBgColor:UIColor = UIColor.orange //Color_family_normal
- var titleViews:[UIView] = [UIView]()
- var curPageIndex = 0
-
- var titles:Array<String> = [] /**< 标签标题 */
- {
- didSet{
- for subview:UIView in titleStackViews.arrangedSubviews {
- titleStackViews.removeArrangedSubview(subview)
- }
-
- for subview:UIView in contentStackViews.arrangedSubviews {
- contentStackViews.removeArrangedSubview(subview)
- }
-
- titleScrollViews.contentOffset = CGPoint.zero
- contentScrollViews.contentOffset = CGPoint.zero
-
- for title in titles {
-
- let btn:UIButton = UIButton.init(type: .custom)
- btn.titleLabel?.font = titleFont
- btn.setTitleColor(titleColorNormal, for: .normal)
- btn.setTitleColor(titleColorSelected, for: .selected)
- btn.setTitle(title, for: .normal)
- btn.sizeToFit()
- btn.addTarget(self, action:#selector(onTitleButtomClick( sender: )), for: .touchUpInside)
-
- titleStackViews.addArrangedSubview(btn)
- }
-
- self.refreshTitleSpace()
-
- contentScrollViews.contentSize = CGSize(width: width * CGFloat(titles.count), height: contentScrollViews.superview!.height - contentScrollViews.y)
- contentStackWidth.constant = CGFloat(titles.count) * width
-
- for _ in 0..<titles.count {
- let subView = UIView()
- subView.backgroundColor = UIColor.clear
- contentStackViews.addArrangedSubview(subView)
- }
-
- titleViews = []
- for btn in titleStackViews.arrangedSubviews {
- titleViews.append(btn)
- }
-
- pageIndex = 0
- }
- }
-
- /**< 配置内容视图 */
- var contentViews:Array<UIView> = []
- {
- didSet{
- let count = contentViews.count
- if count != viewControllers.count {
- viewControllers = []
- }else {
- for i in 0..<count{
- if viewControllers[i].view != contentViews[i]{
- viewControllers = []
- }
- }
- }
-
- for i in 0..<count {
- let contentView:UIView = contentViews[i]
- let superview:UIView = contentStackViews.arrangedSubviews[i]
- superview.addSubview(contentView)
- contentView.snp.makeConstraints({ (mark) in
- mark.edges.equalTo(superview)
- })
- }
- }
- }
-
- /**< 配置内容视图控制器 */
- var viewControllers: Array<UIViewController> = []
- {
- didSet{
- if(viewControllers.count > 0){
- var views:Array<UIView> = []
- for vc in viewControllers {
- views.append(vc.view)
- }
- self.contentViews = views
- }
- }
- }
-
- var didScrollToIndex:((Int)->())? /**< 滚动到第index页时回调 */
- var space:CGFloat = 30 /**< 各标题的间隔 */
- var pageIndex:Int /**< 当前页index */
- {
- set{
- self.setPageIndex(pageIndex: newValue , animated: false)
- }
- get{
- for titleBtn in titleStackViews.arrangedSubviews
- {
- if (titleBtn as! UIButton).isSelected
- {
- return titleStackViews.arrangedSubviews.firstIndex(of: titleBtn)!
- }
- }
- return 0
- }
- }
-
- func setPageIndex(pageIndex:Int,animated:Bool){
- self.layoutIfNeeded()
-
- if titleStackViews.arrangedSubviews.count <= pageIndex {
- return
- }
-
- for titleBtn in titleStackViews.arrangedSubviews {
- (titleBtn as! UIButton).isSelected = false
- }
-
- let sender:UIButton = titleStackViews.arrangedSubviews[pageIndex] as! UIButton
- sender.isSelected = true
-
- // 滚动标题栏、内容栏
- let count = self.titleViews.count
- let startX = self.titleViews[pageIndex].frame.origin.x
- let isRight = (pageIndex - self.curPageIndex) > 0
- let isLeft = (pageIndex - self.curPageIndex) < 0
- let width = self.titleViews[pageIndex].width + self.space
- let endX = startX + width
- let x = self.width * CGFloat(pageIndex)
- let _animated = abs(contentScrollViews.contentOffset.x - x) <= self.width
- contentScrollViews.setContentOffset(CGPoint(x: x, y: 0), animated: animated && _animated)
-
- //向左滑,且左边有未显示的部分
- if isLeft,self.titleScrollViews.contentOffset.x > 0 {
- //若当前单元格的前一个单元格已到最左边或之前,则向右滑
- if (startX - self.titleScrollViews.contentOffset.x - width) < 10 {
- var offectX = (startX - width)
- offectX = max(offectX, 0)
- self.titleScrollViews.setContentOffset(CGPoint.init(x: offectX, y: 0), animated: animated)
- }
- }
- //向右滑,且右边有未显示的部分
- if isRight,(self.titleScrollViews.contentOffset.x + self.width) < self.titleViews[count - 1].right{
- //若当前单元格的后一个单元格已到最右边,则向左滑
- if (endX + width) > (self.width - 10) {
- var offectX = (endX + width - self.width)
- offectX = min(offectX, self.titleViews[count - 1].right - self.width + space)
- self.titleScrollViews.setContentOffset(CGPoint.init(x: offectX, y: 0), animated: animated)
- }
- }
-
- titleScrollViews.layoutIfNeeded()
-
- UIView.animate(withDuration: 0.25) {
-
- let strW:CGFloat = (self.titleStackViews.subviews[pageIndex] as! UIButton).width
- self.UnderlineView.snp.remakeConstraints({ (mark) in
- mark.bottom.equalTo(self.titleScrollViews)
- mark.centerX.equalTo(sender)
- mark.width.equalTo(strW)
- mark.height.equalTo(3)
- })
-
- self.titleScrollViews.layoutIfNeeded()
- }
-
- if didScrollToIndex != nil{
- didScrollToIndex!(pageIndex)
- }
-
- curPageIndex = pageIndex
- }
-
- override func awakeFromNib() {
- super.awakeFromNib()
- contentScrollViews.delegate = self
- UnderlineView.backgroundColor = underlineViewBgColor
- }
-
- override func layoutSubviews() {
- super.layoutSubviews()
-
- self.refreshTitleSpace()
- contentScrollViews.contentSize = CGSize.init(width: self.width * CGFloat(titles.count), height: contentScrollViews.superview!.height - contentScrollViews.y)
- contentStackWidth.constant = CGFloat(titles.count) * self.width
- }
-
- @objc func onTitleButtomClick(sender:UIButton) -> Void {
- self.setPageIndex(pageIndex: titleStackViews.arrangedSubviews.firstIndex(of: sender)!, animated: true)
- }
-
- func refreshTitleSpace() {
- if titles.count == 0 {
- return
- }
-
- let calculativeWidth: (String) -> CGFloat = { str in
- return str.boundingRect(with: CGSize.init(width: 999999,
- height: self.titleFont.pointSize),
- options: [.usesLineFragmentOrigin,
- .usesFontLeading],
- attributes: [NSAttributedString.Key.font: self.titleFont],
- context: nil).size.width //ld??
- }
-
- var len = calculativeWidth({ () -> String in
- var str = String()
- for title in self.titles {
- str.append(title)
- }
- return str
- }())
- // dPrint("总的宽度: \(len)")
-
- len += CGFloat(titles.count) // 这里每个title加上1是因为button的宽度和string的宽度有不到一的差距
-
- var flag = true
- let averageWith = (width - space * CGFloat(titles.count)) / CGFloat(titles.count) // 平均宽度
-
- for title in self.titles {
-
- let length = calculativeWidth(title)
- if length > averageWith {
-
- flag = false
- break
- }
- }
-
- if len + space * CGFloat(titles.count) < self.width && flag {
- titleStackViewLeftConstraints.constant = space/2
- titleStackViewRightConstraints.constant = space/2
- titleStackViewWidthConstraints.constant = self.width - space
- titleStackViews.distribution = .fillEqually
- titleStackViews.spacing = space
- } else {
- titleStackViews.distribution = .fill
- titleStackViewWidthConstraints.constant = len + space * CGFloat((titles.count - 1))
- titleStackViewLeftConstraints.constant = space/2
- titleStackViewRightConstraints.constant = space/2
- titleStackViews.spacing = space
- }
- }
-
- //MARK: - UIScrollViewDelegate
- func scrollViewWillEndDragging(_ scrollView: UIScrollView,
- withVelocity velocity: CGPoint,
- targetContentOffset: UnsafeMutablePointer<CGPoint>) {
- if (scrollView == contentScrollViews) {
- let i = (Int)(targetContentOffset.pointee.x / scrollView.width)
- self.setPageIndex(pageIndex: i, animated: true)
- }
- }
-
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
-
- }
-
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- initialFromXib()
- }
-
- required init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)
-
- initialFromXib()
- }
-
- func initialFromXib() {
- let bundle = Bundle.init(for: self.classForCoder)
- let nib = UINib(nibName: "SlideSegmentView", bundle: bundle)
- contentView = nib.instantiate(withOwner: self, options: nil)[0] as? UIView
- contentView.frame = bounds
- addSubview(contentView)
- }
- }
- //MARK: -String 扩展
- extension String{
- func width() -> (UIFont,CGFloat)->CGFloat {
- return { (font:UIFont,height:CGFloat) -> CGFloat in
- if (self as NSString).length == 0 {
- return 0
- }
-
- return self.boundingRect(with: CGSize.init(width: 0,
- height: height),
- options: [.usesLineFragmentOrigin,
- .usesFontLeading],
- attributes: [NSAttributedString.Key.font:font],
- context: nil).size.width
- }
- }
- }
|