Swift PageViewController内からページングを行うサンプル

やること

PageViewController内のボタンからページングを行う

実行結果


PageViewController on Swift

スマニュー的なUIの実装の方が楽に遷移できそうなきがする.

コード

ViewController.swift

import UIKit

class ViewController: UIViewController {
    var way:UIPageViewControllerNavigationDirection = .forward
    var at = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let r: CGFloat = CGFloat(arc4random_uniform(255)+1) / 255.0
        let g: CGFloat = CGFloat(arc4random_uniform(255)+1) / 255.0
        let b: CGFloat = CGFloat(arc4random_uniform(255)+1) / 255.0
        let color: UIColor = UIColor(red: r, green: g, blue: b, alpha: 1.0)
        view.backgroundColor = color
        let button = UIButton()
        button.setTitle("Tap Me!", for: .normal)
        button.setTitleColor(UIColor.blue, for: .normal)
        button.setTitle("Tapped!", for: .highlighted)
        button.setTitleColor(UIColor.red, for: .highlighted)
        button.frame = CGRect(x: 0,y: 0,width: 300,height: 50)
        button.tag = 1
        button.layer.position = CGPoint(x: self.view.frame.width / 2, y: view.bounds.height / 2)
        button.backgroundColor = UIColor.white
        button.layer.cornerRadius = 10
        button.layer.borderWidth = 1
        button.addTarget(self, action: #selector(self.buttonTapped), for:.touchDown)
        view.addSubview(button)
    }

    @objc func buttonTapped() {
        if let vc = self.parent as? PageViewController {
            vc.setViewControllers([vc.vcArray[at]], direction: way, animated: true, completion: nil)
        }
    }
}

PageViewController.swift

import UIKit

class PageViewController: UIPageViewController, UIPageViewControllerDataSource {
    var vcArray:[UIViewController] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        let vc1 = ViewController()
        vc1.way = .forward
        vc1.at = 1
        vcArray.append(vc1)
        let vc2 = ViewController()
        vc2.way = .reverse
        vc2.at = 0
        vcArray.append(vc2)
        self.setViewControllers([vcArray[0]], direction: .reverse, animated: true, completion: nil)
        self.view.backgroundColor = UIColor.white
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let index = vcArray.index(of: viewController), index > 0 else {
            return nil
        }
        
        return vcArray[index - 1]
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
    {
        guard let index = vcArray.index(of: viewController), index < vcArray.count - 1 else {
            return nil
        }
        
        return vcArray[index + 1]
    }
}

Swift4 RxSwiftで2つのTextFieldの入力を監視しボタンを制御する

やること

2つのTextFieldの入力を監視し,文字数が両TextField共に1以上のときにボタンを選択可能にする

コード

import RxSwift
import RxCocoa

// viewDidLoad

let textField1: UITextField!
let textField2: UITextField!
let saveButton: UIButton!
Observable.combineLatest(textField1.rx.text.orEmpty.asObservable(), textField2.rx.text.orEmpty.asObservable()){
                $0.characters.count > 0 && $1.characters.count > 0
            }
            .bind(to: saveButton.rx.isEnabled)
            .disposed(by: disposeBag)

こんな感じでできる

Swift4 PagingMenuControllerでタブを実装する

PagingMenuControllerとは

上部のタブをスワイプで切り替えることが出来るUIライブラリ

f:id:taillook:20171020191014g:plain

インストール

今回はCocoaPodsでインストールします.

# Uncomment the next line to define a global platform for your project
platform :ios, '11.0'

target 'test' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for test
  pod 'PagingMenuController'
end

実装

まず,Storyboard上でViewController(以下vc)を3つ置く.
次に各ViewControllerにclassを設定する.

  • 白背景のvcにViewController
  • 緑背景のvcにViewController1
  • ピンク背景のvcにViewController2

f:id:taillook:20171020191419p:plain

以下コード
ViewController.swift

import UIKit
import PagingMenuController

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let options = PagingMenuOptions()
        let pagingMenuController = PagingMenuController(options: options)
        
        addChildViewController(pagingMenuController)
        view.addSubview(pagingMenuController.view)
        pagingMenuController.didMove(toParentViewController: self)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

private struct PagingMenuOptions: PagingMenuControllerCustomizable {
    let vc1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController1") as! ViewController1
    let vc2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
    
