Neumorphism: 令和時代のスキューモーフィズム

**※この記事はデザインのトレンドを紹介する体で書かれた技術記事＆ライブラリの宣伝となっています。あらかじめご了承ください。**

## tl;dr;

みなさんは**Neumorphism**という単語をご存知でしょうか？

これは次に流行るとちらほら言われているデザインのトレンドで例えばこんなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/a130a6eb-53dc-8dff-9858-baeef47d444a.png)
*[Neumorphism in user interfaces](https://uxdesign.cc/neumorphism-in-user-interfaces-b47cef3bf3a6)より*

少しスキューモーフィズムのようなリアル感があるのがわかるでしょうか？
これは命名もnew + skeuomorphismから来ているそうで、そこまでリアリティを追求しているわけではないんだけど、フラットやマテリアルよりもっと質感を感じられるようなデザインとなっています。

これはかっこいい。ですが、実装はどうやるのか？気になりますよね。

そこで今回はこのNeumorphismをiOSネイティブで実装するにはどうすればよいのかについて紹介していきます。

## そもそもどうやったらこんな感じになるのん？

実装するためにまずはNeumorphism自体についてもっと理解しなければなりません。
それに関してはこの[Neumorphism (Soft UI) in User interface design -Tutorial](https://uxplanet.org/neumorphism-in-user-interface-tutorial-c353698ac5c0)という記事が参考になります。

この記事自体はSketchやFigma、illustratorでどのようにNeumorphismを実現するのかが解説されているのですが、重要な部分は２点。（以下は上記記事の画像です。）

#### ポイント１：２つの影を使う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/2ebf66c6-1682-ed97-930c-b0dcdb0e864d.png)

まず１つ目に重要なのは影を２つ使うということです。片方がベース色より明るい、もう一方がベース色より暗い色の影を使います。

#### ポイント２：影に使う色はベース色の輝度のみ変えたものを使う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/b1e6e4a6-c929-5692-0630-a5167912196b.png)

厳密には輝度以外が変わっていてもブレンドされていれば大丈夫だとは思いますが、このように並べるとグラデーションになるように色をチョイスすればよいです。


以上を行うとどんな色でもneumorphismと呼ばれるような見た目になってくれます。

## iOSでどうやって実装する？

ではこれをiOSでどのように実装すればいいでしょうか？

大前提としてUIViewは影を一個しかつけられないのでそこを解決しなくてはなりません。

方法としては

0. CALayerをサブレイヤーとして追加していく
1. 影用のViewをつくる

が考えられます。

#### try1: CALayerの罠
影だけであれば１つ目の方法で実装可能です。大体こんな感じ。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/2b8b8e2d-06cf-dee6-69e3-bfd20db6fa02.png" width=50%>

うまくいってるようですが、このときに角丸をつけようとするとうまくいきません。いわゆるmaskedToBoundsのジレンマにはまります。（なぜか一応できている[StackOverflow](https://stackoverflow.com/questions/55285700/multiple-shadows-under-uiview-ios-swift)もあるんですが...）

そこで2のほうの方法を取ることにしました（Viewが増えまくるので苦渋の決断笑）

#### try2: 色をどうするか？

さてShadowの付け方は決まりました。次に重要なのは影の色になります。
毎回デザインソフトなどで色をブレンドして...というのは面倒ですよね。できればベース色を決めたら勝手ににゅってなってほしい。。。

そこでこれはHSLの値を直接いじることにしました。

といっても、SwiftはHSBしか対応していません。そこで変換を用意してあげます。（[参考](http://ariya.blogspot.com/2008/07/converting-between-hsl-and-hsv.html)）

```swift
private func hsbToHsl(h: CGFloat, s: CGFloat, b: CGFloat) -> (h: CGFloat, s: CGFloat, l: CGFloat) {

    let newH = h
    var newL = (2 - s) * b
    var newS = s * b
    newS /= newL <= 1 ? newL : 2 - newL
    newL /= 2
    return (h: newH, s: newS, l: newL)
}

private func hslToHsb(h: CGFloat, s: CGFloat, l: CGFloat) -> (h: CGFloat, s: CGFloat, b: CGFloat) {
    let newH = h
    let ll = l * 2
    let ss = s * (ll <= 1 ? ll : 2 - ll)
    let newB = (ll + ss) / 2
    let newS = (2 * ss) / (ll + ss)
    return (h: newH, s: newS, b: newB)
}
```

これによってHSLでの計算が可能になったので、それをもとにこんなメソッドをUIColorにつけてあげました。

```swift
func lighterColor(value: CGFloat) -> UIColor {
    var h: CGFloat = 0
    var s: CGFloat = 0
    var b: CGFloat = 0
    var a: CGFloat = 0

    guard getHue(&h, saturation: &s, brightness: &b, alpha: &a) else { return self }

    let hsl = hsbToHsl(h: h, s: s, b: b)
    let hsb = hslToHsb(h: hsl.h, s: hsl.s, l: hsl.l + value)

    return UIColor(hue: hsb.h, saturation: hsb.s, brightness: hsb.b, alpha: a)
}
```

このメソッドを使えばvalueに渡した量だけもとの色より輝度が明るい色を作ることができます。

これで下準備は完了です。実際にこのようなextensionをつかってNeumorphismが適用できるようにしました。

```swift
public extension UIView {

    func addNeumorphismShadow(with parent: UIView, dist: CGFloat = 9, blur: CGFloat = 16) {

        guard let backgroundColor = backgroundColor else { return }
        let shadowViews = neumorphismShadowViews(color: backgroundColor, dist: dist, blur: blur)
        shadowViews.forEach {
            parent.insertSubview($0, belowSubview: self)
        }
    }

    func neumorphismShadowViews(color: UIColor, dist: CGFloat, blur: CGFloat) -> [UIView] {

        let lightShadowView: UIView = {
            let lightView = UIView(frame: frame)
            let lightColor = color.lighterColor(value: 0.12)
            lightView.backgroundColor = .white
            lightView.layer.applyShadow(color: lightColor, alpha: 0.5, x: -dist, y: -dist, blur: blur)
            lightView.layer.cornerRadius = layer.cornerRadius
            lightView.layer.maskedCorners = layer.maskedCorners
            return lightView
        }()
        let darkShadowView: UIView = {
            let darkView = UIView(frame: frame)
            let darkColor = color.darkerColor(value: 0.18)
            darkView.backgroundColor = .white
            darkView.layer.applyShadow(color: darkColor, alpha: 0.5, x: dist, y: dist, blur: blur)
            darkView.layer.cornerRadius = layer.cornerRadius
            darkView.layer.maskedCorners = layer.maskedCorners
            return darkView
        }()
        return [lightShadowView, darkShadowView]
    }
}
```

デフォルト値はチュートリアルの推奨値を使っています。

## 応用する

さて、ここまででNeumorphismをどうやって実装するかをざっくりと見てきました（正直力技感がありますが笑）

じゃあこれの使い所はどこか？となったときに最近Pinterestなどが取り入れているフローティングタブバーのNeumorphism版があればいいのでは...？となりました。

なので、実装しちゃいました。デデン！

![neumorphismtab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/2bd60b44-e0dd-5a00-e6bc-fb66782a55a3.png)

**NeumorphismTab**！！！！！

[こちら](https://github.com/touyou/NeumorphismTab)から試すことができます。MITライセンスです。

どんなものかというと普通のTabBarControllerと同じような感覚でNeumorphismなTabBarを使えてしまうという代物です。具体的にはこのように使います。

```swift
import UIKit
import NeumorphismTab

class DemoTabBarController: NeumorphismTabBarController {

    override func setupView() {
        
        let color = UIColor(hex: "C1D2EB")
        let home = NeumorphismTabBarItem(icon: UIImage(systemName: "house.fill")!, title: "Home")
        let favorite = NeumorphismTabBarItem(icon: UIImage(systemName: "heart.fill")!, title: "")

        view.backgroundColor = color

        let homeViewController: ViewController = {
            let viewController = ViewController.instantiate()
            viewController.view.backgroundColor = color
            return viewController
        }()

        let favoriteViewController: UIViewController = {
            let viewController = UIViewController()
            viewController.view.backgroundColor = color
            return viewController
        }()

        setTabBar(items: [home, favorite])
        viewControllers = [homeViewController, favoriteViewController]
    }
}
```

そうするとこのようにそれっぽいタブが使えるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/82191011-fa0f-54f9-97dc-cb1482ae91b5.png)

すべてのViewControllerが同じ背景色である必要があるなど、デザイン的にどうしてもという部分はありますが、かなり簡単に使えると言えるものになったと思います。

これで出すアプリは未定ですが、もしよろしければぜひ使ってみてください！適宜アップデートします。あともしこうしたほうがいいのでは？というのがあればPRも待っています。

Cocoapods/Carthage/SwiftPackageManagerに対応しています。

## まとめ

というわけで今回はNeumorphismの簡単な紹介と、それに伴い作成したライブラリを紹介させていただきました。

それほどモバイルにこのUIが取り入れられていくのかというところはわかりませんが（Viewの数が尋常じゃないし）今後もこんな感じでなういUIを実装していけたらと思います。

では最後にもう一度こちら
![neumorphismtab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/2bd60b44-e0dd-5a00-e6bc-fb66782a55a3.png)
[touyou/NeumorphismTab](https://github.com/touyou/NeumorphismTab)

今回記事に載せなかった実装なども見れるのでぜひ参考にしてみてください。あとスターもお願いします！笑