Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【Swift】Swift4でHMSegmentedControlを試す

■はじめに

メルカリのiOSアプリのような横スクロールでメニューを切り替えられるライブラリである、HMSegmentedControlを試してみました。

 

■開発環境

Xcode 10.1

・Swift 4.2.1

HMSegmentedControl 1.5.5

 

■サンプルのイメージ 

f:id:hfoasi8fje3:20190113231835g:plain

 

■実装部分

1.以下HMSegmentedControlのドキュメントにしたがってライブラリをインストール

https://github.com/HeshamMegid/HMSegmentedControl

 

2.StoryboardでUIViewとUIScrollViewを配置

f:id:hfoasi8fje3:20190113233527p:plain

 

3.ViewController.swiftに以下実装

import UIKit
import HMSegmentedControl

class ViewController: UIViewController, UIScrollViewDelegate {
    // メニューを表示するView
    @IBOutlet weak var headerView: UIView!
    // メニューごとのViewを表示するScrollView
    @IBOutlet weak var scrollView: UIScrollView!
    
    // HMSegmentedControlをインスタンス化
    var segmentedControls: HMSegmentedControl!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // headerViewに合わせてsegmentedControlsのサイズを指定
        let statusbarHeight: CGFloat = UIApplication.shared.statusBarFrame.height
        self.segmentedControls = HMSegmentedControl(frame: CGRect(x: 0, y: statusbarHeight, width: self.view.frame.size.width, height:self.headerView.frame.size.height))
        // メニューのタイトル
        self.segmentedControls.sectionTitles = ["Menu1", "Menu2", "Menu3"]
        // インジケータのスタイルを指定
        self.segmentedControls.selectionIndicatorLocation =  HMSegmentedControlSelectionIndicatorLocation.down
        self.segmentedControls.selectionStyle = HMSegmentedControlSelectionStyle.fullWidthStripe
        // インジケータの色を指定
        self.segmentedControls.selectionIndicatorColor = UIColor(red: 30/255, green: 144/255, blue: 255/255, alpha: 1.0)
        // インジケータの高さ(太さ)を指定
        self.segmentedControls.selectionIndicatorHeight = 2.0
        // segmentedControlsで選択中の文字の色
        self.segmentedControls.selectedTitleTextAttributes = [
            NSAttributedString.Key.foregroundColor: UIColor(red: 30/255, green: 144/255, blue: 255/255, alpha: 1.0),
            NSAttributedString.Key.font: UIFont(name: "HiraginoSans-W6", size: 16)!
        ]
        // segmentedControlsで非選択中の文字の色
        self.segmentedControls.titleTextAttributes = [
            NSAttributedString.Key.foregroundColor: UIColor.lightGray,
            NSAttributedString.Key.font: UIFont(name: "HiraginoSans-W6", size: 16)!
        ]
        
        self.view.addSubview(segmentedControls)
        
        // メニューで選択したタイトルに合わせてScrollViewの表示を変更する
        let blockVariable: IndexChangeBlock =  {(index: Int) -> Void in
            let frame = CGRect(x: self.scrollView.frame.size.width * CGFloat(index), y: 0, width: self.scrollView.frame.size.width, height: self.scrollView.frame.size.height)
            self.scrollView.scrollRectToVisible(frame, animated: true)
        }
        segmentedControls.indexChangeBlock = blockVariable
        
        scrollView.delegate = self
        // メニュー単位のスクロールを可能にする
        scrollView.isPagingEnabled = true
        // 水平方向のスクロールインジケータを非表示にする
        scrollView.showsHorizontalScrollIndicator = false
        // scrollViewのサイズを指定(幅は1メニューに表示するViewの幅×メニュー数)
        scrollView.contentSize = CGSize(width: self.view.frame.size.width * 3, height: self.scrollView.frame.size.height)

        // 各メニューに表示するViewを生成
        let menu1 = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height))
        menu1.backgroundColor = UIColor.cyan
        self.scrollView.addSubview(menu1)
        
        let menu2 = UIView(frame: CGRect(x: self.view.frame.size.width, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height))
        menu2.backgroundColor = UIColor.red
        self.scrollView.addSubview(menu2)
        
        let menu3 = UIView(frame: CGRect(x: self.view.frame.size.width * 2, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height))
        menu3.backgroundColor = UIColor.green
        self.scrollView.addSubview(menu3)
    }
    
    // ScrollViewの横スクロールに合わせてメニューのインジケータを移動する
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        segmentedControls.selectedSegmentIndex = Int(scrollView.contentOffset.x / scrollView.frame.maxX)
    }
}

 

■おわりに

HMSegmentedControlを使った実装に関して、Swift 4系で実装している記事がなかったので記事にしてみました。また、他の記事よりも各実装内容に対してコメントを多めに書いてみたので、少しでも参考になればと思います。

 

■関連リンク

GitHub - HeshamMegid/HMSegmentedControl: A drop-in replacement for UISegmentedControl mimicking the style of the segmented control used in Google Currents and various other Google products.

iOSでマテリアルデザインのようなタブが作れるHMSegmentedControl | DevelopersIO

Swift 2 - HMSegmentedControlにてタブ部分とScrollViewを連動させる方法|teratail