MILLEN BOX

音楽好きの組み込みソフトエンジニアによるプログラミング(主にiOSアプリ開発)の勉強の記録

swiftでグラデーションがかかったViewを作成する[CAGradientLayer][swift3.0]

今回はグラデーションがかかったViewを作成したいと思います。
現在作成中のアプリで使っていたのですが、ちょっといらないかも...と感じまして、消してしまう前に記録に残しておきます。

githubは以下です。

▶︎GitHub - anthrgrnwrld/gradationView

f:id:anthrgrnwrld:20160923194712p:plain

コードを以下に貼っておきます

class ViewController: UIViewController {

    @IBOutlet weak var gradationView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let gradient = CAGradientLayer()
        gradient.frame = self.view.bounds
        
        let color_1 = UIColor(red: 1.0, green: 0.7, blue: 0.7, alpha: 1.0).cgColor
        let color_2 = UIColor(red: 0.7, green: 1.0, blue: 0.7, alpha: 1.0).cgColor
        let color_3 = UIColor(red: 0.7, green: 0.7, blue: 1.0, alpha: 1.0).cgColor
        gradient.colors = [color_1, color_2, color_3]
        
        let position_1 = NSNumber(value: 0.0 as Float)
        let position_2 = NSNumber(value: 0.5 as Float)
        let position_3 = NSNumber(value: 1.0 as Float)
        
        gradient.startPoint = CGPoint(x: 0.0, y: 0.0)
        gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
        gradient.locations = [position_1, position_2, position_3]
        
        self.gradationView.layer.insertSublayer(gradient, at: 0)

    }

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


}

処理イメージ

これ書いたの結構前で参考にしたページも忘れてしまいましたが、以下のような処理のイメージです。

(前提方針) CAGradientLayerクラスのインスタンスを色々処理した後に対象のViewのLayerへ代入する。

  1. CAGradientLayerのインスタンスを作成し、その大きさを定義する。
  2. グラデーションする色を決定。いくつ作成しても良い。
  3. グラデーションの開始及び終了の位置、2で決定した色を開始する位置などを決定する。1で決定したサイズを1.0として。
  4. 対象Viewの.layerへ作成・編集したCAGradientLayerのインスタンスを入れる。

以上です。

UIImageの角を丸くするExtension [swift2.2] [UIImage] [CGContextClipToMask]

UIImageの角を丸くしたいと思います。
ネットでザクッと検索をかけると、UIImageViewのCALayer -> cornerRadiusをイジイジすることで実現する方法が多かったのですが、UIImage自体で角を丸くする方法はあんまり出てこなかったので。
とは言いながらやはりネットの記事を参考にしました。(Objective-Cでしたが)

d.akiroom.com

今回はこのページを参考に、swift用いて実現したUIImageのExtentionを備忘録として残しておこうと思います。

実現方法

  1. まずUIBezierPath.init(roundedRect rect: CGRect, cornerRadius: CGFloat)を使用して角が丸いRectを作成します。
  2. 手順1で作成した角丸Rectを青で塗りつぶします。ここで青で塗りつぶされていない部分がマスクになります。
  3. CGContextClipToMask(c: CGContext?, _ rect: CGRect, _ mask: CGImage?)で手順2で作成したマスクを適応します。
  4. drawInRectやdrawAtPointなどで元イメージのDrawを実行します。

ソースは以下に貼っておきます

import UIKit

extension UIImage {
    
    func imageWithCornerRadius(cornerRadius: CGFloat) -> UIImage{
        
        var imageBounds: CGRect
        let scaleForDisplay = UIScreen.mainScreen().scale     //1ポイント当たり何ピクセルか
        let cornerRadius = cornerRadius * scaleForDisplay     //ポイントからピクセルへの変換

        imageBounds = CGRectMake(0, 0, self.size.height, self.size.height)
 
        //角丸のマスクを作成する
        let path = UIBezierPath.init(roundedRect: imageBounds, cornerRadius: cornerRadius)
        UIGraphicsBeginImageContextWithOptions(path.bounds.size, false, 0.0)
        let fillColor = UIColor.blueColor()
        fillColor.setFill()
        path.fill()
        let maskImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        //元イメージにマスクをかける
        UIGraphicsBeginImageContextWithOptions(path.bounds.size, false, 0.0)
        let context = UIGraphicsGetCurrentContext()
        CGContextClipToMask(context, imageBounds, maskImage.CGImage)

        self.drawAtPoint(CGPointZero)
        
        let resultImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return resultImage
        
    }
    
}

SwiftでUISliderのデザインをカスタマイズする方法 [UISlider] [swift2.2]

今回はUISliderのデザインをカスタマイズする方法を残しておきます。
 
f:id:anthrgrnwrld:20160818150442g:plain  
Githubは以下です。

GitHub - anthrgrnwrld/customSlider

また今回は、Objective-Cで書かれた以下のページを参考に Storyboard + Swift で作成しました。

lab.dolice.net

