Created
November 3, 2015 09:46
-
-
Save wujianguo/5a3e2e19db32c740ace1 to your computer and use it in GitHub Desktop.
ios swift Gesture Password
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GesturePasswordView.swift | |
// GesturePassword | |
// | |
// Created by wujianguo on 15/10/16. | |
// Copyright © 2015 wujianguo. All rights reserved. | |
// | |
import UIKit | |
@IBDesignable | |
class GesturePasswordView: UIControl { | |
var passwordValue: String { | |
var v: String = "" | |
for i in touchCells { | |
v.append(Character("\(i)")) | |
} | |
return v | |
} | |
@IBInspectable | |
var cellLineWidth: CGFloat = 2 { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var cellLineNormalColor: UIColor = UIColor.greenColor() { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var cellLineSuccessColor: UIColor = UIColor.purpleColor() { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var cellLineFailureColor: UIColor = UIColor.redColor() { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var lineSuccColor: UIColor = UIColor.blueColor() { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var lineErrorColor: UIColor = UIColor.redColor() { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var lineWidth: CGFloat = 5 { didSet { setNeedsDisplay() } } | |
@IBInspectable | |
var contentInset: UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) | |
@IBInspectable | |
var touchTheme = CellTheme.Success | |
enum CellTheme { case Normal, Success, Failure } | |
private func drawCellWith(center: CGPoint, diameter: CGFloat, theme: CellTheme = .Normal) { | |
let context = UIGraphicsGetCurrentContext() | |
CGContextSetLineWidth(context, cellLineWidth) | |
let outterDiameter = diameter - cellLineWidth*2 | |
let outter = CGRectMake(center.x - outterDiameter/2, center.y - outterDiameter/2, outterDiameter, outterDiameter) | |
switch theme { | |
case .Normal: | |
CGContextSetStrokeColorWithColor(context, cellLineNormalColor.CGColor) | |
case .Success: | |
CGContextSetStrokeColorWithColor(context, cellLineSuccessColor.CGColor) | |
CGContextSetFillColorWithColor(context, cellLineSuccessColor.colorWithAlphaComponent(0.3).CGColor) | |
CGContextAddEllipseInRect(context, outter) | |
CGContextFillPath(context) | |
case .Failure: | |
CGContextSetStrokeColorWithColor(context, cellLineFailureColor.CGColor) | |
CGContextSetFillColorWithColor(context, cellLineFailureColor.colorWithAlphaComponent(0.3).CGColor) | |
CGContextAddEllipseInRect(context, outter) | |
CGContextFillPath(context) | |
} | |
CGContextAddEllipseInRect(context, outter) | |
CGContextStrokePath(context) | |
if theme != .Normal { | |
if theme == .Success { | |
CGContextSetFillColorWithColor(context, cellLineSuccessColor.CGColor) | |
} else { | |
CGContextSetFillColorWithColor(context, cellLineFailureColor.CGColor) | |
} | |
let inner = CGRectMake(center.x - diameter/8, center.y - diameter/8, diameter/4, diameter/4); | |
CGContextAddEllipseInRect(context, inner) | |
CGContextFillPath(context) | |
} | |
} | |
private func drawLine(start: CGPoint, end: CGPoint, theme: CellTheme) { | |
let context = UIGraphicsGetCurrentContext() | |
CGContextSetLineWidth(context, lineWidth) | |
if theme == .Normal || theme == .Success { | |
CGContextSetStrokeColorWithColor(context, lineSuccColor.CGColor) | |
} else { | |
CGContextSetStrokeColorWithColor(context, lineErrorColor.CGColor) | |
} | |
CGContextMoveToPoint(context, start.x, start.y) | |
CGContextAddLineToPoint(context, end.x, end.y) | |
CGContextStrokePath(context) | |
} | |
override func drawRect(rect: CGRect) { | |
super.drawRect(rect) | |
let width = rect.width - contentInset.left - contentInset.right | |
let height = rect.height - contentInset.top - contentInset.bottom | |
let diameter = min(width, height) / 4 | |
for i in 0..<9 { | |
drawCellWith(centerOfCell(i), diameter: diameter, theme: cellThemes[i]) | |
} | |
for i in 0..<touchCells.count { | |
if i < touchCells.count - 1 { | |
drawLine(centerOfCell(touchCells[i]), end: centerOfCell(touchCells[i+1]), theme: touchTheme) | |
} else if lineEndPoint != nil { | |
drawLine(centerOfCell(touchCells[i]), end: lineEndPoint!, theme: touchTheme) | |
} | |
} | |
} | |
private func centerOfCell(index: Int) -> CGPoint { | |
let row = Int(index/3) | |
let col = Int(index%3) | |
let width = bounds.width - contentInset.left - contentInset.right | |
let height = bounds.height - contentInset.top - contentInset.bottom | |
let diameter = min(width, height) / 4 | |
let paddingX = (width - 3*diameter) / 2 | |
let paddingY = (height - 3*diameter) / 2 | |
return CGPointMake(contentInset.left + diameter/2 + CGFloat(col)*(diameter+paddingX), contentInset.top + diameter/2 + CGFloat(row)*(diameter+paddingY)) | |
} | |
private func hitCell(point: CGPoint) -> Int? { | |
let width = bounds.width - contentInset.left - contentInset.right | |
let height = bounds.height - contentInset.top - contentInset.bottom | |
let diameter = min(width, height) / 4 | |
for index in 0..<9 { | |
let c = centerOfCell(index) | |
let xDist: Double = Double(c.x) - Double(point.x) | |
let yDist: Double = Double(c.y) - Double(point.y) | |
let distance = sqrt(xDist*xDist + yDist*yDist) | |
if distance < Double(diameter/2) { | |
return index | |
} | |
} | |
return nil | |
} | |
private var touchCells = [Int]() | |
private var lineEndPoint: CGPoint? | |
private var cellThemes = [CellTheme](count: 9, repeatedValue: .Normal) | |
override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool { | |
touchCells.removeAll() | |
cellThemes = [CellTheme](count: 9, repeatedValue: .Normal) | |
if let h = hitCell(touch.locationInView(self)) { | |
cellThemes[h] = .Success | |
touchCells.append(h) | |
} | |
setNeedsDisplay() | |
return super.beginTrackingWithTouch(touch, withEvent: event) | |
} | |
override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool { | |
super.continueTrackingWithTouch(touch, withEvent: event) | |
if let h = hitCell(touch.locationInView(self)) { | |
if (touchCells.filter { $0 == h }).count == 0 { | |
cellThemes[h] = .Success | |
touchCells.append(h) | |
} | |
} | |
lineEndPoint = touch.locationInView(self) | |
setNeedsDisplay() | |
return true | |
} | |
override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) { | |
super.endTrackingWithTouch(touch, withEvent: event) | |
lineEndPoint = nil | |
setNeedsDisplay() | |
sendActionsForControlEvents(.ValueChanged) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment