mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-11 08:50:24 +00:00
[AsyncDisplayKit+Utilities.h] Convenience methods for creating resizable circles & rounded rects. (#1811)
* [AsyncDisplayKit+Utilities.h] UIImage category for performant (optionally rounded) flat color stretchable images * treat clear background color as no background color (D99117) * add borderWidth * add several shorter methods per Scott's comment * rename files and add to AsyncDisplayKit.h * fix xcode project file * update commentse
This commit is contained in:
parent
3763df1f06
commit
682ddcfe51
@ -314,6 +314,10 @@
|
||||
7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; };
|
||||
7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */; };
|
||||
8021EC1C1D2B00B100799119 /* UIImage+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8021EC1D1D2B00B100799119 /* UIImage+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8021EC1E1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */; };
|
||||
8021EC1F1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */; };
|
||||
81EE384F1C8E94F000456208 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
|
||||
8B0768B31CE752EC002E1453 /* ASDefaultPlaybackButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */; };
|
||||
@ -840,6 +844,8 @@
|
||||
7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRelativeLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm; sourceTree = "<group>"; };
|
||||
7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRelativeLayoutSpec.h; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h; sourceTree = "<group>"; };
|
||||
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRelativeLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; };
|
||||
8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ASConvenience.h"; sourceTree = "<group>"; };
|
||||
8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ASConvenience.m"; sourceTree = "<group>"; };
|
||||
81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = "<group>"; };
|
||||
81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = "<group>"; };
|
||||
8B0768B11CE752EC002E1453 /* ASDefaultPlaybackButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDefaultPlaybackButton.h; sourceTree = "<group>"; };
|
||||
@ -1124,6 +1130,8 @@
|
||||
058D09DD195D050800B7D73C /* ASImageNode.h */,
|
||||
058D09DE195D050800B7D73C /* ASImageNode.mm */,
|
||||
68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */,
|
||||
8021EC1A1D2B00B100799119 /* UIImage+ASConvenience.h */,
|
||||
8021EC1B1D2B00B100799119 /* UIImage+ASConvenience.m */,
|
||||
0516FA3E1A1563D200B4EBED /* ASMultiplexImageNode.h */,
|
||||
0516FA3F1A1563D200B4EBED /* ASMultiplexImageNode.mm */,
|
||||
68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */,
|
||||
@ -1594,6 +1602,7 @@
|
||||
AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
|
||||
058D0A4D195D05CB00B7D73C /* ASDisplayNodeExtras.h in Headers */,
|
||||
92074A671CC8BADA00918F75 /* ASControlNode+tvOS.h in Headers */,
|
||||
8021EC1C1D2B00B100799119 /* UIImage+ASConvenience.h in Headers */,
|
||||
697C0DE31CF38F28001DE0D4 /* ASLayoutValidation.h in Headers */,
|
||||
68355B3B1CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h in Headers */,
|
||||
68B0277A1C1A79CC0041016B /* ASDisplayNode+Beta.h in Headers */,
|
||||
@ -1753,6 +1762,7 @@
|
||||
A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */,
|
||||
DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */,
|
||||
9C70F2061CDA4F0C007D6C76 /* ASTraitCollection.h in Headers */,
|
||||
8021EC1D1D2B00B100799119 /* UIImage+ASConvenience.h in Headers */,
|
||||
254C6B801BF94DF4003EC431 /* ASEqualityHashHelpers.h in Headers */,
|
||||
B350624F1B010EFD0018CF92 /* ASDisplayNode+DebugTiming.h in Headers */,
|
||||
B35061FD1B010EFD0018CF92 /* ASDisplayNode+Subclasses.h in Headers */,
|
||||
@ -2093,6 +2103,7 @@
|
||||
B30BF6531C5964B0004FCD53 /* ASLayoutManager.m in Sources */,
|
||||
05A6D05B19D0EB64002DD95E /* ASDealloc2MainObject.m in Sources */,
|
||||
ACF6ED211B17843500DA7C62 /* ASDimension.mm in Sources */,
|
||||
8021EC1E1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */,
|
||||
058D0A28195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm in Sources */,
|
||||
058D0A29195D050800B7D73C /* ASDisplayNode+DebugTiming.mm in Sources */,
|
||||
764D83D61C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m in Sources */,
|
||||
@ -2260,6 +2271,7 @@
|
||||
B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */,
|
||||
509E68641B3AEDB7009B9150 /* ASCollectionViewLayoutController.mm in Sources */,
|
||||
B35061F91B010EFD0018CF92 /* ASControlNode.mm in Sources */,
|
||||
8021EC1F1D2B00B100799119 /* UIImage+ASConvenience.m in Sources */,
|
||||
B35062181B010EFD0018CF92 /* ASDataController.mm in Sources */,
|
||||
B350621A1B010EFD0018CF92 /* ASDealloc2MainObject.m in Sources */,
|
||||
767E7F8E1C90191D0066C000 /* AsyncDisplayKit+Debug.m in Sources */,
|
||||
|
||||
@ -75,15 +75,17 @@
|
||||
#import <AsyncDisplayKit/ASLog.h>
|
||||
#import <AsyncDisplayKit/ASMutableAttributedStringBuilder.h>
|
||||
#import <AsyncDisplayKit/ASThread.h>
|
||||
#import <AsyncDisplayKit/CGRect+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/NSMutableAttributedString+TextKitAdditions.h>
|
||||
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/UIView+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/ASRunLoopQueue.h>
|
||||
#import <AsyncDisplayKit/ASTextKitComponents.h>
|
||||
#import <AsyncDisplayKit/ASTraitCollection.h>
|
||||
#import <AsyncDisplayKit/ASVisibilityProtocols.h>
|
||||
|
||||
#import <AsyncDisplayKit/CGRect+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/NSMutableAttributedString+TextKitAdditions.h>
|
||||
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/UIView+ASConvenience.h>
|
||||
#import <AsyncDisplayKit/UIImage+ASConvenience.h>
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit+Debug.h>
|
||||
|
||||
#import <AsyncDisplayKit/ASCollectionNode+Beta.h>
|
||||
|
||||
71
AsyncDisplayKit/UIImage+ASConvenience.h
Normal file
71
AsyncDisplayKit/UIImage+ASConvenience.h
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// UIImage+ASConvenience.h
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Hannah Troisi on 6/24/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import <UIKit/UIImage.h>
|
||||
#import <UIKit/UIBezierPath.h>
|
||||
|
||||
// High-performance flat-colored, rounded-corner resizable images
|
||||
//
|
||||
// For "Baked-in Opaque" corners, set cornerColor equal to the color behind the rounded image object, e.g. the background color.
|
||||
// For "Baked-in Alpha" corners, set cornerColor = [UIColor clearColor]
|
||||
//
|
||||
// See http://asyncdisplaykit.org/docs/corner-rounding.html for an explanation.
|
||||
|
||||
@interface UIImage (ASDKAdditions)
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image
|
||||
*
|
||||
* @param cornerRadius The radius of the rounded-corner
|
||||
* @param cornerColor The fill color of the corners (For Alpha corners use clearColor)
|
||||
* @param fillColor The fill color of the rounded-corner image
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor;
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image with a border
|
||||
*
|
||||
* @param cornerRadius The radius of the rounded-corner
|
||||
* @param cornerColor The fill color of the corners (For Alpha corners use clearColor)
|
||||
* @param fillColor The fill color of the rounded-corner image
|
||||
* @param borderColor The border color. Set to nil for no border.
|
||||
* @param borderWidth The border width. Dummy value if borderColor = nil.
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth;
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image with a border
|
||||
*
|
||||
* @param cornerRadius The radius of the rounded-corner
|
||||
* @param cornerColor The fill color of the corners (For Alpha corners use clearColor)
|
||||
* @param fillColor The fill color of the rounded-corner image
|
||||
* @param borderColor The border color. Set to nil for no border.
|
||||
* @param borderWidth The border width. Dummy value if borderColor = nil.
|
||||
* @param roundedCorners Select individual or multiple corners to round. Set to UIRectCornerAllCorners to round all 4 corners.
|
||||
* @param scale The number of pixels per point. Provide 0.0 to use the screen scale.
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale;
|
||||
|
||||
@end
|
||||
|
||||
131
AsyncDisplayKit/UIImage+ASConvenience.m
Normal file
131
AsyncDisplayKit/UIImage+ASConvenience.m
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// UIImage+ASConvenience.m
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Hannah Troisi on 6/24/16.
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import "UIImage+ASConvenience.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@implementation UIImage (ASDKAdditions)
|
||||
|
||||
|
||||
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
{
|
||||
return [self as_resizableRoundedImageWithCornerRadius:cornerRadius
|
||||
cornerColor:cornerColor
|
||||
fillColor:fillColor
|
||||
borderColor:nil
|
||||
borderWidth:1.0
|
||||
roundedCorners:UIRectCornerAllCorners
|
||||
scale:0.0];
|
||||
}
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
{
|
||||
return [self as_resizableRoundedImageWithCornerRadius:cornerRadius
|
||||
cornerColor:cornerColor
|
||||
fillColor:fillColor
|
||||
borderColor:borderColor
|
||||
borderWidth:borderWidth
|
||||
roundedCorners:UIRectCornerAllCorners
|
||||
scale:0.0];
|
||||
}
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale
|
||||
{
|
||||
static NSCache *__pathCache = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
__pathCache = [[NSCache alloc] init];
|
||||
// UIBezierPath objects are fairly small and these are equally sized. 20 should be plenty for many different parameters.
|
||||
__pathCache.countLimit = 20;
|
||||
});
|
||||
|
||||
// Treat clear background color as no background color
|
||||
if ([cornerColor isEqual:[UIColor clearColor]]) {
|
||||
cornerColor = nil;
|
||||
}
|
||||
|
||||
CGFloat dimension = (cornerRadius * 2) + 1;
|
||||
CGRect bounds = CGRectMake(0, 0, dimension, dimension);
|
||||
|
||||
// This is a hack to make one NSNumber key out of the corners and cornerRadius
|
||||
if (roundedCorners == UIRectCornerAllCorners) {
|
||||
// UIRectCornerAllCorners is ~0, but below is equivalent and we can pack it into half an NSUInteger
|
||||
roundedCorners = UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight;
|
||||
}
|
||||
// Left half of NSUInteger is roundedCorners, right half is cornerRadius
|
||||
UInt64 pathKeyNSUInteger = (UInt64)roundedCorners << sizeof(Float32) * 8;
|
||||
Float32 floatCornerRadius = cornerRadius;
|
||||
pathKeyNSUInteger |= (NSUInteger)floatCornerRadius;
|
||||
|
||||
NSNumber *pathKey = [NSNumber numberWithUnsignedLongLong:pathKeyNSUInteger];
|
||||
|
||||
UIBezierPath *path = nil;
|
||||
CGSize cornerRadii = CGSizeMake(cornerRadius, cornerRadius);
|
||||
|
||||
@synchronized(__pathCache) {
|
||||
path = [__pathCache objectForKey:pathKey];
|
||||
if (!path) {
|
||||
path = [UIBezierPath bezierPathWithRoundedRect:bounds byRoundingCorners:roundedCorners cornerRadii:cornerRadii];
|
||||
[__pathCache setObject:path forKey:pathKey];
|
||||
}
|
||||
}
|
||||
|
||||
// We should probably check if the background color has any alpha component but that
|
||||
// might be expensive due to needing to check mulitple color spaces.
|
||||
UIGraphicsBeginImageContextWithOptions(bounds.size, cornerColor != nil, scale);
|
||||
|
||||
if (cornerColor) {
|
||||
[cornerColor setFill];
|
||||
// Copy "blend" mode is extra fast because it disregards any value currently in the buffer and overwrites directly.
|
||||
UIRectFillUsingBlendMode(bounds, kCGBlendModeCopy);
|
||||
}
|
||||
|
||||
[fillColor setFill];
|
||||
[path fill];
|
||||
|
||||
if (borderColor) {
|
||||
[borderColor setStroke];
|
||||
|
||||
// Inset border fully inside filled path (not halfway on each side of path)
|
||||
CGRect strokeRect = CGRectInset(bounds, borderWidth / 2.0, borderWidth / 2.0);
|
||||
|
||||
// It is rarer to have a stroke path, and our cache key only handles rounded rects for the exact-stretchable
|
||||
// size calculated by cornerRadius, so we won't bother caching this path. Profiling validates this decision.
|
||||
UIBezierPath *strokePath = [UIBezierPath bezierPathWithRoundedRect:strokeRect cornerRadius:cornerRadius];
|
||||
[strokePath setLineWidth:borderWidth];
|
||||
[strokePath stroke];
|
||||
}
|
||||
|
||||
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
UIEdgeInsets capInsets = UIEdgeInsetsMake(cornerRadius, cornerRadius, cornerRadius, cornerRadius);
|
||||
result = [result resizableImageWithCapInsets:capInsets resizingMode:UIImageResizingModeStretch];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
Loading…
x
Reference in New Issue
Block a user