しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

【iOS】ナビゲーションバーの背景を画像にする

ナビゲーションバーの背景を画像にしてみました。

f:id:llcc:20170818121811p:plain

画像は下のフリー素材を使っています。

青色のざらざらした紙のテクスチャ素材 | Paper-co | 紙のテクスチャー素材を無料でダウンロードできるサイト

バーに背景画像を設定する方法は下の通りです。
titleTextAttributesはタイトルの色を白くする為の設定です。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationController?.navigationBar.setBackgroundImage(UIImage(named: "texture"), for: .default)
        navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
    }
}

起動すると以下のようにバーの背景が代わります。
もし画像サイズが小さい場合は、画像をリピート描画をしてくれます。

f:id:llcc:20170818121817p:plain

下のように、UIImageをUIColorに変換した上でbarTintColorに設定しても同様の結果になります。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        navigationController?.navigationBar.barTintColor = UIColor(patternImage: UIImage(named: "texture")!)
    }
}

アプリ内の全てのナビゲーションバーの背景を変える場合は、以下のようにappearanceを使います。

ちなみにbarTintColorで画像をセットしている時にSafariViewControllerを使うと'NSInternalInconsistencyException', reason: 'Only RGBA or White color spaces are supported in this situation.'というエラーでクラッシュします。
SafariViewController以外でもエラーになるかもしれないので、できるだけsetBackgroundImageを使う方が安全そうです。

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        UINavigationBar.appearance().barTintColor = UIColor(patternImage: UIImage(named: "texture")!)
        
        return true
    }
}

iMovieでAppStore用の動画を作る

iMovieを使ってAppstoreに掲載する動画を作ってみました。

まずはQuickTime Playerの新規ムービー収録でiPhoneの動画を作成します。

f:id:llcc:20170818125401p:plain

作った動画を保存します。

f:id:llcc:20170818125739p:plain

次はその動画をiMovieで編集します。
iMovieを立ち上げて「新規アプリケーションプレビュー」を選びます。

f:id:llcc:20170818124646p:plain

「新規アプリケーションプレビュー」の選択後は以下のような画面になります。

f:id:llcc:20170818125910p:plain

下のエリアに、さっき撮影した動画を保存します。

f:id:llcc:20170818130140p:plain

動画の左右の端をドラッグすると、その尺を削除する事ができます。
不要な部分を削除する時に便利です。

f:id:llcc:20170818130225p:plain

動画は同じものを複数配置できます。

f:id:llcc:20170818130429p:plain

トランジションを動画と動画の間にセットする事で、動画の切り替わりをアニメーションさせる事ができます。

f:id:llcc:20170818130532p:plain

ファイル出力は、右上のボタンのファイルから行います。

f:id:llcc:20170818130803p:plain

Fireworksでゴールドの円を作成する

Fireworks CS3で次のようなボタンを作ってみました。

f:id:llcc:20170813175400p:plain

こちらですが作り方は非常に簡単です。
円を描いてスタイルタブの金色のテクスチャを選択するだけです。

f:id:llcc:20170813175437p:plain

テクスチャの再現

今回はこのデザインを参考に、同じものを自分で1から作ってみようと思います。

まずは画面に白い円を描きます。

f:id:llcc:20170813175628p:plain

次は、下のような線形グラデーションを追加します。

f:id:llcc:20170813175802p:plain

次はフィルターで色相・彩度を選びます。

f:id:llcc:20170813175847p:plain

パラメータは下の通りです。

f:id:llcc:20170813181725p:plain

色がゴールド系になりました。

f:id:llcc:20170813180022p:plain

次はフィルターのカーブを追加します。
こちらはトーンカーブと呼ばれるものの調整ができます。

f:id:llcc:20170813180230p:plain

少し複雑ですが、トーンカーブは次のように設定します。

f:id:llcc:20170813180518p:plain

かなりカラフルな円になりました。

f:id:llcc:20170813180526p:plain

次は明るさ、コントラストのフィルターを追加します。

f:id:llcc:20170813180652p:plain

パラメータは下の通りです。

f:id:llcc:20170813181405p:plain

同時にフィルターの順番を下のように変更します。

f:id:llcc:20170813181001p:plain

少しゴールドに近づいてきました。

f:id:llcc:20170813181024p:plain

グラデーションの方向を、上下反対にします。

f:id:llcc:20170813181314p:plain

次はフィルターの最上部に下のような内側のシャドウを追加します。

f:id:llcc:20170813181601p:plain

角度が60のシャドウも追加します。

f:id:llcc:20170813181711p:plain

かなり金属風になりました。

f:id:llcc:20170813181815p:plain

フィルターのカーブの下にも次のようなシャドウを追加します。

f:id:llcc:20170813182020p:plain

続けてエッジをぼかす処理を値を3にして追加します。

f:id:llcc:20170813182117p:plain

最後に、次のような白線を追加します。

f:id:llcc:20170813182240p:plain

以上でゴールドの円の完成です。

f:id:llcc:20170813182303p:plain

Fireworksで碁石を作る

Fireworksで下のような碁石を作ってみました。

f:id:llcc:20170807222336p:plain

デザインは下の絵文字を参考にしました。
背景はフリーのテクスチャを使っています。

f:id:llcc:20170807222429p:plain

碁石ですが、最初に黒丸を作成します。

f:id:llcc:20170807222543p:plain

次は線形のグラデーションを追加します。

f:id:llcc:20170807222622p:plain

グラデーションを次のような設定にします。
色は左から「#999」「#333」「#333」です。

f:id:llcc:20170807222702p:plain

最後に#333の外枠をつければ完成です。

f:id:llcc:20170807222833p:plain

ドロップシャドウを追加すると少し立体感が出ます。

f:id:llcc:20170807223249p:plain

白石はグラデーションを左から「#fff」「#ddd」「#eee」で、枠線を「#ccc」にします。

f:id:llcc:20170807223421p:plain

Fireworksで金属風なボタンを制作する

こちらの記事を参考にボタンを作ってみました。
ソフトはFireworksのCS3を使いました。

blog.fenrir-inc.com

下のものが制作物になります。

f:id:llcc:20170806172346p:plain

作成過程

まずは矩形を配置します。

f:id:llcc:20170806172515p:plain

次は矩形に円錐グラデーションを適用します。
色は#fffと#666を交互に配置しました。
両端の色は#999です。

f:id:llcc:20170806172601p:plain

f:id:llcc:20170806172618p:plain

続けて矩形にノイズを追加します。

f:id:llcc:20170806172751p:plain

次は放射状のぼかしを追加します。
かなり金属風になってきました。

f:id:llcc:20170806172836p:plain

次は好きな形でマスクとしてグループ化をします。

f:id:llcc:20170806174206p:plain

f:id:llcc:20170806174158p:plain

元記事では「マスクとしてペースト」をしているのですが、うまく行かなかったためマスクとしてグループ化にしました。

f:id:llcc:20170806174407p:plain

最後にドロップシャドウと外側の線(1px,#000)を追加して終了です。

f:id:llcc:20170806174814p:plain

パラメータの調整

追加で、パラメータを変更するとどうなるかを検証してみました。

矩形のサイズ

上で作ったボタンですが、端がぼやけていたのでサイズを「200x200」から「800x800」に変更しました。
修正後画像は下の通りです、端がきれいになりました。

f:id:llcc:20170806180216p:plain

色の変更

色も調整してみました。
「#000と#666」へ変更した結果は下の通りです。
レコード盤のようになりました。

f:id:llcc:20170806180506p:plain

赤系の「#651E25と#9A353F」も試してみました。
見慣れてないせいかもしれませんが、銀の方がきれいだと感じました。

f:id:llcc:20170806180842p:plain

ノイズ

ノイズを10から50にしてみました。
ざらつきが強くなって、金属っぽさがなくなってきました。

f:id:llcc:20170806181058p:plain

ぼかし

画質を100から10にしてみました。
表面がかなりザラザラになりました。

f:id:llcc:20170806181210p:plain

適用量を30→70にすると下のようになります。
全体の色が混ざって、光沢がなくなりました。

f:id:llcc:20170806181636p:plain

逆に適用量を30から10にすると、色の変化がきつくてあまりきれいに見えませんでした。

f:id:llcc:20170806181746p:plain

【Swift】SKLightNodeで画面を明るく照らしてみる

ゲームフレームワークであるSpriteKitのSKLightNodeを使って、画面にライトを追加してみました。

まずは新規プロジェクト作成からゲームを選択します。

f:id:llcc:20170806233459p:plain

プロジェクトを作成したら、GameViewController.swiftを以下のようにします。
サンプルコードを削除して、画面に何も表示されないようにしました。

import UIKit
import SpriteKit
import GameplayKit

class GameViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let view = self.view as! SKView? {
            let scene = GameScene(size: view.bounds.size)
            scene.scaleMode = .aspectFill
            view.presentScene(scene)
            
            view.ignoresSiblingOrder = true
            
            view.showsFPS = true
            view.showsNodeCount = true
        }
    }
    
    override var prefersStatusBarHidden: Bool {
        return true
    }
}

続けてGameScene.swiftを以下のように修正します。

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
    }
}

アプリを立ち上げると、下のように真っ白な表示になるかと思います。

f:id:llcc:20170806233733p:plain

続けて画面にSKLightNodeを追加します。

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
        
        let light = SKLightNode()
        light.position = view.center
        light.categoryBitMask = 1
        addChild(light)
        baseNode.lightingBitMask = 1
    }
}

起動すると、中心が光に照らされています。

