no message

This commit is contained in:
Peter 2015-09-22 15:23:16 +03:00
parent 032a5ec6bd
commit 2078656033
6 changed files with 185 additions and 3 deletions

View File

@ -53,6 +53,7 @@
D06EE8451B7140FF00837186 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06EE8441B7140FF00837186 /* Font.swift */; };
D07921A91B6FC0C0005C23D9 /* KeyboardHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */; };
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */; };
D0E49C881B83A3580099E553 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E49C871B83A3580099E553 /* ImageCache.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -115,6 +116,7 @@
D06EE8441B7140FF00837186 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; };
D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardHostWindow.swift; sourceTree = "<group>"; };
D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarHostWindow.swift; sourceTree = "<group>"; };
D0E49C871B83A3580099E553 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -172,6 +174,7 @@
D07921A71B6FC0AE005C23D9 /* Keyboard */,
D05CC3211B695AA600E235A3 /* Navigation */,
D02BDAEC1B6A7053008AFAD2 /* Nodes */,
D0E49C861B83A1680099E553 /* Image Cache */,
D05CC2A11B69326C00E235A3 /* Window.swift */,
D05CC2E21B69552C00E235A3 /* ViewController.swift */,
D05CC2E11B69534100E235A3 /* Supporting Files */,
@ -273,6 +276,14 @@
name = "Status Bar";
sourceTree = "<group>";
};
D0E49C861B83A1680099E553 /* Image Cache */ = {
isa = PBXGroup;
children = (
D0E49C871B83A3580099E553 /* ImageCache.swift */,
);
name = "Image Cache";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -393,6 +404,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D0E49C881B83A3580099E553 /* ImageCache.swift in Sources */,
D05CC3181B695A9600E235A3 /* NavigationItemTransitionState.swift in Sources */,
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */,
D05CC2F81B6955D000E235A3 /* UIViewController+Navigation.m in Sources */,

View File

@ -36,7 +36,7 @@ public extension CALayer {
self.addAnimation(animation, forKey: keyPath)
self.setValue(to, forKey: keyPath)
//self.setValue(to, forKey: keyPath)
}
public func animateAlpha(from from: CGFloat, to: CGFloat, duration: NSTimeInterval) {

154
Display/ImageCache.swift Normal file
View File

@ -0,0 +1,154 @@
import Foundation
private final class ImageCacheData {
let size: CGSize
let bytesPerRow: Int
var data: NSPurgeableData
var isDiscarded: Bool {
return self.data.isContentDiscarded()
}
var image: UIImage? {
if self.data.beginContentAccess() {
return self.createImage()
}
return nil
}
init(size: CGSize, generator: CGContextRef -> Void, @noescape takenImage: UIImage -> Void) {
self.size = size
self.bytesPerRow = (4 * Int(size.width) + 15) & (~15)
self.data = NSPurgeableData(length: self.bytesPerRow * Int(size.height))!
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue
if let context = CGBitmapContextCreate(self.data.mutableBytes, Int(size.width), Int(size.height), 8, bytesPerRow, colorSpace, bitmapInfo)
{
CGContextTranslateCTM(context, size.width / 2.0, size.height / 2.0)
CGContextScaleCTM(context, 1.0, -1.0)
CGContextTranslateCTM(context, -size.width / 2.0, -size.height / 2.0)
UIGraphicsPushContext(context)
generator(context)
UIGraphicsPopContext()
}
takenImage(self.createImage())
}
private func createImage() -> UIImage {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue
let unmanagedData = withUnsafePointer(&self.data, { pointer in
return Unmanaged<NSPurgeableData>.fromOpaque(COpaquePointer(pointer))
})
unmanagedData.retain()
let dataProvider = CGDataProviderCreateWithData(UnsafeMutablePointer<Void>(unmanagedData.toOpaque()), self.data.bytes, self.bytesPerRow, { info, _, _ in
let unmanagedData = Unmanaged<NSPurgeableData>.fromOpaque(COpaquePointer(info))
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
unmanagedData.takeUnretainedValue().endContentAccess()
unmanagedData.release()
})
})
let image = CGImageCreate(Int(self.size.width), Int(self.size.height), 8, 32, self.bytesPerRow, colorSpace, CGBitmapInfo(rawValue: bitmapInfo), dataProvider, nil, false, CGColorRenderingIntent(rawValue: 0)!)
let result = UIImage(CGImage: image!)
return result
}
}
private final class ImageCacheResidentImage {
let key: String
let image: UIImage
var accessIndex: Int
init(key: String, image: UIImage, accessIndex: Int) {
self.key = key
self.image = image
self.accessIndex = accessIndex
}
}
public final class ImageCache {
let maxResidentSize: Int
var mutex = pthread_mutex_t()
private var imageDatas: [String : ImageCacheData] = [:]
private var residentImages: [String : ImageCacheResidentImage] = [:]
var nextAccessIndex = 1
var residentImagesSize = 0
public init(maxResidentSize: Int) {
self.maxResidentSize = maxResidentSize
pthread_mutex_init(&self.mutex, nil)
}
deinit {
pthread_mutex_destroy(&self.mutex)
}
public func addImageForKey(key: String, size: CGSize, generator: CGContextRef -> Void) {
var image: UIImage?
let imageData = ImageCacheData(size: size, generator: generator, takenImage: { image = $0 })
pthread_mutex_lock(&self.mutex)
self.imageDatas[key] = imageData
self.addResidentImage(image!, forKey: key)
pthread_mutex_unlock(&self.mutex)
}
public func imageForKey(key: String) -> UIImage? {
var image: UIImage?
pthread_mutex_lock(&self.mutex);
if let residentImage = self.residentImages[key] {
image = residentImage.image
self.nextAccessIndex++
residentImage.accessIndex = self.nextAccessIndex
} else {
if let imageData = self.imageDatas[key] {
if let takenImage = imageData.image {
image = takenImage
self.addResidentImage(takenImage, forKey: key)
} else {
self.imageDatas.removeValueForKey(key)
}
}
}
pthread_mutex_unlock(&self.mutex)
return image
}
private func addResidentImage(image: UIImage, forKey key: String) {
let imageSize = Int(image.size.width * image.size.height * image.scale) * 4
if self.residentImagesSize + imageSize > self.maxResidentSize {
let sizeToRemove = self.residentImagesSize - (self.maxResidentSize - imageSize)
let sortedImages = self.residentImages.values.sort({ $0.accessIndex < $1.accessIndex })
var removedSize = 0
var i = sortedImages.count - 1
while i >= 0 && removedSize < sizeToRemove {
let currentImage = sortedImages[i]
let currentImageSize = Int(currentImage.image.size.width * currentImage.image.size.height * currentImage.image.scale) * 4
removedSize += currentImageSize
self.residentImages.removeValueForKey(currentImage.key)
i--
}
self.residentImagesSize = max(0, self.residentImagesSize - removedSize)
}
self.residentImagesSize += imageSize
self.nextAccessIndex++
self.residentImages[key] = ImageCacheResidentImage(key: key, image: image, accessIndex: self.nextAccessIndex)
}
}