    fileprivate var componentType: ComponentType {
        return .all(menuOptions: MenuOptions(), pagingControllers: pagingControllers)
    }
    
    fileprivate var pagingControllers: [UIViewController] {
        return [vc1, vc2]
    }
    
    fileprivate struct MenuOptions: MenuViewCustomizable {
        var displayMode: MenuDisplayMode {
            return .segmentedControl
        }
        var height: CGFloat {
            return 40
        }
        var backgroundColor: UIColor {
            return UIColor.gray
        }
        var selectedBackgroundColor: UIColor {
            return UIColor.gray
        }
        var focusMode: MenuFocusMode {
            return .underline(height: 4, color: UIColor.darkGray, horizontalPadding: 0, verticalPadding: 0)
        }
        var itemsOptions: [MenuItemViewCustomizable] {
            return [MenuItem1(), MenuItem2()]
        }
    }
    
    fileprivate struct MenuItem1: MenuItemViewCustomizable {
        var displayMode: MenuItemDisplayMode {
            return .text(title: MenuItemText(text: "First", color: UIColor.lightGray, selectedColor: UIColor.white))
        }
    }
    
    fileprivate struct MenuItem2: MenuItemViewCustomizable {
        var displayMode: MenuItemDisplayMode {
            return .text(title: MenuItemText(text: "Second", color: UIColor.lightGray, selectedColor: UIColor.white))
        }
    }
}

PagingMenuOptionsのMenuOptions内でビューのUIをカスタマイズしている.

TableViewのHeaderとFooterのサイズを動的に変更する

環境

  • Swift4
  • Xcode9

概要

Storyboard上でTableViewにHeaderViewを追加し実行するとUILabel等の高さが変わる時にHeaderViewの高さが変わらずにSubViewが途切れてしまった.
UITableViewController().viewWillLayoutSubviews()をオーバーライドしてコードを追加し,これを解決する.

Example

MyTableViewController.swift

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    
    if let headerView = tableView.tableHeaderView {
        let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        
        if height != headerView.frame.size.height {
            tableView.tableHeaderView?.frame.size.height = height
        }
    }
}

ZipCode4sをSwift4に対応&BugFix

今までのZipCode4s

インターネットを介して郵便番号のデータを取って来ていた
これからはローカルに置いてあるので遅延が最小になる

Swiftに強い人がプルリクを送ってくれた

.podspecの

s.source_files      = 'ZipCode4s/*.{h,m,swift,csv}'

s.source_files      = 'ZipCode4s/*.{h,m,swift}'
s.resource          = 'ZipCode4s/*.csv'

にすると動いた
.source_filesにファイルを全て書くものだと思っていた...

github.com

ほしい機能等あればissue投げてください
(スターもほしい)

Swift4のsubstringが非推奨になった話 - 'substring(to:)' is deprecated

Swift4からのコード

"abcdefg".substring(to:"abcdefg".index("abcdefg".endIndex, offsetBy: -5))

こういうコードがSwift4からは

"abcdefg"[..<"abcdefg".index("abcdefg".endIndex, offsetBy: -5)]

になります.

ZipCode4sをSwift4に対応させました

github.com

polSearch アップデート情報 2017/09/16

アップデート内容

  • ブックマーク機能追加
  • 広告もちょっぴし追加(バイトしてなくて貯金もほぼないので助けて…
  • スペシャルサンクスページ追加

スクリーンショット

  • インフォボタンの追加(ここからスペシャルサンクスページへ)
  • タブバーを追加(ブックマーク画面との切り替え)

f:id:taillook:20170916232925p:plain

ブックマークのやりかた

  • +ボタンを押すとブックマークに追加出来ます
  • 削除は+ボタンの位置にゴミ箱ボタンが出るのでそれを押すとブックマークから削除できます

f:id:taillook:20170916233304p:plain

ハードタブとソフトタブについて

ハードタブ・ソフトタブ

インデントの種類としてハードタブとソフトタブがある.

ハードタブ

ハードタブはタブ文字 \tを用いてインデントを表現する.

ハードタブのメリット

エディタの設定で幅を変えられる

ソフトタブ

ソフトタブはスペースを用いてインデントを表現する.
(スペースなのにタブって言ってるの面白い)

ソフトタブのメリット

どの環境で見ても同じ幅になる.

おすすめ

www.taillook.tech

私はハードタブが好き