Skip to content

Instantly share code, notes, and snippets.

@mingsai
Created July 14, 2015 12:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mingsai/3d27db100fb2d0bb78fc to your computer and use it in GitHub Desktop.
Save mingsai/3d27db100fb2d0bb78fc to your computer and use it in GitHub Desktop.
Star rating control is the code behind a custom view to produce a number of stars that respond to touch. The stars become highlighted when touched and change a rating property.
//
// StarRatingControl.swift
// ths
//
// Created by Tommie Carter on 7/13/15.
// Copyright © 2015 MING Technology. All rights reserved.
//
import UIKit
protocol StarRatingDelegate {
func starRatingControl(control:StarRatingControl, didUpdateRating:Float)
func starRatingControl(control:StarRatingControl, willUpdateRating:Float)
}
class StarRatingControl: UIControl {
let kDefaultNumberOfStars = 5
let kStarPadding:Float = 5.0
var delegate:StarRatingDelegate!
var rating:Float! {
set {
currentIdx = Int(round(self.rating))
for (idx, _star) in stars!.enumerate() {
(_star as! UIImageView
).highlighted = (idx < currentIdx)
}
}
get {
return Float (currentIdx)
}
}
var star:UIImage!
var highlightedStar:UIImage!
var currentIdx:Int!
var numberOfStars:Int!
var stars:[AnyObject]?
//MARK: View Initialization
override init(frame: CGRect) {
super.init(frame: frame)
self.numberOfStars = kDefaultNumberOfStars
setupView()
}
convenience init(frame: CGRect, numberOfStars:Int) {
self.init(frame: frame)
self.numberOfStars = kDefaultNumberOfStars
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.numberOfStars = kDefaultNumberOfStars
setupView()
}
//MARK: View Layout
func setupView () {
self.clipsToBounds = true
currentIdx = -1
//let normal = UIImage.imageFromText("★", fontname: "Chalkduster", fontSize: CGFloat(60.0))?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
//let highlightedImage = UIImage.imageFromText("★", fontname: "Chalkduster", fontSize: CGFloat(60.0))?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
star = UIImage.imageFromText("★", fontname: "Chalkduster", fontSize: CGFloat(60.0))?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
//UIImage(named: "star.png")
highlightedStar = UIImage.imageFromText("★", fontname: "Chalkduster", fontSize: CGFloat(60.0))?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
var s = Array<AnyObject>()
s.reserveCapacity(self.numberOfStars)
for (var i = 0; i < numberOfStars; i = i + 1) {
let v = UIImageView(image: star, highlightedImage: highlightedStar)
v.tintColor = UIColor.yellowColor()
self.addSubview(v)
s.append(v)
}
stars = s
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
override func layoutSubviews() {
super.layoutSubviews()
let width = CGFloat((Float(self.frame.size.width) - (kStarPadding * Float(numberOfStars + 1))) / Float(numberOfStars))
let cellWidth = min(self.frame.size.height, width)
// We need to align the stars in the center of the view
let totalCellWidth = (Float(self.frame.size.width) - (Float(cellWidth) * Float(numberOfStars)))
let padding = totalCellWidth + (kStarPadding * (Float(numberOfStars) + 1)) / Float(2.0)
for (idx, _star) in stars!.enumerate() {
let paddedValue = padding + kStarPadding + Float(idx) * Float(cellWidth) + Float(idx) * kStarPadding
let frame = CGRectMake(CGFloat(paddedValue) * CGFloat(kStarPadding), 0, cellWidth, cellWidth)
(_star as! UIImageView
).frame = frame
}
}
func starForPoint(point:CGPoint) -> UIImageView? {
for star in stars! {
if let imageView = star as? UIImageView {
(CGRectContainsPoint(star.frame, point))
return imageView
}
}
return nil
}
func indexForStar(atPoint:CGPoint) -> Int {
let _stars = stars as! [UIImageView]
return _stars.indexOf(self.starForPoint(atPoint)!)!
}
//MARK: Touch Events
override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
//super.beginTrackingWithTouch(touch, withEvent: event)
let _star = stars![0] as! UIImageView
let point = touch.locationInView(self)
let index = self.indexForStar(point)
if (index != NSNotFound) {
self.rating = Float ( index+1 )
//if (self.delegate?.starRatingControl:willUpdateRating) ///{
let pointOffset = Int(point.x)
let firstStarPoint = Int ( _star.frame.origin.x )
if ( pointOffset < firstStarPoint ) {
self.delegate.starRatingControl(self, willUpdateRating: self.rating)
} else {
self.rating = 0
self.delegate.starRatingControl(self, willUpdateRating:self.rating)
}
}
return true
}
override func cancelTrackingWithEvent(event: UIEvent?) {
super.cancelTrackingWithEvent(event)
}
override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
let point = touch.locationInView(self)
let index = self.indexForStar(point)
let _star = stars![0] as! UIImageView
if (index != NSNotFound) {
self.rating = Float( index + 1 )
let pointOffset = Int(point.x)
let firstStarPoint = Int ( _star.frame.origin.x )
if ( pointOffset < firstStarPoint ) {
self.delegate.starRatingControl(self, willUpdateRating: self.rating)
} else {
self.rating = 0
self.delegate.starRatingControl(self, willUpdateRating:self.rating)
}
}
return true
}
override func endTrackingWithTouch(touch: UITouch?, withEvent event: UIEvent?) {
self.delegate.starRatingControl(self, didUpdateRating: self.rating)
super.endTrackingWithTouch(touch, withEvent: event)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment