這篇文章主要介紹了Tab Bar圖標怎么用,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了五華免費建站歡迎大家使用!
背景
框架自帶的 Tab Bar 相信大家已經(jīng)熟悉得不能再熟悉了,一般使用的時候不過是設(shè)置兩個圖標代表選中和未選中兩種狀態(tài),難免有一些平淡。后來很多控件就在標簽選中時進行一些比較抓眼球的動畫,不過我覺得大部分都是為了動畫而動畫。直到后來我看到Outlook客戶端的動畫時,我才意識到原來還可以跟用戶的交互結(jié)合在一起。
圖1 標簽圖標跟隨手勢進行不同的動畫
有意思吧,不過本文并不是要仿制個一模一樣的出來,會有稍微變化:
圖2 本文完成的最終效果
實現(xiàn)分析
寫代碼之前,咱先討論下實現(xiàn)的方法,相信你已經(jīng)猜到標簽頁的圖標顯然已經(jīng)不是圖片,而是一個自定義的UIView。將一個視圖掛載到原本圖標的位置并不是一件難事,稍微有些復雜的是數(shù)字滾輪效果的實現(xiàn),別看它數(shù)字不停地在滾動,仔細看其實最多顯示2種數(shù)字,也就說只要2個Label就夠了。
基于篇幅,文章不會涉及右側(cè)的時鐘效果,感興趣請直接參考源碼。
數(shù)字滾輪
打開項目TabBarInteraction,新建文件WheelView.swift,它是UIView的子類。首先設(shè)置好初始化函數(shù):
class WheelView: UIView { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupView() } override init(frame: CGRect) { super.init(frame: frame) setupView() } }
接著創(chuàng)建兩個Label實例,代表滾輪中的上下兩個Label:
private lazy var toplabel: UILabel = { return createDefaultLabel() }() private lazy var bottomLabel: UILabel = { return createDefaultLabel() }() private func createDefaultLabel() -> UILabel { let label = UILabel() label.textAlignment = NSTextAlignment.center label.adjustsFontSizeToFitWidth = true label.translatesAutoresizingMaskIntoConstraints = false return label }
現(xiàn)在來完成setupView()方法,在這方法中將上述兩個Label添加到視圖中,然后設(shè)置約束將它們的四邊都與layoutMarginsGuide對齊。
private func setupView() { translatesAutoresizingMaskIntoConstraints = false for label in [toplabel, bottomLabel] { addSubview(label) NSLayoutConstraint.activate([ label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor), label.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor), label.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor), label.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor) ]) } }
有人可能會問現(xiàn)在這樣兩個Label不是重疊的狀態(tài)嗎?不著急,接下來我們會根據(jù)參數(shù)動態(tài)地調(diào)整它們的大小和位置。
添加兩個實例變量progress和contents,分別表示滾動的總體進度和顯示的全部內(nèi)容。
var progress: Float = 0.0 var contents = [String]()
我們接下來要根據(jù)這兩個變量計算出當前兩個Label顯示的內(nèi)容以及它們的縮放位置。這些計算都在progress的didSet里完成:
var progress: Float = 0.0 { didSet { progress = min(max(progress, 0.0), 1.0) guard contents.count > 0 else { return } /** 根據(jù) progress 和 contents 計算出上下兩個 label 顯示的內(nèi)容以及 label 的壓縮程度和位置 * * Example: * progress = 0.4, contents = ["A","B","C","D"] * * 1)計算兩個label顯示的內(nèi)容 * topIndex = 4 * 0.4 = 1.6, topLabel.text = contents[1] = "B" * bottomIndex = 1.6 + 1 = 2.6, bottomLabel.text = contents[2] = "C" * * 2) 計算兩個label如何壓縮和位置調(diào)整,這是實現(xiàn)滾輪效果的原理 * indexOffset = 1.6 % 1 = 0.6 * halfHeight = bounds.height / 2 * ┌─────────────┐ ┌─────────────┐ * |┌───────────┐| scaleY | | * || || 1-0.6=0.4 | | translationY * || topLabel || ----------> |┌─ topLabel─┐| ------------------ * || || |└───────────┘| -halfHeight * 0.6 ? ┌─────────────┐ * |└───────────┘| | | ? |┌─ toplabel─┐| * └─────────────┘ └─────────────┘ ? |└───────────┘| * ? |┌───────────┐| * ┌─────────────┐ ┌─────────────┐ ? ||bottomLabel|| * |┌───────────┐| scaleY | | ? |└───────────┘| * || || 0.6 |┌───────────┐| translationY ? └─────────────┘ * ||bottomLabel|| ----------> ||bottomLabel|| ----------------- * || || |└───────────┘| halfHeight * 0.4 * |└───────────┘| | | * └─────────────┘ └─────────────┘ * * 可以想象出,當 indexOffset 從 0.0 遞增到 0.999 過程中, * topLabel 從滿視圖越縮越小至0,而 bottomLabel剛好相反越變越大至滿視圖,即形成一次完整的滾動 */ let topIndex = min(max(0.0, Float(contents.count) * progress), Float(contents.count - 1)) let bottomIndex = min(topIndex + 1, Float(contents.count - 1)) let indexOffset = topIndex.truncatingRemainder(dividingBy: 1) toplabel.text = contents[Int(topIndex)] toplabel.transform = CGAffineTransform(scaleX: 1.0, y: CGFloat(1 - indexOffset)) .concatenating(CGAffineTransform(translationX: 0, y: -(toplabel.bounds.height / 2) * CGFloat(indexOffset))) bottomLabel.text = contents[Int(bottomIndex)] bottomLabel.transform = CGAffineTransform(scaleX: 1.0, y: CGFloat(indexOffset)) .concatenating(CGAffineTransform(translationX: 0, y: (bottomLabel.bounds.height / 2) * (1 - CGFloat(indexOffset)))) } }
最后我們還要向外公開一些樣式進行自定義:
extension WheelView { /// 前景色變化事件 override func tintColorDidChange() { [toplabel, bottomLabel].forEach { $0.textColor = tintColor } layer.borderColor = tintColor.cgColor } /// 背景色 override var backgroundColor: UIColor? { get { return toplabel.backgroundColor } set { [toplabel, bottomLabel].forEach { $0.backgroundColor = newValue } } } /// 邊框?qū)挾? var borderWidth: CGFloat { get { return layer.borderWidth } set { layoutMargins = UIEdgeInsets(top: newValue, left: newValue, bottom: newValue, right: newValue) layer.borderWidth = newValue } } /// 字體 var font: UIFont { get { return toplabel.font } set { [toplabel, bottomLabel].forEach { $0.font = newValue } } } }
至此,整個滾輪效果已經(jīng)完成。
掛載視圖
在FirstViewController中實例化剛才自定義的視圖,設(shè)置好字體、邊框、背景色、Contents等內(nèi)容,別忘了isUserInteractionEnabled設(shè)置為false,這樣就不會影響原先的事件響應。
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. tableView.delegate = self tableView.dataSource = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell") tableView.rowHeight = 44 wheelView = WheelView(frame: CGRect.zero) wheelView.font = UIFont.systemFont(ofSize: 15, weight: .bold) wheelView.borderWidth = 1 wheelView.backgroundColor = UIColor.white wheelView.contents = data wheelView.isUserInteractionEnabled = false }
然后要把視圖掛載到原先的圖標上,viewDidLoad()方法底部新增代碼:
override func viewDidLoad() { ... guard let parentController = self.parent as? UITabBarController else { return } let controllerIndex = parentController.children.firstIndex(of: self)! var tabBarButtons = parentController.tabBar.subviews.filter({ type(of: $0).description().isEqual("UITabBarButton") }) guard !tabBarButtons.isEmpty else { return } let tabBarButton = tabBarButtons[controllerIndex] let swappableImageViews = tabBarButton.subviews.filter({ type(of: $0).description().isEqual("UITabBarSwappableImageView") }) guard !swappableImageViews.isEmpty else { return } let swappableImageView = swappableImageViews.first! tabBarButton.addSubview(wheelView) swappableImageView.isHidden = true NSLayoutConstraint.activate([ wheelView.widthAnchor.constraint(equalToConstant: 25), wheelView.heightAnchor.constraint(equalToConstant: 25), wheelView.centerXAnchor.constraint(equalTo: swappableImageView.centerXAnchor), wheelView.centerYAnchor.constraint(equalTo: swappableImageView.centerYAnchor) ]) }
上述代碼的目的是最終找到對應標簽UITabBarButton內(nèi)類型為UITabBarSwappableImageView的視圖并替換它??瓷先ハ喈攺碗s,但是它盡可能地避免出現(xiàn)意外情況導致程序異常。只要以后UIkit不更改類型UITabBarButton和UITabBarSwappableImageView,以及他們的包含關(guān)系,程序基本不會出現(xiàn)意外,最多導致自定義的視圖掛載不上去而已。另外一個好處是FirstViewController不用去擔心它被添加到TabBarController中的第幾個標簽上??傮w來說這個方法并不完美,但目前似乎也沒有更好的方法?
實際上還可以將上面的代碼剝離出來,放到名為TabbarInteractable的protocol的默認實現(xiàn)上。有需要的ViewController只要宣布遵守該協(xié)議,然后在viewDidLoad方法中調(diào)用一個方法即可實現(xiàn)整個替換過程。
只剩下最后一步了,我們知道UITableView是UIScrollView的子類。在它滾動的時候,F(xiàn)irsViewController作為UITableView的delegate,同樣會收到scrollViewDidScroll方法的調(diào)用,所以在這個方法里更新滾動的進度再合適不過了:
// MARK: UITableViewDelegate extension FirstViewController: UITableViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { //`progress`怎么計算取決于你需求,這里的是為了把`tableview`當前可見區(qū)域最底部的2個數(shù)字給顯示出來。 let progress = Float((scrollView.contentOffset.y + tableView.bounds.height - tableView.rowHeight) / scrollView.contentSize.height) wheelView.progress = progress } }
把項目跑起來看看吧,你會得到文章開頭的效果。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“Tab Bar圖標怎么用”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學習!
文章名稱:TabBar圖標怎么用
標題路徑:http://aaarwkj.com/article34/isgese.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導航、網(wǎng)站收錄、軟件開發(fā)、域名注冊、虛擬主機、手機網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)