f:id:llcc:20170806234301p:plain

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
        
        let light = SKLightNode()
        light.position = view.center
        light.categoryBitMask = 1
        addChild(light)
        baseNode.lightingBitMask = 1
    }
}

ライトのfalloffプロパティーを変更すると、光の届く距離が代わります。
試しにデフォルトの1から0.1に変更したら、より遠くまで光が届くようになりました。

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
        
        let light = SKLightNode()
        light.position = view.center
        light.categoryBitMask = 1
        light.falloff = 0.1 // ここを修正
        addChild(light)
        baseNode.lightingBitMask = 1
    }
}

f:id:llcc:20170806234509p:plain

ライトの色はlightColorというプロパティーで変更できます。
ライトがない箇所の色はambientColorというプロパティーで変更します。

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
        
        let light = SKLightNode()
        light.position = view.center
        light.categoryBitMask = 1
        light.lightColor = .blue
        light.ambientColor = .red
        addChild(light)
        baseNode.lightingBitMask = 1
    }
}

lightColorを青、ambientColorを赤にしたら以下のようになりました。

f:id:llcc:20170806234855p:plain

shadowCastBitMaskを使うと光を遮る事ができます。

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
        
        let light = SKLightNode()
        light.position = view.center
        light.categoryBitMask = 1
        addChild(light)
        baseNode.lightingBitMask = 1
        
        let node = SKSpriteNode(color: .darkGray, size: CGSize(width: 100, height: 100))
        node.position = CGPoint(x: view.frame.width / 2, y: view.frame.height / 2 - 100)
        node.shadowCastBitMask = 1
        addChild(node)
    }
}

f:id:llcc:20170806235615p:plain

この時の影の色はSKLightNodeshadowColorというプロパティーで変更できます。

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    private var label : SKLabelNode?
    private var spinnyNode : SKShapeNode?
    
    override func didMove(to view: SKView) {
        let baseNode = SKSpriteNode(color: .white, size: view.frame.size)
        baseNode.position = view.center
        baseNode.zPosition = -1
        addChild(baseNode)
        
        let light = SKLightNode()
        light.position = view.center
        light.categoryBitMask = 1
        light.shadowColor = .green
        addChild(light)
        baseNode.lightingBitMask = 1
        
        let node = SKSpriteNode(color: .darkGray, size: CGSize(width: 100, height: 100))
        node.position = CGPoint(x: view.frame.width / 2, y: view.frame.height / 2 - 100)
        node.shadowCastBitMask = 1
        addChild(node)
    }
}

f:id:llcc:20170806235709p:plain

【SpriteKit】SKSpriteNodeの背景に繰り返し画像を使う

SpriteKitで繰り返し画像を背景に使う方法です。

f:id:llcc:20170804002213p:plain

元の画像素材は下のようなものです。
今回はこれを画面全体に繰り返し配置しました。

f:id:llcc:20170804002648p:plain

実際のコードは下の通りです。
まずはCoreGraphicsを使って、画面と同じサイズの繰り返し画像を生成。それをSKSpriteNodeの背景画像に設定しました。

UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
if let image = UIImage(named: "test"), let cgImage = image.cgImage {
    context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), byTiling: true)
    
    if let image = UIGraphicsGetImageFromCurrentImageContext() {
        let texture = SKTexture(image: image)
        let tatami = SKSpriteNode(texture: texture)
        addChild(tatami)
    }
}
UIGraphicsEndImageContext()

CoreGraphics部分について少し補足します。

下のコードでは、繰り返し画像を生成しています。 CGContextのdrawメソッドのbyTilingをtrueにすることで、繰り返し画像を生成しています。

UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
if let image = UIImage(named: "test"), let cgImage = image.cgImage {
    context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), byTiling: true)
    if let image = UIGraphicsGetImageFromCurrentImageContext() {
        // ...省略
    }
}
UIGraphicsEndImageContext()

drawメソッドのbyTilingをfalseにすると、下のように繰り返しなしの画像になります。

f:id:llcc:20170804003624p:plain

CoreGraphicsを使わない方法も検討したのですが、こちらはあまりうまくいきませんでした。
SKSpriteNodeの初期化時に画像名を渡したのですが、これは繰り返しなしの画像が表示されました。

let tatami = SKSpriteNode(imageNamed: "tatami")
addChild(tatami)

f:id:llcc:20170804003924p:plain

SKSpriteNodeのサイズを画面いっぱいにする方法も試したのですが、中の画像が引き伸ばされるだけでした。

let tatami = SKSpriteNode(imageNamed: "tatami")
tatami.size = self.size
addChild(tatami)

f:id:llcc:20170804004101p:plain

UIImageをUIColorに変換する方法も試したのですが、これだと画面に何も表示されませんでした。

SKSpriteNode(color: UIColor(patternImage: UIImage(named: "test")!), size: size)

良い方法見つかるまでは、CoreGraphicsを使っていこうと思います。