ポイント & コード

  • Sliderの画像の指定はUISliderのメソッド setThumbImage, setMinimumTrackImage, setMaximumTrackImageにて行います。
  • 画像の作成の際、Sliderバーの長さを伸ばすため、stretchableImageWithLeftCapWidthというメソッドを使用するのが便利です。

(参考URL)

www.system-i-enter.com

  • コード
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var mySlider: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        setCustomSlider()
    }

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

        //スライダー初期化
        mySlider.minimumValue = 0.0
        mySlider.maximumValue = 1.0
        mySlider.value = 0.5
        
        //スライダーのデザインをカスタマイズ
        let imageForThumb = UIImage(named: "slider_thumb.png")
        let imageMinBase = UIImage(named: "slider_left.png")
        let imageMaxBase = UIImage(named: "slider_right.png")
        let imageForMin = imageMinBase?.stretchableImageWithLeftCapWidth(4, topCapHeight: 0)
        let imageForMax = imageMaxBase?.stretchableImageWithLeftCapWidth(4, topCapHeight: 0)
 
        mySlider.setThumbImage(imageForThumb, forState: .Normal)
        mySlider.setThumbImage(imageForThumb, forState: .Highlighted)
        mySlider.setMinimumTrackImage(imageForMin, forState: .Normal)
        mySlider.setMaximumTrackImage(imageForMax, forState: .Normal)
        
    }


}

UIImageとCGImageの違いでハマったこと [pixel] [point] [swift2.2]

以前、UIImageから一部を切り取る方法について本ブログにて書かせて頂きました。

anthrgrnwrld.hatenablog.com  
ザクッと方法を説明しますと、targetとなるUIImageをCGImageへ変換し、そのCGImageと切り取るrectを指定し、 CGImageCreateWithImageInRect を使用して切り取りを実行しています。

この度、UIImageを切り取りたい事案があり、ここで書いた方法で実行しましたが、想定した切り取り位置でimageが切り取られない現象が発生しました。
何で?と思いデバッグしてみたところ、「ん〜?どうやら指定した座標、長さの1/2で切り取られてるぞ〜?」ということに気づきました。実行環境はiPhone6です。ここでピンときました。
そこでググってみたところ、以下のようになっていることを理解しました。

  • UIImageの長さや位置の指定はpoint単位で行う
  • CGImageの長さや位置の指定はpixel単位で行う
  • retinaディスプレイは1pointで複数pixelとなる(iPhone6の場合には2pixel)

参考ページは以下です。

cheesememo.blog39.fc2.com

 
1point当たり何pixelになるかは実行するiOSバイスによって異なります。
以下のコードで調べることが出来ます。
scaleが1point当たりのpixel数にあたります。

let scale = imageSize.height / viewSize.height

 
よって、

  • UIImageを基準に指定したRectのx,y,width,heightにそれぞれscaleをかけたRectを準備する
  • その算出されたRectを CGImageCreateWithImageInRect の引数に指定する

を行うことで、想定通りに動作されるようになります。

swiftのzip関数で二つの配列の組み合わせを作成する [swift2.2] [Zip2Sequence]

swiftにはzipという関数で、二つの配列を組み合わせた構造体(のようなもの)を作成することが出来ます。

下の例のコードでは、ランダムなInt型の配列array1とString型の配列array2を組み合わせ、zippedArrayという組み合わせを作成したものです。

let array1 = [3,78,5,8,6,7,2]
let array2 = ["s", "w", "i", "f", "t"]

var zippedArray = zip(array1, array2)

全組み合わせをprintしてみましょう。
コードは以下です。

zippedArray.forEach {
    print("\($0.0), \($0.1)")
}

実行結果は以下のようになります。

3, s
78, w
5, i
8, f
6, t

 
上記の実効結果からわかる通り、配列のメンバー数が異なる場合には、少ない方に合わせて多い方がカットされるようです。

 

Swiftでお絵描きアプリを作成する(第4回UIImageのカメラロールへの保存) [Array][swift2.2]

前回に引き続きお絵描きアプリを作成しようと思います。
今回で本シリーズは最終回です。
作成するお絵描きアプリの機能は以下!
 

  • 拡大が可能!(前々々回済み)
  • ペンの色、太さが変更可能!(前々回済み)
  • Redo/Undoが可能!(前回済み)
  • 描いた絵の保存が可能!(今回)

 
前回まででお絵描きアプリとしてはほぼ完成しました。
しかし何かが足りない...?
そうだ!保存機能がない!
...ということで保存機能を追加することにしました。
「UIImageのカメラロールへの保存」はお絵描きアプリだけでなく、他のアプリでも使いたくなる機能ですね。
 
f:id:anthrgrnwrld:20160721080139g:plain

 
Githubは以下です。

▶︎GitHub - anthrgrnwrld/drawWithExpand at 66fafc321ba11a57a8560a4149579dd6d8b25985

過去の本シリーズの記事は以下です。
まだ読んでない、という方は以下の方も見てみて下さい!

anthrgrnwrld.hatenablog.com

anthrgrnwrld.hatenablog.com

anthrgrnwrld.hatenablog.com

続きを読む