View File

@ -192,8 +192,6 @@ internal class NavigationItemWrapper {
if suspendLayout {
return
}
self.titleNode.measure(self.parentNode.bounds.size)
self.titleNode.frame = self.titleFrame
self.backButtonNode.measure(self.parentNode.frame.size)
self.backButtonNode.frame = self.backButtonFrame
@ -208,6 +206,9 @@ internal class NavigationItemWrapper {
rightBarButtonItemWrapper.buttonNode.measure(self.parentNode.frame.size)
rightBarButtonItemWrapper.buttonNode.frame = self.rightButtonFrame!
}
self.titleNode.measure(CGSize(width: self.parentNode.bounds.size.width - 140.0, height: CGFloat.max))
self.titleNode.frame = self.titleFrame
}
func interpolatePosition(from: CGPoint, _ to: CGPoint, value: CGFloat) -> CGPoint {

View File

@ -17,6 +17,8 @@ public class NavigationTitleNode: ASDisplayNode {
public init(text: NSString) {
self.label = ASTextNode()
self.label.maximumLineCount = 1
self.label.truncationMode = .ByTruncatingTail
self.label.displaysAsynchronously = false
super.init()

View File

@ -34,6 +34,10 @@ public extension UIColor {
convenience init(_ rgb: Int) {
self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: 1.0)
}
convenience init(_ rgb: Int, _ alpha: CGFloat) {
self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: alpha)
}
}
public extension CGSize {
@ -47,4 +51,13 @@ public extension CGSize {
}
return fittedSize
}
public func aspectFilled(size: CGSize) -> CGSize {
let scale = max(size.width / max(1.0, self.width), size.height / max(1.0, self.height))
return CGSize(width: floor(self.width * scale), height: floor(self.height * scale))
}
}
public func assertNotOnMainThread(file: String = __FILE__, line: Int = __LINE__) {
assert(!NSThread.isMainThread(), "\(file):\(line) running on main thread")
}