Skip to content

Instantly share code, notes, and snippets.

@clmntcrl
Last active August 3, 2017 08:26
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clmntcrl/8e4cab3ed7d1e7da47e7 to your computer and use it in GitHub Desktop.
Save clmntcrl/8e4cab3ed7d1e7da47e7 to your computer and use it in GitHub Desktop.
ShapedButton is a UIButton subclass optimized for non-rectangular button shapes written in Swift. ShapedButton respond to touches only in areas where the flattened button image (background image + image + title label) for state .Normal is non-transparent. This implementation is based on OBShapedButton by Ole Begemann (https://github.com/ole/OBSh…
//
// ShapedButton.swift
//
//
// Created by clmntcrl on 16/09/2014.
// Copyright (c) 2014 clmntcrl. All rights reserved.
//
import UIKit
class ShapedButton: UIButton {
override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
if !super.pointInside(point, withEvent: event) {
return false
}
UIGraphicsBeginImageContext(bounds.size)
layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
// ↓ cf. UIImage+ColorAtPixel from https://github.com/ole/OBShapedButton
let pointX = trunc(point.x)
let pointY = trunc(point.y)
let cgImage = image.CGImage
let width = image.size.width
let height = image.size.height
var pixelData: [CUnsignedChar] = [0, 0, 0, 0]
let bytesPerPixel: UInt = 4
let bytesPerRow: UInt = bytesPerPixel * 1
let bitsPerComponent: UInt = 8
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo.ByteOrder32Big | CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
let context = CGBitmapContextCreate(&pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)
CGContextSetBlendMode(context, kCGBlendModeCopy)
CGContextTranslateCTM(context, -pointX, pointY - height)
CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), cgImage)
// let r = CGFloat(pixelData[0]) / 255.0
// let g = CGFloat(pixelData[1]) / 255.0
// let b = CGFloat(pixelData[2]) / 255.0
let a = CGFloat(pixelData[3]) / 255.0
return a != 0.0
}
}
@avadhbsd
Copy link

avadhbsd commented Oct 1, 2015

I got this
Cannot invoke 'CGBitmapContextCreate' with an argument list of type '(inout [CUnsignedChar], Int, Int, UInt, UInt, CGColorSpace!, CGBitmapInfo)'

@NickBols
Copy link

Updated it for Swift 2.0 with following code. Seems to work fine so far but you might wanna check!
Thanks!

var pixelData: [CUnsignedChar] = [0, 0, 0, 0]
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * 1
let bitsPerComponent = 8
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue)
let context = CGBitmapContextCreate(&pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo.rawValue)
CGContextSetBlendMode(context, CGBlendMode.Copy)

@mwallon
Copy link

mwallon commented Aug 10, 2016

Hi, for some reason I get memory error when using this. I have a function that adds 10 buttons with pngs as backgrounds but everytime I click one of the buttons it adds to the memorybuffer an after about 10 clicks the app crash due to memory issues. Do you know what could cause this?

@cbechtell
Copy link

Will this be updated for Swift 3? I'm having trouble getting it functioning.

@gmichal
Copy link

gmichal commented Jan 4, 2017

Is anyone working on swift 3 for this?

Copy link

ghost commented Aug 3, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment