カスタムキーボードを作っていると、iOSシステムキーボードのようなオフィシャルなキーアイコンを描画したくなります。
しかし、drawRect()内で一から描くのは大変だし、かといってドローイングソフトで描いてUIImageをセットしていては、extensionアプリではメモリ的にきついし、アイコンの数が多くなるほどコードも複雑化していきます。
保守性やキーサイズへの応変、手軽に色をカスタマイズできるといった利便性などを考慮してもやはりdrawRectで描くに限ることを痛感しました。
ありがたいことに、GitHubにtasty-imitation-keyboardというアイコンをUIBezierPathで描いたものがあったわけですが、アイコンのクオリティ的にアレだったので僕が見よう見まねでシステムキーボードにさらに近づけたのをここにアップしておきます。
プロジェクトに組み込む準備
まずGitHubからtasty-imitation-keyboardをダウンロードし、「Shapes.swift」ファイルのみをプロジェクトへ追加。
Shapesクラスの
・getFactors(fromSize: CGSize, toRect: CGRect)
・centerShape(fromSize: CGSize, toRect: CGRect)
・endCenter()
の3つのメソッドを利用します。
描画の流れとしては
1. スケーリングに必要なFactorなどを定義
2. centerShape()でアイコンを中央に配置する
3. 各アイコンを描く
4. endCenter()で終了
これらを各UIButtonクラスのdrawRect()メソッドにオーバーライドします。
ここでご紹介するアイコンは主にiPadの分割キーボードを基準にしています。
また、自分のプロジェクトのコードを記事用に修正したものを貼っただけのもので、下記のコードのままの動作確認は行っていません。
載せているアイコンはデリート、グローブ、シフト、キーボードを閉じるの4種類です。
デリートアイコンを描く
左がシステムキーボードのアイコンで、
右が真似て描いたアイコンです。
Buttonのサイズに合わせてbaseIconSizeやscaleRateなどを適宜調節する必要があります。
override func drawRect(rect: CGRect) { let baseIconSize = CGSizeMake(37, 32) // アイコンのベースとなるサイズ let factors = getFactors(baseIconSize, toRect: bounds) let scaleRate: CGFloat = 1.6 // Buttonのサイズに合わせてスケールさせる let xScalingFactor = factors.xScalingFactor * scaleRate // x軸のスケール let yScalingFactor = factors.yScalingFactor * scaleRate // y軸のスケール let lineWidthScalingFactor = factors.lineWidthScalingFactor * 2.0 // lineWidthにそのまま放り込む // アイコンをButtonの中心に描画させる centerShape(CGSizeMake(baseIconSize.width * xScalingFactor, baseIconSize.height * yScalingFactor), toRect: bounds) // 別メソッドでアイコンの外枠とばつ印を描く drawBackwardIconFrame(xScalingFactor, yScalingFactor: yScalingFactor, lineWidthScalingFactor: lineWidthScalingFactor) drawBackwardCross(xScalingFactor, yScalingFactor: yScalingFactor, lineWidthScalingFactor: lineWidthScalingFactor) } // 外枠の描画 func drawBackwardIconFrame(xScalingFactor: CGFloat, yScalingFactor: CGFloat, lineWidthScalingFactor: CGFloat) { let sharpX: CGFloat = 0 // 先端のx let sharpY: CGFloat = 16 // 先端のy let mostRightX: CGFloat = 36 // アイコン右マージン let mostLeftX: CGFloat = 13 // アイコン左マージン let mostBottomY: CGFloat = 29.5 // アイコンボトムマージン let mostTopY: CGFloat = 2.5 // アイコントップマージン let rightCurveEndPointY: CGFloat = 5 // 右側カーブの(先端から見た)終着点 let rightCurveBeforePointX: CGFloat = mostRightX - 6 // 右側カーブの(先端から見た)手前の点 //// デリートキーの枠 let frameBezierPath = UIBezierPath() frameBezierPath.moveToPoint(CGPointMake((mostLeftX + 3) * xScalingFactor, mostBottomY * yScalingFactor)) // 左下の角 frameBezierPath.addLineToPoint(CGPointMake(rightCurveBeforePointX * xScalingFactor, mostBottomY * yScalingFactor)) // 右下カーブ手前 frameBezierPath.addCurveToPoint(CGPointMake(mostRightX * xScalingFactor, (mostBottomY - rightCurveEndPointY) * yScalingFactor), controlPoint1: CGPointMake(rightCurveBeforePointX * xScalingFactor, mostBottomY * yScalingFactor), controlPoint2: CGPointMake(mostRightX * xScalingFactor, mostBottomY * yScalingFactor)) // 右下カーブ後の点へ向かって曲線 frameBezierPath.addLineToPoint(CGPointMake(mostRightX * xScalingFactor, (mostTopY + rightCurveEndPointY) * yScalingFactor)) // 右の縦線 frameBezierPath.addCurveToPoint(CGPointMake(rightCurveBeforePointX * xScalingFactor, mostTopY * yScalingFactor), controlPoint1: CGPointMake(mostRightX * xScalingFactor, (mostTopY + rightCurveEndPointY) * yScalingFactor), controlPoint2: CGPointMake(mostRightX * xScalingFactor, mostTopY * yScalingFactor)) // 右上カーブ後の点へ向かって曲線 frameBezierPath.addLineToPoint(CGPointMake((mostLeftX + 3) * xScalingFactor, mostTopY * yScalingFactor)) // トップの横線 // とんがりへ向かう手前のカーブ frameBezierPath.addCurveToPoint(CGPointMake((mostLeftX - 2) * xScalingFactor, (mostTopY + 2) * yScalingFactor), controlPoint1: CGPointMake((mostLeftX + 3) * xScalingFactor, mostTopY * yScalingFactor), controlPoint2: CGPointMake(mostLeftX * xScalingFactor, mostTopY * yScalingFactor)) frameBezierPath.addLineToPoint(CGPointMake(sharpX * xScalingFactor, (sharpY - 0.5) * yScalingFactor)) // 左端のとんがり上 frameBezierPath.addLineToPoint(CGPointMake(sharpX * xScalingFactor, (sharpY + 0.5) * yScalingFactor)) // 左端のとんがり下 frameBezierPath.addLineToPoint(CGPointMake((mostLeftX - 2) * xScalingFactor, (mostBottomY - 2) * yScalingFactor)) // 左下のカーブの手前までの直線 frameBezierPath.addCurveToPoint(CGPointMake((mostLeftX + 3) * xScalingFactor, mostBottomY * yScalingFactor), controlPoint1: CGPointMake((mostLeftX - 2) * xScalingFactor, (mostBottomY - 2) * yScalingFactor), controlPoint2: CGPointMake(mostLeftX * xScalingFactor, mostBottomY * yScalingFactor)) // 左下のカーブ frameBezierPath.closePath() standardKeyTextColor().setStroke() frameBezierPath.lineWidth = 1.4 * lineWidthScalingFactor frameBezierPath.stroke() } // ばつ印の描画 func drawBackwardCross(xScalingFactor: CGFloat, yScalingFactor: CGFloat, lineWidthScalingFactor: CGFloat) { let leftX: CGFloat = 17 let rightX: CGFloat = leftX + 10 let topY: CGFloat = 11 let bottomY: CGFloat = topY + 10 //// 右肩下がりのバツ線 let downFromLeftToRightBezierPath = UIBezierPath() downFromLeftToRightBezierPath.moveToPoint(CGPointMake(leftX * xScalingFactor, topY * yScalingFactor)) downFromLeftToRightBezierPath.addLineToPoint(CGPointMake(rightX * xScalingFactor, bottomY * yScalingFactor)) downFromLeftToRightBezierPath.lineCapStyle = CGLineCap.Round standardKeyTextColor().setStroke() downFromLeftToRightBezierPath.lineWidth = 1.5 * lineWidthScalingFactor downFromLeftToRightBezierPath.stroke() //// 右肩上がりのバツ線 let upFromLeftToRightBezierPath = UIBezierPath() upFromLeftToRightBezierPath.moveToPoint(CGPointMake(leftX * xScalingFactor, bottomY * yScalingFactor)) upFromLeftToRightBezierPath.addLineToPoint(CGPointMake(rightX * xScalingFactor, topY * yScalingFactor)) upFromLeftToRightBezierPath.lineCapStyle = CGLineCap.Round standardKeyTextColor().setStroke() upFromLeftToRightBezierPath.lineWidth = 1.5 * lineWidthScalingFactor upFromLeftToRightBezierPath.stroke() }
グローブアイコンを描画する
// x,yFactorをかけたCGPointを渡す。 private func scaledPoint(x: CGFloat, y: CGFloat) -> CGPoint { return CGPointMake(x * xScalingFactor, y * yScalingFactor) } // xScalingFactorをかけた値を渡す。 private func xScaledValue(value: CGFloat) -> CGFloat { return value * xScalingFactor } // yScalingFactorをかけた値を渡す。 private func yScaledValue(value: CGFloat) -> CGFloat { return value * yScalingFactor } let globeSizeH: CGFloat = 58 let globeSizeW: CGFloat = 56 let globeCenterY: CGFloat = 58 / 2.0 let globeCenterX: CGFloat = 56 / 2.0 var xScalingFactor = CGFloat() var yScalingFactor = CGFloat() var lineWidthScalingFactor = CGFloat() override func drawRect(rect: CGRect) { let scaleRate: CGFloat = 1.0 let factors = getFactors(CGSizeMake(globeSizeH, globeSizeW), toRect: bounds) xScalingFactor = factors.xScalingFactor * scaleRate yScalingFactor = factors.yScalingFactor * scaleRate lineWidthScalingFactor = factors.lineWidthScalingFactor * 1.4 centerShape(CGSizeMake(xScaledValue(globeSizeW), yScaledValue(globeSizeH)), toRect: bounds) drawGlobeIcon() // 地球儀アイコンを描く endCenter() } // 地球儀アイコンを描く。2016/03/10 func drawGlobeIcon() { let color = UIColor.blackColor() //// 円の描画 let ovalPath = UIBezierPath(ovalInRect: CGRectMake(xScaledValue(0), yScaledValue(0), xScaledValue(globeSizeW), yScaledValue(globeSizeH))) color.setStroke() ovalPath.lineWidth = lineWidthScalingFactor ovalPath.stroke() //// 中央の縦線 let centralVerticalPath = UIBezierPath() centralVerticalPath.moveToPoint(scaledPoint(globeCenterX, y: 0)) centralVerticalPath.addLineToPoint(scaledPoint(globeCenterX, y: globeSizeH)) color.setStroke() centralVerticalPath.lineWidth = lineWidthScalingFactor * 1.2 centralVerticalPath.stroke() //// 中央の横線 let centralHolizontalPath = UIBezierPath() centralHolizontalPath.moveToPoint(scaledPoint(0.5, y: globeCenterY)) centralHolizontalPath.addLineToPoint(scaledPoint(globeSizeW - 0.5, y: globeCenterY)) color.setStroke() centralHolizontalPath.lineWidth = lineWidthScalingFactor * 1.2 centralHolizontalPath.stroke() //// 右側のたて曲線 let rightVerticalCurvePath = UIBezierPath() let xPointR = (globeCenterX + 1.0) let yPoint: CGFloat = 0.42 let rightSideHalfPoint = globeCenterX + globeCenterX / 2 // 上の頂点から下へ向かって描く rightVerticalCurvePath.moveToPoint(scaledPoint(xPointR, y: 0)) rightVerticalCurvePath.addCurveToPoint( // 上半分のカーブ scaledPoint(rightSideHalfPoint, y: globeCenterY + 2), controlPoint1: scaledPoint(xPointR, y: yPoint), controlPoint2: scaledPoint(rightSideHalfPoint, y: yPoint)) rightVerticalCurvePath.addCurveToPoint( // 下半分のカーブ scaledPoint(xPointR, y: globeSizeH - yPoint), controlPoint1: scaledPoint(rightSideHalfPoint, y: globeCenterY - 2), controlPoint2: scaledPoint(rightSideHalfPoint, y: globeSizeH)) rightVerticalCurvePath.lineCapStyle = .Round; color.setStroke() rightVerticalCurvePath.lineWidth = lineWidthScalingFactor rightVerticalCurvePath.stroke() //// 左側のたて曲線 let leftVerticalCurvePath = UIBezierPath() let xPointL = (globeCenterX - 1.0) let leftSideHalfPoint = globeCenterX / 2 // 上の頂点から下へ向かって描く leftVerticalCurvePath.moveToPoint(scaledPoint(xPointL, y: 0)) leftVerticalCurvePath.addCurveToPoint( // 上半分のカーブ scaledPoint(leftSideHalfPoint, y: globeCenterY + 2), controlPoint1: scaledPoint(xPointL, y: yPoint), controlPoint2: scaledPoint(leftSideHalfPoint, y: yPoint)) leftVerticalCurvePath.addCurveToPoint( // 下半分のカーブ scaledPoint(xPointL, y: globeSizeH - yPoint), controlPoint1: scaledPoint(leftSideHalfPoint, y: globeCenterY - 2), controlPoint2: scaledPoint(leftSideHalfPoint, y: globeSizeH)) leftVerticalCurvePath.lineCapStyle = .Round; color.setStroke() leftVerticalCurvePath.lineWidth = lineWidthScalingFactor leftVerticalCurvePath.stroke() //// 上側のよこ曲線 let basePointX: CGFloat = 8 let basePointY: CGFloat = 10 let topHorizontalCurvePath = UIBezierPath() topHorizontalCurvePath.moveToPoint(scaledPoint(basePointX, y: basePointY)) topHorizontalCurvePath.addCurveToPoint( scaledPoint(globeSizeW - basePointX, y: basePointY), controlPoint1: scaledPoint(basePointX, y: basePointY), controlPoint2: scaledPoint(globeCenterX - 1, y: globeCenterY + 1)) topHorizontalCurvePath.lineCapStyle = .Round color.setStroke() topHorizontalCurvePath.lineWidth = lineWidthScalingFactor topHorizontalCurvePath.stroke() //// 下側のよこ曲線 let bottomBaseY: CGFloat = globeSizeH - basePointY let bottomHorizontalCurvePath = UIBezierPath() bottomHorizontalCurvePath.moveToPoint(scaledPoint(basePointX, y: bottomBaseY)) bottomHorizontalCurvePath.addCurveToPoint( scaledPoint(globeSizeW - basePointX, y: bottomBaseY), controlPoint1: scaledPoint(basePointX, y: bottomBaseY), controlPoint2: scaledPoint(globeCenterX - 1, y: globeCenterY + 1)) bottomHorizontalCurvePath.lineCapStyle = .Round color.setStroke() bottomHorizontalCurvePath.lineWidth = lineWidthScalingFactor bottomHorizontalCurvePath.stroke() }
シフトアイコンを描く
上から通常アイコン、ハイライトアイコン、Capsアイコンです。
// MARK: アイコン描画 var xScalingFactor: CGFloat = 0 var yScalingFactor: CGFloat = 0 var lineWidthScalingFactor: CGFloat = 0 func initFactorsGetCenterShapeSize(bounds: CGRect) -> CGSize { var iconHeight = maxY if isCapsState() { iconHeight = capsMaxY } let factors = getFactors(CGSizeMake(maxX, iconHeight), toRect: bounds) let scaleRate: CGFloat = 1.0 xScalingFactor = factors.xScalingFactor * scaleRate yScalingFactor = factors.yScalingFactor * scaleRate lineWidthScalingFactor = factors.lineWidthScalingFactor return CGSizeMake(maxX * xScalingFactor, iconHeight * yScalingFactor) } // x,yFactorをかけたCGPointを渡す。 private func scaledPoint(x: CGFloat, y: CGFloat) -> CGPoint { return CGPointMake(x * xScalingFactor, y * yScalingFactor) } override func drawRect(rect: CGRect) { centerShape(initFactorsGetCenterShapeSize(bounds), toRect: bounds) let color = getTitleColor() if ハイライト or Caps { model.drawHighlightedArrow(color: color) }else { // 通常モード model.drawNormalArrow(color: color) } endCenter() } func drawNormalArrow(color clr: UIColor) { //// Bezier Drawing let bezierPath = UIBezierPath() bezierPath.moveToPoint(scaledPoint(bodyRightX, y: middleY)) // 矢印の右内側かど let beforeRightSharpPoint = scaledPoint(maxX - 3, y: middleY) bezierPath.addLineToPoint(beforeRightSharpPoint) // 矢印の右端角の手前 // 矢印の右端かどのCurve bezierPath.addCurveToPoint(scaledPoint(maxX - 2, y: middleY - 3), controlPoint1: beforeRightSharpPoint, controlPoint2: scaledPoint(maxX, y: middleY)) bezierPath.addLineToPoint(scaledPoint(maxX / 2, y: 0)) // 頂点 let beforeLeftSharpPoint = scaledPoint(2, y: middleY - 3) bezierPath.addLineToPoint(beforeLeftSharpPoint) // 矢印の左端角の手前 // 矢印の左端かどのCurve bezierPath.addCurveToPoint(scaledPoint(4, y: middleY), controlPoint1: beforeLeftSharpPoint, controlPoint2: scaledPoint(0, y: middleY)) bezierPath.addLineToPoint(scaledPoint(bodyLeftX, y: middleY)) // 矢印の左内側かど bezierPath.addLineToPoint(scaledPoint(bodyLeftX, y: maxY - 3)) // ボディ左Curveの手前 // ボディ左Curve bezierPath.addCurveToPoint(scaledPoint(bodyLeftX + 3, y: maxY), controlPoint1: scaledPoint(bodyLeftX, y: maxY - 3), controlPoint2: scaledPoint(bodyLeftX, y: maxY)) bezierPath.addLineToPoint(scaledPoint(bodyRightX - 3, y: maxY)) // ボディの底辺 // ボディ右Curve bezierPath.addCurveToPoint(scaledPoint(bodyRightX, y: maxY - 3), controlPoint1: scaledPoint(bodyRightX - 3, y: maxY), controlPoint2: scaledPoint(bodyRightX, y: maxY)) bezierPath.addLineToPoint(scaledPoint(bodyRightX, y: middleY)) // ボディの右たて線 bezierPath.closePath() bezierPath.lineWidth = lineWidthScalingFactor * 2.5 clr.setStroke() bezierPath.stroke() } func drawHighlightedArrow(color clr: UIColor) { //// Bezier Drawing let bezierPath = UIBezierPath() bezierPath.moveToPoint(scaledPoint(bodyRightX, y: middleY)) // 矢印の右内側かど let beforeRightSharpPoint = scaledPoint(maxX - 3, y: middleY) bezierPath.addLineToPoint(beforeRightSharpPoint) // 矢印の右端角の手前 // 矢印の右端かどのCurve bezierPath.addCurveToPoint(scaledPoint(maxX - 2, y: middleY - 3), controlPoint1: beforeRightSharpPoint, controlPoint2: scaledPoint(maxX, y: middleY)) bezierPath.addLineToPoint(scaledPoint(maxX / 2, y: 0)) // 頂点 let beforeLeftSharpPoint = scaledPoint(2, y: middleY - 3) bezierPath.addLineToPoint(beforeLeftSharpPoint) // 矢印の左端角の手前 // 矢印の左端かどのCurve bezierPath.addCurveToPoint(scaledPoint(4, y: middleY), controlPoint1: beforeLeftSharpPoint, controlPoint2: scaledPoint(0, y: middleY)) bezierPath.addLineToPoint(scaledPoint(bodyLeftX, y: middleY)) // 矢印の左内側かど bezierPath.addLineToPoint(scaledPoint(bodyLeftX, y: maxY - 3)) // ボディ左Curveの手前 // ボディ左Curve bezierPath.addCurveToPoint(scaledPoint(bodyLeftX + 3, y: maxY), controlPoint1: scaledPoint(bodyLeftX, y: maxY - 3), controlPoint2: scaledPoint(bodyLeftX, y: maxY)) bezierPath.addLineToPoint(scaledPoint(bodyRightX - 3, y: maxY)) // ボディの底辺 // ボディ右Curve bezierPath.addCurveToPoint(scaledPoint(bodyRightX, y: maxY - 3), controlPoint1: scaledPoint(bodyRightX - 3, y: maxY), controlPoint2: scaledPoint(bodyRightX, y: maxY)) bezierPath.addLineToPoint(scaledPoint(bodyRightX, y: middleY)) // ボディの右たて線 bezierPath.closePath() clr.setFill() bezierPath.fill() if isCapsState() { // Capsのみ長方形も描く let rectanglePath = UIBezierPath(roundedRect: CGRectMake(10 * xScalingFactor, (capsMaxY - 2) * yScalingFactor, 18 * xScalingFactor, capsRectangleHeight * yScalingFactor), cornerRadius: capsRectangleHeight / 2) clr.setFill() rectanglePath.fill() } }
キーボードを閉じるアイコンを描く
最後はキーボードを閉じるときに使うキーボードアイコンですが、
僕が描いたものはiOS8のアイコンを真似たものなのでiOS9のそれとは異なることをご了承ください。
var xScalingFactor = CGFloat() var yScalingFactor = CGFloat() override func drawRect(rect: CGRect) { let baseIconSize = CGSizeMake(44, 34) let factors = getFactors(baseIconSize, toRect: bounds) var scaleRate: CGFloat = 1.6 xScalingFactor = factors.xScalingFactor * scaleRate yScalingFactor = factors.yScalingFactor * scaleRate let lineWidthScalingFactor = factors.lineWidthScalingFactor * 1.5 centerShape(CGSizeMake(baseIconSize.width * xScalingFactor, baseIconSize.height * yScalingFactor), toRect: bounds) // キーボードアイコンの枠を描画。 drawKeyboardFrame(lineWidthScalingFactor, color: getTitleColor()) // キーボードアイコンのキーを描画。 drawKeys(lineWidthScalingFactor, color: getTitleColor()) // キーボード下の矢印を描画。 drawDownArrow(lineWidthScalingFactor, color: getTitleColor()) endCenter() } // 描画に必要な定数 let mostLeftX: CGFloat = 0 let mostRightX: CGFloat = 44 let mostTopY: CGFloat = 2 let frameBottomY: CGFloat = 20 //キーボードの枠のボトム // キーボードアイコンの枠を描く。 func drawKeyboardFrame(lineWidthScalingFactor: CGFloat, color: UIColor) { let frameBezierPath = UIBezierPath() frameBezierPath.moveToPoint(scaledPoint(mostLeftX, y: mostTopY + 1)) // 左の縦線 frameBezierPath.addLineToPoint(scaledPoint(mostLeftX, y: frameBottomY - 1)) // 左下のカーブ frameBezierPath.addCurveToPoint(scaledPoint(mostLeftX + 1, y: frameBottomY), controlPoint1: scaledPoint(mostLeftX, y: frameBottomY), controlPoint2: scaledPoint(mostLeftX, y: frameBottomY - 1)) // 下の横線 frameBezierPath.addLineToPoint(scaledPoint(mostRightX, y: frameBottomY)) // 右下のカーブ frameBezierPath.addCurveToPoint(scaledPoint(mostRightX, y: frameBottomY - 1), controlPoint1: scaledPoint(mostRightX, y: frameBottomY), controlPoint2: scaledPoint(mostRightX - 1, y: frameBottomY)) // 右の縦線 frameBezierPath.addLineToPoint(scaledPoint(mostRightX, y: mostTopY)) // 右上のカーブ frameBezierPath.addCurveToPoint(scaledPoint(mostRightX - 1, y: mostTopY), controlPoint1: scaledPoint(mostRightX, y: mostTopY), controlPoint2: scaledPoint(mostRightX, y: mostTopY + 1)) // 上の横線 frameBezierPath.addLineToPoint(scaledPoint(mostLeftX, y: mostTopY)) // 左上のカーブ frameBezierPath.addCurveToPoint(scaledPoint(mostLeftX, y: mostTopY + 1), controlPoint1: scaledPoint(mostLeftX, y: mostTopY), controlPoint2: scaledPoint(mostLeftX + 1, y: mostTopY)) frameBezierPath.lineCapStyle = CGLineCap.Round color.setStroke() frameBezierPath.lineWidth = lineWidthScalingFactor frameBezierPath.stroke() } let keyWidthPlusMargin: CGFloat = 4.5 let keySize: CGFloat = 2.5 // キーボードアイコンのキーを描く。 func drawKeys(lineWidthScalingFactor: CGFloat, color: UIColor) { let spaceKeyWidth: CGFloat = getSpaceKeyWidth(keySize: keySize) let keyTopMargin: CGFloat = 2.5 for row in 0..<2 {// 1,2段目のキー for column in 0..<9 { let topMargin = (mostTopY + keyTopMargin + (keySize + keyTopMargin) * CGFloat(row)) let squareBezierPath = UIBezierPath(roundedRect: scaledRect(getKeyLeftMargin(index: column), y: topMargin, width: keySize, height: keySize), cornerRadius: 0) color.setFill() squareBezierPath.fill() } } for idx in 0..<9 { let topMargin = (mostTopY + keyTopMargin + (keySize + keyTopMargin) * 2) if !(2 <= idx && idx <= 6) { // 3段目のキー let squareBezierPath = UIBezierPath(roundedRect: scaledRect(getKeyLeftMargin(index: idx), y: topMargin, width: keySize, height: keySize), cornerRadius: 0) color.setFill() squareBezierPath.fill() }else if idx == 2 { // 3段目のスペースキー let rectangleBezierPath = UIBezierPath(roundedRect: scaledRect(getKeyLeftMargin(index: idx), y: topMargin, width: spaceKeyWidth, height: keySize), cornerRadius: 0) color.setFill() rectangleBezierPath.fill() } } } // キーボード下の下矢印を描く。 func drawDownArrow(lineWidthScalingFactor: CGFloat, color: UIColor) { let spaceKeyWidth: CGFloat = getSpaceKeyWidth(keySize: keySize) let spaceKeyLeft = getKeyLeftMargin(index: 2) let arrowTopY = frameBottomY + 7 let mostBottomY: CGFloat = arrowTopY + 6 // 矢印の左側 let arrowLeftBezierPath = UIBezierPath() arrowLeftBezierPath.moveToPoint(scaledPoint(spaceKeyLeft, y: arrowTopY)) arrowLeftBezierPath.addLineToPoint(scaledPoint(spaceKeyLeft + spaceKeyWidth / 2, y: mostBottomY)) arrowLeftBezierPath.lineCapStyle = CGLineCap.Round color.setStroke() arrowLeftBezierPath.lineWidth = lineWidthScalingFactor arrowLeftBezierPath.stroke() // 矢印の右側 let spaceKeyRight = spaceKeyLeft + spaceKeyWidth let arrowRightBezierPath = UIBezierPath() arrowRightBezierPath.moveToPoint(scaledPoint(spaceKeyRight, y: arrowTopY)) arrowRightBezierPath.addLineToPoint(scaledPoint(spaceKeyLeft + spaceKeyWidth / 2, y: mostBottomY)) arrowRightBezierPath.lineCapStyle = CGLineCap.Round color.setStroke() arrowRightBezierPath.lineWidth = lineWidthScalingFactor arrowRightBezierPath.stroke() } // キーボードアイコンのスペースキーの幅を返す。 private func getSpaceKeyWidth(keySize size: CGFloat) -> CGFloat { let keyCount: CGFloat = 5 let keyMargin = keyWidthPlusMargin - size return (size * keyCount) + (keyMargin * 4) } // 各キーの左マージンを計算して返す。 private func getKeyLeftMargin(index idx: Int) -> CGFloat { return mostLeftX + 2.5 + (CGFloat(idx) * 4.5) } // スケール処理をしたCGPointを返す。 private func scaledPoint(x: CGFloat, y: CGFloat) -> CGPoint { return CGPointMake(x * xScalingFactor, y * yScalingFactor) } // スケール処理をしたCGRectを返す。 private func scaledRect(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) -> CGRect { return CGRectMake(x * xScalingFactor, y * yScalingFactor, width * xScalingFactor, height * yScalingFactor) }
以上です。
ではでは。