Commit f722fb2b authored by 李震's avatar 李震

提高版本号

parent 81c8fb80
//
// Dictionary+GM.swift
// Gengmei
//
// Created by Thierry on 16/6/15.
// Copyright © 2016年 更美互动信息科技有限公司. All rights reserved.
//
import Foundation
public extension Dictionary {
func merge(_ dict: Dictionary) -> Dictionary {
var mutableCopy = self
for (key, value) in dict {
// If both dictionaries have a value for same key, the value of the other dictionary is used.
mutableCopy[key] = value
}
return mutableCopy
}
}
//
// NSDictionary+LogCategory.h
//
//
// Created by liulujie on 18/1/10.
// Copyright © 2018年 RedSoft. All rights reserved.
//
#import <Foundation/Foundation.h>
// 如果需要关掉兼容中文的打印,把下面的宏注释掉即可
#define UseLogChinese
@interface NSArray (Log)
@end
@interface NSDictionary (Log)
@end
//
// NSDictionary+LogCategory.m
//
//
// Created by liulujie on 18/1/10.
// Copyright © 2018年 RedSoft. All rights reserved.
//
#import "LogCategory.h"
#import <objc/runtime.h>
@implementation NSArray (Log)
#ifdef UseLogChinese
- (NSString *)debugDescription {
return [NSString stringWithFormat:@"<%@ %p> %@", NSStringFromClass([self class]), self, [self descriptionWithLocale:nil]];
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@ %p> %@", NSStringFromClass([self class]), self, [self descriptionWithLocale:nil]];
}
- (NSString *)descriptionWithLocale:(id)locale {
NSMutableString * string = [NSMutableString string];
[string appendString:@"[\n"];
NSUInteger count = self.count;
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString * temp = nil;
if ([obj respondsToSelector:@selector(descriptionWithLocale:)]) {
temp = [obj performSelector:@selector(descriptionWithLocale:) withObject:locale];
temp = [temp stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"];
} else {
temp = [obj performSelector:@selector(description) withObject:nil];
if ([obj isKindOfClass:[NSString class]]) {
temp = [NSString stringWithFormat:@"\"%@\"", temp];
}
}
[string appendFormat:@"\t%@", temp];
if (idx+1 != count) {
[string appendString:@","];
}
[string appendString:@"\n"];
}];
[string appendString:@"]"];
return string;
}
#endif
@end
@implementation NSDictionary (Log)
#ifdef UseLogChinese
- (NSString *)debugDescription {
return [NSString stringWithFormat:@"<%@ %p> %@", NSStringFromClass([self class]), self, [self descriptionWithLocale:nil]];
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@ %p> %@", NSStringFromClass([self class]), self, [self descriptionWithLocale:nil]];
}
- (NSString *)descriptionWithLocale:(id)locale {
NSMutableString * string = [NSMutableString string];
[string appendString:@"{\n"];
NSUInteger count = self.allKeys.count;
for (id key in self.allKeys) {
NSInteger index = [self.allKeys indexOfObject:key];
id value = [self objectForKey:key];
NSString * temp = nil;
if ([value respondsToSelector:@selector(descriptionWithLocale:)]) {
temp = [value performSelector:@selector(descriptionWithLocale:) withObject:locale];
temp = [temp stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"];
} else {
temp = [value performSelector:@selector(description) withObject:nil];
if ([value isKindOfClass:[NSString class]]) {
temp = [NSString stringWithFormat:@"\"%@\"", temp];
}
}
[string appendFormat:@"\t%@ = %@", key, temp];
if (index+1 != count) {
[string appendString:@";"];
}
[string appendString:@"\n"];
}
[string appendString:@"}"];
return string;
}
#endif
@end
//
// NSArray+GM.h
// Gengmei
//
// Created by wangyang on 2018/4/9.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSArray (GM)
// 循环对比数组中的元素,遇到第一个符合条件的就删除,并停止遍历
- (NSArray *)arrayFromDeleteCondition:(BOOL (^)(id object))compare;
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block;
@end
@interface NSMutableArray (GM)
// 循环对比数组中的元素,遇到第一个符合条件的就删除,并停止遍历
- (void)deleteCondition:(BOOL (^)(id object))compare;
@end
//
// NSArray+GM.m
// Gengmei
//
// Created by wangyang on 2018/4/9.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import "NSArray+GM.h"
@implementation NSArray (GM)
- (NSArray *)arrayFromDeleteCondition:(BOOL (^)(id object))compare {
NSMutableArray *array;
if ([self isMemberOfClass:[NSMutableArray class]]) {
array = (NSMutableArray *)self;
} else {
array = [self mutableCopy];
}
NSInteger deleteIndex = -1;
for (int i = 0; i < array.count; i++) {
if (compare(array[i])) {
deleteIndex = i;
break;
}
}
if (deleteIndex != -1) {
[array removeObjectAtIndex:deleteIndex];
}
return array;
}
// 对于不想添加到结果中的情况,就返回 nil
- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
NSMutableArray *result = [NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
id value = block(obj, idx);
if (value) {
[result addObject:value];
}
}];
return result;
}
@end
@implementation NSMutableArray (GM)
- (void)deleteCondition:(BOOL (^)(id object))compare {
NSInteger deleteIndex = -1;
for (int i = 0; i < self.count; i++) {
if (compare(self[i])) {
deleteIndex = i;
break;
}
}
if (deleteIndex != -1) {
[self removeObjectAtIndex:deleteIndex];
}
}
@end
//
// NSDate+Category.h
// FoJiao
//
// Created by yh on 15/8/31.
// Copyright (c) 2015年 ZSC. All rights reserved.
//
#import <Foundation/Foundation.h>
#define D_MINUTE 60
#define D_HOUR 3600
#define D_DAY 86400
#define D_WEEK 604800
#define D_YEAR 31556926
@interface NSDate (Category)
- (NSString *)timeIntervalDescription;//距离当前的时间间隔描述
- (NSString *)minuteDescription;/*精确到分钟的日期描述*/
- (NSString *)formattedTime;
- (NSString *)formattedDateDescription;//格式化日期描述
- (double)timeIntervalSince1970InMilliSecond;
+ (NSDate *)dateWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond;
+ (NSString *)dateStringWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond;
+ (NSString *)dateStringWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond format:(NSString *)format;
+ (NSString *)formattedTimeFromTimeInterval:(long long)time;
// Relative dates from the current date
+ (NSDate *) dateTomorrow;
+ (NSDate *) dateYesterday;
+ (NSDate *) dateWithDaysFromNow: (NSInteger) days;
+ (NSDate *) dateWithDaysBeforeNow: (NSInteger) days;
+ (NSDate *) dateWithHoursFromNow: (NSInteger) dHours;
+ (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours;
+ (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes;
+ (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes;
// Comparing dates
//- (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate;
- (BOOL) isToday;
- (BOOL) isTomorrow;
- (BOOL) isYesterday;
- (BOOL) isSameWeekAsDate: (NSDate *) aDate;
- (BOOL) isThisWeek;
- (BOOL) isNextWeek;
- (BOOL) isLastWeek;
- (BOOL) isSameMonthAsDate: (NSDate *) aDate;
- (BOOL) isThisMonth;
- (BOOL) isSameYearAsDate: (NSDate *) aDate;
- (BOOL) isThisYear;
- (BOOL) isNextYear;
- (BOOL) isLastYear;
- (BOOL) isEarlierThanDate: (NSDate *) aDate;
- (BOOL) isLaterThanDate: (NSDate *) aDate;
- (BOOL) isInFuture;
- (BOOL) isInPast;
// Date roles
- (BOOL) isTypicallyWorkday;
- (BOOL) isTypicallyWeekend;
// Adjusting dates
- (NSDate *) dateByAddingDays: (NSInteger) dDays;
- (NSDate *) dateBySubtractingDays: (NSInteger) dDays;
- (NSDate *) dateByAddingHours: (NSInteger) dHours;
- (NSDate *) dateBySubtractingHours: (NSInteger) dHours;
- (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes;
- (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes;
- (NSDate *) dateAtStartOfDay;
// Retrieving intervals
- (NSInteger) minutesAfterDate: (NSDate *) aDate;
- (NSInteger) minutesBeforeDate: (NSDate *) aDate;
- (NSInteger) hoursAfterDate: (NSDate *) aDate;
- (NSInteger) hoursBeforeDate: (NSDate *) aDate;
- (NSInteger) daysAfterDate: (NSDate *) aDate;
- (NSInteger) daysBeforeDate: (NSDate *) aDate;
- (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate;
// Decomposing dates
@property (readonly) NSInteger nearestHour;
@property (readonly) NSInteger hour;
@property (readonly) NSInteger minute;
@property (readonly) NSInteger seconds;
@property (readonly) NSInteger day;
@property (readonly) NSInteger month;
@property (readonly) NSInteger week;
@property (readonly) NSInteger weekday;
@property (readonly) NSInteger nthWeekday; // e.g. 2nd Tuesday of the month == 2
@property (readonly) NSInteger year;
@end
//
// NSDate+Category.m
// FoJiao
//
// Created by yh on 15/8/31.
// Copyright (c) 2015年 ZSC. All rights reserved.
//
#import "NSDate+Category.h"
#import "NSDateFormatter+Category.h"
#define DATE_COMPONENTS (NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit)
#define CURRENT_CALENDAR [NSCalendar currentCalendar]
@implementation NSDate (Category)
/*距离当前的时间间隔描述*/
- (NSString *)timeIntervalDescription {
NSTimeInterval timeInterval = -[self timeIntervalSinceNow];
if (timeInterval < 60) {
return NSLocalizedString(@"NSDateCategory.text1", @"");
} else if (timeInterval < 3600) {
return [NSString stringWithFormat:@"%.f分钟前", timeInterval / 60];
} else if (timeInterval < 86400) {
return [NSString stringWithFormat:@"%.f小时前", timeInterval / 3600];
} else if (timeInterval < 2592000) {//30天内
return [NSString stringWithFormat:@"%.f天前", timeInterval / 86400];
} else if (timeInterval < 31536000) {//30天至1年内
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"M月d日"];
return [dateFormatter stringFromDate:self];
} else {
return [NSString stringWithFormat:@"%.f年前", timeInterval / 31536000];
}
}
/*精确到分钟的日期描述*/
- (NSString *)minuteDescription {
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyy-MM-dd"];
NSString *theDay = [dateFormatter stringFromDate:self];//日期的年月日
NSString *currentDay = [dateFormatter stringFromDate:[NSDate date]];//当前年月日
if ([theDay isEqualToString:currentDay]) {//当天
[dateFormatter setDateFormat:@"ah:mm"];
return [dateFormatter stringFromDate:self];
} else if ([[dateFormatter dateFromString:currentDay] timeIntervalSinceDate:[dateFormatter dateFromString:theDay]] == 86400) {//昨天
[dateFormatter setDateFormat:@"ah:mm"];
return [NSString stringWithFormat:@"昨天 %@", [dateFormatter stringFromDate:self]];
} else if ([[dateFormatter dateFromString:currentDay] timeIntervalSinceDate:[dateFormatter dateFromString:theDay]] < 86400 * 7) {//间隔一周内
[dateFormatter setDateFormat:@"EEEE ah:mm"];
return [dateFormatter stringFromDate:self];
} else {//以前
[dateFormatter setDateFormat:@"yyyy-MM-dd ah:mm"];
return [dateFormatter stringFromDate:self];
}
}
/*标准时间日期描述*/
- (NSString *)formattedTime {
NSDateFormatter* formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"YYYY-MM-dd"];
NSString * dateNow = [formatter stringFromDate:[NSDate date]];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:[[dateNow substringWithRange:NSMakeRange(8,2)] intValue]];
[components setMonth:[[dateNow substringWithRange:NSMakeRange(5,2)] intValue]];
[components setYear:[[dateNow substringWithRange:NSMakeRange(0,4)] intValue]];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:components]; //今天 0点时间
NSInteger hour = [self hoursAfterDate:date];
NSDateFormatter *dateFormatter = nil;
NSString *ret = @"";
//hasAMPM==TURE为12小时制,否则为24小时制
NSString *formatStringForHours = [NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]];
NSRange containsA = [formatStringForHours rangeOfString:@"a"];
BOOL hasAMPM = containsA.location != NSNotFound;
if (!hasAMPM) { //24小时制
if (hour <= 24 && hour >= 0) {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"HH:mm"];
}else if (hour < 0 && hour >= -24) {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"昨天HH:mm"];
}else {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyy-MM-dd HH:mm"];
}
}else {
if (hour >= 0 && hour <= 6) {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"凌晨hh:mm"];
}else if (hour > 6 && hour <=11 ) {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"上午hh:mm"];
}else if (hour > 11 && hour <= 17) {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"下午hh:mm"];
}else if (hour > 17 && hour <= 24) {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"晚上hh:mm"];
}else if (hour < 0 && hour >= -24){
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"昨天HH:mm"];
}else {
dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyy-MM-dd HH:mm"];
}
}
ret = [dateFormatter stringFromDate:self];
return ret;
}
/*格式化日期描述*/
- (NSString *)formattedDateDescription {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd"];
NSString *theDay = [dateFormatter stringFromDate:self];//日期的年月日
NSString *currentDay = [dateFormatter stringFromDate:[NSDate date]];//当前年月日
NSInteger timeInterval = -[self timeIntervalSinceNow];
if (timeInterval < 60) {
return @"1分钟内";
} else if (timeInterval < 3600) {//1小时内
return [NSString stringWithFormat:@"%ld分钟前", timeInterval / 60];
} else if (timeInterval < 21600) {//6小时内
return [NSString stringWithFormat:@"%ld小时前", timeInterval / 3600];
} else if ([theDay isEqualToString:currentDay]) {//当天
[dateFormatter setDateFormat:@"HH:mm"];
return [NSString stringWithFormat:@"今天 %@", [dateFormatter stringFromDate:self]];
} else if ([[dateFormatter dateFromString:currentDay] timeIntervalSinceDate:[dateFormatter dateFromString:theDay]] == 86400) {//昨天
[dateFormatter setDateFormat:@"HH:mm"];
return [NSString stringWithFormat:@"昨天 %@", [dateFormatter stringFromDate:self]];
} else {//以前
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm"];
return [dateFormatter stringFromDate:self];
}
}
- (double)timeIntervalSince1970InMilliSecond {
double ret;
ret = [self timeIntervalSince1970] * 1000;
return ret;
}
+ (NSDate *)dateWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond {
NSDate *ret = nil;
double timeInterval = timeIntervalInMilliSecond;
// judge if the argument is in secconds(for former data structure).
if(timeIntervalInMilliSecond > 140000000000) {
timeInterval = timeIntervalInMilliSecond / 1000;
}
ret = [NSDate dateWithTimeIntervalSince1970:timeInterval];
return ret;
}
+ (NSString *)dateStringWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond format:(NSString *)format {
NSDate *date = [self dateWithTimeIntervalInMilliSecondSince1970:timeIntervalInMilliSecond];
NSDateFormatter *formatter = [NSDateFormatter defaultDateFormatter];
[formatter setDateFormat:format];
return [formatter stringFromDate:date];
}
+ (NSString *)dateStringWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond {
return [self dateStringWithTimeIntervalInMilliSecondSince1970:timeIntervalInMilliSecond format:@"yyyy-MM-dd HH:mm:ss"];
}
+ (NSString *)formattedTimeFromTimeInterval:(long long)time{
return [[NSDate dateWithTimeIntervalInMilliSecondSince1970:time] formattedTime];
}
#pragma mark Relative Dates
+ (NSDate *) dateWithDaysFromNow:(NSInteger)days {
// Thanks, Jim Morrison
return [[NSDate date] dateByAddingDays:days];
}
+ (NSDate *) dateWithDaysBeforeNow:(NSInteger)days {
// Thanks, Jim Morrison
return [[NSDate date] dateBySubtractingDays:days];
}
+ (NSDate *) dateTomorrow {
return [NSDate dateWithDaysFromNow:1];
}
+ (NSDate *) dateYesterday {
return [NSDate dateWithDaysBeforeNow:1];
}
+ (NSDate *) dateWithHoursFromNow:(NSInteger)dHours {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_HOUR * dHours;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
+ (NSDate *) dateWithHoursBeforeNow:(NSInteger)dHours {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_HOUR * dHours;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
+ (NSDate *) dateWithMinutesFromNow:(NSInteger)dMinutes {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
+ (NSDate *) dateWithMinutesBeforeNow:(NSInteger)dMinutes {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_MINUTE * dMinutes;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
#pragma mark Comparing Dates
- (BOOL) isEqualToDateIgnoringTime:(NSDate *)aDate {
NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate];
return ((components1.year == components2.year) &&
(components1.month == components2.month) &&
(components1.day == components2.day));
}
- (BOOL)isToday {
return [self isEqualToDateIgnoringTime:[NSDate date]];
}
- (BOOL)isTomorrow {
return [self isEqualToDateIgnoringTime:[NSDate dateTomorrow]];
}
- (BOOL)isYesterday {
return [self isEqualToDateIgnoringTime:[NSDate dateYesterday]];
}
// This hard codes the assumption that a week is 7 days
- (BOOL) isSameWeekAsDate: (NSDate *) aDate {
NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate];
// Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week
if (components1.week != components2.week) return NO;
// Must have a time interval under 1 week. Thanks @aclark
return (fabs([self timeIntervalSinceDate:aDate]) < D_WEEK);
}
- (BOOL)isThisWeek {
return [self isSameWeekAsDate:[NSDate date]];
}
- (BOOL)isNextWeek {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_WEEK;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return [self isSameWeekAsDate:newDate];
}
- (BOOL)isLastWeek {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_WEEK;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return [self isSameWeekAsDate:newDate];
}
// Thanks, mspasov
- (BOOL)isSameMonthAsDate:(NSDate *)aDate {
NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:self];
NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:aDate];
return ((components1.month == components2.month) &&
(components1.year == components2.year));
}
- (BOOL)isThisMonth {
return [self isSameMonthAsDate:[NSDate date]];
}
- (BOOL)isSameYearAsDate: (NSDate *)aDate {
NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self];
NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:aDate];
return (components1.year == components2.year);
}
- (BOOL)isThisYear {
// Thanks, baspellis
return [self isSameYearAsDate:[NSDate date]];
}
- (BOOL)isNextYear {
NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self];
NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:[NSDate date]];
return (components1.year == (components2.year + 1));
}
- (BOOL)isLastYear {
NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self];
NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:[NSDate date]];
return (components1.year == (components2.year - 1));
}
- (BOOL)isEarlierThanDate:(NSDate *) aDate {
return ([self compare:aDate] == NSOrderedAscending);
}
- (BOOL)isLaterThanDate:(NSDate *)aDate {
return ([self compare:aDate] == NSOrderedDescending);
}
// Thanks, markrickert
- (BOOL)isInFuture {
return ([self isLaterThanDate:[NSDate date]]);
}
// Thanks, markrickert
- (BOOL)isInPast {
return ([self isEarlierThanDate:[NSDate date]]);
}
#pragma mark Roles
- (BOOL)isTypicallyWeekend {
NSDateComponents *components = [CURRENT_CALENDAR components:NSWeekdayCalendarUnit fromDate:self];
if ((components.weekday == 1) ||
(components.weekday == 7))
return YES;
return NO;
}
- (BOOL)isTypicallyWorkday {
return ![self isTypicallyWeekend];
}
#pragma mark Adjusting Dates
- (NSDate *)dateByAddingDays:(NSInteger)dDays {
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_DAY * dDays;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
- (NSDate *)dateBySubtractingDays:(NSInteger)dDays {
return [self dateByAddingDays: (dDays * -1)];
}
- (NSDate *)dateByAddingHours:(NSInteger)dHours {
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_HOUR * dHours;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
- (NSDate *)dateBySubtractingHours:(NSInteger)dHours {
return [self dateByAddingHours: (dHours * -1)];
}
- (NSDate *)dateByAddingMinutes:(NSInteger)dMinutes {
NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
- (NSDate *)dateBySubtractingMinutes: (NSInteger)dMinutes {
return [self dateByAddingMinutes: (dMinutes * -1)];
}
- (NSDate *)dateAtStartOfDay {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
components.hour = 0;
components.minute = 0;
components.second = 0;
return [CURRENT_CALENDAR dateFromComponents:components];
}
- (NSDateComponents *)componentsWithOffsetFromDate:(NSDate *)aDate {
NSDateComponents *dTime = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate toDate:self options:0];
return dTime;
}
#pragma mark Retrieving Intervals
- (NSInteger)minutesAfterDate:(NSDate *)aDate {
NSTimeInterval ti = [self timeIntervalSinceDate:aDate];
return (NSInteger) (ti / D_MINUTE);
}
- (NSInteger)minutesBeforeDate:(NSDate *)aDate {
NSTimeInterval ti = [aDate timeIntervalSinceDate:self];
return (NSInteger) (ti / D_MINUTE);
}
- (NSInteger) hoursAfterDate:(NSDate *)aDate {
NSTimeInterval ti = [self timeIntervalSinceDate:aDate];
return (NSInteger) (ti / D_HOUR);
}
- (NSInteger) hoursBeforeDate: (NSDate *) aDate
{
NSTimeInterval ti = [aDate timeIntervalSinceDate:self];
return (NSInteger) (ti / D_HOUR);
}
- (NSInteger)daysAfterDate:(NSDate *)aDate {
NSTimeInterval ti = [self timeIntervalSinceDate:aDate];
return (NSInteger) (ti / D_DAY);
}
- (NSInteger)daysBeforeDate:(NSDate *)aDate {
NSTimeInterval ti = [aDate timeIntervalSinceDate:self];
return (NSInteger) (ti / D_DAY);
}
// Thanks, dmitrydims
// I have not yet thoroughly tested this
- (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate {
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components:NSDayCalendarUnit fromDate:self toDate:anotherDate options:0];
return components.day;
}
#pragma mark Decomposing Dates
- (NSInteger)nearestHour {
NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * 30;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
NSDateComponents *components = [CURRENT_CALENDAR components:NSHourCalendarUnit fromDate:newDate];
return components.hour;
}
- (NSInteger)hour {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.hour;
}
- (NSInteger)minute {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.minute;
}
- (NSInteger)seconds {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.second;
}
- (NSInteger)day {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.day;
}
- (NSInteger)month {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.month;
}
- (NSInteger)week {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.week;
}
- (NSInteger)weekday {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.weekday;
}
- (NSInteger)nthWeekday { // e.g. 2nd Tuesday of the month is 2{
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.weekdayOrdinal;
}
- (NSInteger)year {
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
return components.year;
}
@end
/************************************************************
* * EaseMob CONFIDENTIAL
* __________________
* Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of EaseMob Technologies.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from EaseMob Technologies.
*/
#import <Foundation/Foundation.h>
@interface NSDateFormatter (Category)
+ (id)dateFormatter;
+ (id)dateFormatterWithFormat:(NSString *)dateFormat;
+ (id)defaultDateFormatter;/*yyyy-MM-dd HH:mm:ss*/
@end
/************************************************************
* * EaseMob CONFIDENTIAL
* __________________
* Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of EaseMob Technologies.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from EaseMob Technologies.
*/
#import "NSDateFormatter+Category.h"
@implementation NSDateFormatter (Category)
+ (id)dateFormatter
{
return [[self alloc] init];
}
+ (id)dateFormatterWithFormat:(NSString *)dateFormat
{
NSDateFormatter *dateFormatter = [[self alloc] init];
dateFormatter.dateFormat = dateFormat;
return dateFormatter;
}
+ (id)defaultDateFormatter
{
return [self dateFormatterWithFormat:@"yyyy-MM-dd HH:mm:ss"];
}
@end
//
// NSDictionary+GM.h
// Gengmei
//
// Created by Mikasa on 2019/8/8.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface NSDictionary (GM)
- (BOOL)dictContainsKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END
//
// NSDictionary+GM.m
// Gengmei
//
// Created by Mikasa on 2019/8/8.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "NSDictionary+GM.h"
@implementation NSDictionary (GM)
- (BOOL)dictContainsKey:(NSString *)key {
if ([self.allKeys containsObject:key]) {
return YES;
}
return NO;
}
@end
//
// NSDictionary+json.h
// Gengmei
//
// Created by Q14 on 2019/5/8.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSDictionary (json)
/**
* JSON字符串转NSDictionary
*
* @param jsonString JSON字符串
*
* @return NSDictionary
*/
+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString;
/**
* 字典转JSON字符串
*
* @param dic 字典
*
* @return JSON字符串
*/
+ (NSString *)dictionaryToJson:(NSDictionary *)dic;
@end
NS_ASSUME_NONNULL_END
//
// NSDictionary+json.m
// Gengmei
//
// Created by Q14 on 2019/5/8.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "NSDictionary+json.h"
@implementation NSDictionary (json)
/**
* JSON字符串转NSDictionary
*
* @param jsonString JSON字符串
*
* @return NSDictionary
*/
+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
if (jsonString == nil) {
return nil;
}
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
if(error) {
NSLog(@"json解析失败:%@",error);
return nil;
}
return dic;
}
/**
* 字典转JSON字符串
*
* @param dic 字典
*
* @return JSON字符串
*/
+ (NSString *)dictionaryToJson:(NSDictionary *)dic {
NSError *parseError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
@end
//
// NSJSONSerialization+GM.swift
// Gengmei
//
// Created by licong on 16/8/25.
// Copyright © 2016年 更美互动信息科技有限公司. All rights reserved.
//
import Foundation
@objc public extension JSONSerialization {
class func JSONString(_ object: AnyObject) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: object, options: .prettyPrinted),
let string = String(data: data, encoding: String.Encoding.utf8) else { return nil }
return string
}
}
//
// NSMutableAttributedString+Attachment.h
// Gengmei
//
// Created by wangyang on 2018/8/7.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSMutableAttributedString (Attachment)
/**
需求:http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=9767058#space-menu-link-content
一些卡片标题有置顶标识。
*/
- (void)addFeedIsTopAttachment;
/**
http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=11609153
*/
- (void)addDiaryMatchAttachment;
/**
标题前方添加标识(默认为拼团)
*/
- (NSAttributedString *)addGroupBuyIsFrontAttachment:(NSString *)iconName;
- (NSAttributedString *)addGroupBuyIsFrontAttachment:(NSString *)iconName attachmentBounds:(CGRect)attachmentBounds;
@end
//
// NSMutableAttributedString+Attachment.m
// Gengmei
//
// Created by wangyang on 2018/8/7.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import "NSMutableAttributedString+Attachment.h"
#import "NSString+GM.h"
@implementation NSMutableAttributedString (Attachment)
- (void)addFeedIsTopAttachment {
NSTextAttachment* textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:@"feed_is_top"];
textAttachment.bounds = CGRectMake(0, -1, 13, 13); // 微调图片位置
NSAttributedString *imageAttachment = [NSAttributedString attributedStringWithAttachment:textAttachment];
// 给最后一个字符尾部添加字符水平间距,以符合设计要求:箭头与文字的间距为8个点
[self addAttribute:NSKernAttributeName value:@(8) range:NSMakeRange(self.string.length - 1, 1)];
[self insertAttributedString:imageAttachment atIndex:self.string.length];
}
- (void)addDiaryMatchAttachment {
NSTextAttachment* textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:@"diary_match"];//diary_match//feed_is_top
textAttachment.bounds = CGRectMake(0, -2, 31, 16); // 微调图片位置
NSAttributedString *imageAttachment = [NSAttributedString attributedStringWithAttachment:textAttachment];
// 给最后一个字符尾部添加字符水平间距,以符合设计要求:箭头与文字的间距为8个点
[self addAttribute:NSKernAttributeName value:@(8) range:NSMakeRange(self.string.length - 1, 1)];
[self insertAttributedString:imageAttachment atIndex:self.string.length];
}
- (NSAttributedString *)addGroupBuyIsFrontAttachment:(NSString *)iconName {
[self addGroupBuyIsFrontAttachment:iconName attachmentBounds:CGRectMake(0, -1, 25, 13)];
// [self addAttribute:NSKernAttributeName value:@(20) range:NSMakeRange(0, 1)];
return self;
}
- (NSAttributedString *)addGroupBuyIsFrontAttachment:(NSString *)iconName attachmentBounds:(CGRect)attachmentBounds {
NSMutableAttributedString *textAttrStr = [[NSMutableAttributedString alloc] init];
NSTextAttachment* textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = [UIImage imageNamed:iconName.isNonEmpty ? iconName : @"groupBuy_icon"];
textAttachment.bounds = CGRectMake(attachmentBounds.origin.x, attachmentBounds.origin.y, attachmentBounds.size.width, attachmentBounds.size.height); // 微调图片位置
NSAttributedString *imageAttachment = [NSAttributedString attributedStringWithAttachment:textAttachment];
[textAttrStr appendAttributedString:imageAttachment];
//标签后添加空格
[textAttrStr appendAttributedString:[[NSAttributedString alloc] initWithString:@" "]];
// 给最后一个字符尾部添加字符水平间距,以符合设计要求:箭头与文字的间距为8个点
[self insertAttributedString:textAttrStr atIndex:0];
return self;
}
@end
//
// NSObject+GMDate.h
// Gengmei
//
// Created by lizhen on 2019/2/15.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#include <mach/mach_time.h>
@interface NSObject (GMDate)
/** NSDate->时间戳 */
- (CGFloat)getDateTime:(NSDate *)Date;
/** NSDate->时间字符串 */
- (NSString *)getDateToString:(NSDate *)Date;
/** 时间戳->字符串 */
- (NSString *)getDateStringWithTimeStr:(float)time;
/** 字符串时间—>时间戳 */
- (CGFloat)timeStringToTimeFloat:(NSString *)time;
/** 计算两个 NSDate 相差天数 */
- (NSString *)getTimeFrom:(NSDate *)fromDate to:(NSDate *)toDate;
/** 字符串->日期 */
- (NSDate *)getDateWithString:(NSString *)str;
/** 时间戳->NSDate */
- (NSDate *)getDateWithFloat:(float)time;
uint64_t GetPIDTimeInNanoseconds(uint64_t start,uint64_t end);
@end
//
// NSObject+GMDate.m
// Gengmei
//
// Created by lizhen on 2019/2/15.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "NSObject+GMDate.h"
#include <assert.h>
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <unistd.h>
@implementation NSObject (GMDate)
#pragma mark - NSDate转化为时间戳
- (CGFloat)getDateTime:(NSDate *)Date {
//获取选择的时间戳
NSDate *date = [Date dateByAddingTimeInterval:0];
NSTimeInterval time = [date timeIntervalSince1970];// *1000 是精确到毫秒,不乘就是精确到秒
return time;
}
#pragma mark - NSDate->时间字符串
- (NSString *)getDateToString:(NSDate *)Date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// 设定时间格式,这里可以设置成自己需要的格式
[formatter setDateFormat:@"yyyy/MM/dd"];
NSString *time = [formatter stringFromDate:Date];
return time;
}
#pragma mark - 时间戳转字符串
- (NSString *)getDateStringWithTimeStr:(float)time {
// 时间戳转时间,时间戳为13位是精确到毫秒的,10位精确到秒
NSDate *detailDate = [NSDate dateWithTimeIntervalSince1970:time];
NSString *currentDateStr = [self getDateToString:detailDate];
return currentDateStr;
}
#pragma mark - 字符串时间—>时间戳
- (CGFloat)timeStringToTimeFloat:(NSString *)time {
// 转换为时间戳
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy/MM/dd"];
NSDate *date = [formatter dateFromString:time];
return [self getDateTime:date];
}
#pragma mark - 计算两个 NSDate 相差天数
- (NSString *)getTimeFrom:(NSDate *)fromDate to:(NSDate *)toDate {
//计算两个中间差值(秒)
NSTimeInterval time = [toDate timeIntervalSinceDate:fromDate];
//开始时间和结束时间的中间相差的时间
int days;
days = ((int)time)/(3600*24); //一天是24小时*3600秒
NSString *dateValue = [NSString stringWithFormat:@"%i",days];
return dateValue;
}
#pragma mark - 字符串转日期
- (NSDate *)getDateWithString:(NSString *)str {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy/MM/dd";
[dateFormatter setMonthSymbols:[NSArray arrayWithObjects:@"01",@"02",@"03",@"04",@"05",@"06",@"07",@"08",@"09",@"10",@"11",@"12", nil]];
NSDate * ValueDate = [dateFormatter dateFromString:str];
return ValueDate;
}
#pragma mark - 时间戳->NSDate
- (NSDate *)getDateWithFloat:(float)time {
if (time <= 0) {
return nil;
}
NSString *timeStr = [self getDateStringWithTimeStr:time];
NSDate *date = [self getDateWithString:timeStr];
return date;
}
uint64_t GetPIDTimeInNanoseconds(uint64_t start,uint64_t end)
{
uint64_t elapsed;
uint64_t elapsedNano;
static mach_timebase_info_data_t sTimebaseInfo;
// Start the clock.
// start = mach_absolute_time();
// Call getpid. This will produce inaccurate results because
// we're only making a single system call. For more accurate
// results you should call getpid multiple times and average
// the results.
(void) getpid();
// Stop the clock.
// end = mach_absolute_time();
// Calculate the duration.
elapsed = end - start;
// Convert to nanoseconds.
// If this is the first time we've run, get the timebase.
// We can use denom == 0 to indicate that sTimebaseInfo is
// uninitialised because it makes no sense to have a zero
// denominator is a fraction.
if ( sTimebaseInfo.denom == 0 ) {
(void) mach_timebase_info(&sTimebaseInfo);
}
// Do the maths. We hope that the multiplication doesn't
// overflow; the price you pay for working in fixed point.
elapsedNano = elapsed * sTimebaseInfo.numer / sTimebaseInfo.denom;
return elapsedNano/1000000;
}
@end
//
// NSString+Base64.h
// GMAlpha
//
// Created by ioszhb on 2019/1/18.
// Copyright © 2019 Gengmei. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (Base64)
- (NSString *)encodeString:(NSString *)string;
- (NSString *)decodeString:(NSString *)string;
//base64编码
- (NSString *)str_base64Encode;
//base64解码
- (NSString *)str_base64Decode;
@end
NS_ASSUME_NONNULL_END
//
// NSString+Base64.m
// GMAlpha
//
// Created by ioszhb on 2019/1/18.
// Copyright © 2019 Gengmei. All rights reserved.
//
#import "NSString+Base64.h"
@implementation NSString (Base64)
//base64编码
- (NSString *)encodeString:(NSString *)string
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSString *encodedStr = [data base64EncodedStringWithOptions:0];
return encodedStr;
}
//base64解码
- (NSString *)decodeString:(NSString *)string
{
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
NSString *decodedStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return decodedStr;
}
//base64编码
- (NSString *)str_base64Encode
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
NSString *encodedStr = [data base64EncodedStringWithOptions:0];
return encodedStr;
}
//base64解码
- (NSString *)str_base64Decode
{
NSData *data = [[NSData alloc] initWithBase64EncodedString:self options:0];
NSString *decodedStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return decodedStr;
}
@end
//
// NSString+IconFont.h
// Gengmei
//
// Created by lizhen on 2018/5/25.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (IconFont)
/**
替换字符串中指定字体为iconfont
@param oldString 要替换的字符串
@param newString 替换后的字符串
@param font 文字字体
@param textColor 文字颜色
@param lineSpace 行间距
*/
- (NSMutableAttributedString *)replaceString:(NSArray<NSString *> *)oldArray
withStrings:(NSArray<NSString *> *)newArray
font:(UIFont *)font
textColor:(UIColor *)textColor
lineSpace:(NSInteger)lineSpace;
@end
@interface NSString (IconFontFactory)
// 美购详情页中使用
- (NSMutableAttributedString *)welfareDetailNameWithFontSize:(NSInteger)size
textColor:(UIColor *)textColor;
// 其它各处的美购标题使用
- (NSMutableAttributedString *)welfareNameWithFontSize:(NSInteger)size
textColor:(UIColor *)textColor
lineSpace:(NSInteger)lineSpace;
- (NSMutableAttributedString *)customDetailNameWithFontSize:(UIFont *)font
textColor:(UIColor *)textColor
lineSpace:(NSInteger)lineSpace;
@end
//
// NSString+IconFont.m
// Gengmei
//
// Created by lizhen on 2018/5/25.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import "NSString+IconFont.h"
#import "NSAttributedString+GMSize.h"
#define RGBFCOLOR_HEX(hexColor) [UIColor colorWithRed: (((hexColor >> 16) & 0xFF))/255.0f \
green: (((hexColor >> 8) & 0xFF))/255.0f \
blue: ((hexColor & 0xFF))/255.0f \
alpha: 1]
@implementation NSString (IconFont)
- (NSMutableAttributedString *)replaceString:(NSArray<NSString *> *)oldArray
withStrings:(NSArray<NSString *> *)newArray
font:(UIFont *)font
textColor:(UIColor *)textColor
lineSpace:(NSInteger)lineSpace {
NSString *contentString = [self copy];
NSMutableArray *rangeArray = [NSMutableArray array];
for (NSInteger i = 0; i < oldArray.count; i++) {
NSInteger number = [[self mutableCopy] replaceOccurrencesOfString:oldArray[i] withString:newArray[i] options:NSCaseInsensitiveSearch range:NSMakeRange(0, self.length)];
NSRange range = NSMakeRange(0, 0);
for (NSInteger j = 0; j < number; j++) {
if ([contentString containsString:oldArray[i]]) {
//记录range,为替换成icomoon
range = [contentString rangeOfString:oldArray[i]];
contentString = [contentString stringByReplacingOccurrencesOfString:oldArray[i] withString:newArray[i] options:NSCaseInsensitiveSearch range:range];
NSValue *value = [NSValue valueWithRange:range];
[rangeArray addObject:value];
}
}
}
NSDictionary *attributeDic = @{NSForegroundColorAttributeName: textColor, NSFontAttributeName: font};
NSMutableAttributedString *content = [[NSMutableAttributedString alloc] initWithString:contentString attributes:attributeDic];
for (NSInteger k = 0; k < rangeArray.count; k++) {
//通过range遍历, 替换为icomoon
[content setAttributes:@{NSFontAttributeName : [UIFont fontWithName:@"icomoon" size:font.pointSize]} range:[rangeArray[k] rangeValue]];
}
[content addLineSpace:lineSpace];
return content;
}
@end
// BRACKETS 即 brackets,中括号的意思
#define CHINESE_BRACKETS @[@"【", @"】"]
#define ICON_FONT_BRACKETS @[@"\U0000e901", @"\U0000e902"]
@implementation NSString (IconFontFactory)
- (NSMutableAttributedString *)welfareDetailNameWithFontSize:(NSInteger)size
textColor:(UIColor *)textColor {
NSMutableAttributedString *content = [self replaceString:CHINESE_BRACKETS
withStrings:ICON_FONT_BRACKETS
font:[UIFont fontWithName:@"PingFangSC-Medium" size:size]
textColor:textColor ?: RGBFCOLOR_HEX(0x282828)
lineSpace:0];
return content;
}
- (NSMutableAttributedString *)welfareNameWithFontSize:(NSInteger)size
textColor:(UIColor *)textColor
lineSpace:(NSInteger)lineSpace {
NSMutableAttributedString *content = [self replaceString:CHINESE_BRACKETS withStrings:ICON_FONT_BRACKETS font:[UIFont fontWithName:@"PingFangSC-Regular" size:size] textColor:textColor ?: RGBFCOLOR_HEX(0x282828) lineSpace:lineSpace];
return content;
}
- (NSMutableAttributedString *)customDetailNameWithFontSize:(UIFont *)font
textColor:(UIColor *)textColor
lineSpace:(NSInteger)lineSpace {
NSMutableAttributedString *content = [self replaceString:CHINESE_BRACKETS withStrings:ICON_FONT_BRACKETS font:font textColor:textColor ?: RGBFCOLOR_HEX(0x282828) lineSpace:lineSpace];
return content;
}
@end
//
// NSString+RegularString.h
// Gengmei
//
// Created by 汪俊 on 2018/2/1.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (RegularString)
- (NSString *)regularPattern:(NSArray *)keys;
/** 数量转换 */
- (NSString *)numberToString;
/** 转换
<1w,显示具体数字
>=1w,显示1w+
以每一w为单位递增2w+、3w+、4w+
*/
- (NSString *)numberToWString;
/** 转换
<=99,显示具体数字
>99,显示99+
*/
- (NSString *)numberTo99String;
@end
//
// NSString+RegularString.m
// Gengmei
//
// Created by 汪俊 on 2018/2/1.
// Copyright © 2018年 更美互动信息科技有限公司. All rights reserved.
//
#import "NSString+RegularString.h"
@implementation NSString (RegularString)
/**
关键字 正则判断
*/
- (NSString *)regularPattern:(NSArray *)keys{
NSMutableString *pattern = [[NSMutableString alloc]initWithString:@"(?i)"];
for (NSString *key in keys) {
[pattern appendFormat:@"%@|",key];
}
return pattern;
}
- (NSString *)numberToString {
NSInteger num = self.integerValue;
if (num > 0 && num < 10000) {
return self;
} else if (num >= 10000) {
return [NSString stringWithFormat:@"%ld.%.0f万", num / 10000, ceilf(num % 10000 / 1000.0)];
} else {
return @"0";
}
}
- (NSString *)numberToWString {
NSInteger num = self.integerValue;
if (num > 0 && num < 10000) {
return self;
} else if (num >= 10000) {
return [NSString stringWithFormat:@"%ldw+", num / 10000];
} else {
return @"";
}
}
- (NSString *)numberTo99String {
NSInteger num = self.integerValue;
if (num > 0 && num < 100) {
return self;
} else if (num > 99) {
return [NSString stringWithFormat:@"99+"];
} else {
return @"";
}
}
@end
//
// String+GM.swift
// Gengmei
//
// Created by wangyang on 2017/12/21.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import Foundation
// MARK: - 字符串截取
extension String {
// 截取字符串从开始到index
func substring(to index: Int) -> String {
guard let end_Index = validEndIndex(original: index) else {
return self
}
return String(self[startIndex..<end_Index])
}
// 截取字符串从index到结束
func substring(from index: Int) -> String {
guard let start_index = validStartIndex(original: index) else {
return self
}
return String(self[start_index..<endIndex])
}
// 切割字符串(区间范围 前闭后开)
func sliceString(_ range: CountableRange<Int>) -> String {
guard
let startIndex = validStartIndex(original: range.lowerBound),
let endIndex = validEndIndex(original: range.upperBound),
startIndex <= endIndex
else {
return ""
}
return String(self[startIndex..<endIndex])
}
// 切割字符串(区间范围 前闭后闭)
func sliceString(_ range: CountableClosedRange<Int>) -> String {
guard
let start_Index = validStartIndex(original: range.lowerBound),
let end_Index = validEndIndex(original: range.upperBound),
startIndex <= endIndex
else {
return ""
}
if endIndex.encodedOffset <= end_Index.encodedOffset {
return String(self[start_Index..<endIndex])
}
return String(self[start_Index...end_Index])
}
// 校验字符串位置 是否合理,并返回String.Index
func validIndex(original: Int) -> String.Index {
switch original {
case ...startIndex.encodedOffset : return startIndex
case endIndex.encodedOffset... : return endIndex
default : return index(startIndex, offsetBy: original)
}
}
// 校验是否是合法的起始位置
func validStartIndex(original: Int) -> String.Index? {
guard original <= endIndex.encodedOffset else { return nil }
return validIndex(original: original)
}
// 校验是否是合法的结束位置
func validEndIndex(original: Int) -> String.Index? {
guard original >= startIndex.encodedOffset else { return nil }
return validIndex(original: original)
}
}
//
// CIContext+fixBug.h
// Gengmei
//
// Created by Terminator on 2017/7/31.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import <CoreImage/CoreImage.h>
//在swift3.0 iOS8系统下 CIContext(options: nil) 会crash 因此加了一个类别
@interface CIContext (fixBug)
+ (CIContext *)swiftContextWithOptions:(NSDictionary<NSString *, id> *)options;
@end
//
// CIContext+fixBug.m
// Gengmei
//
// Created by Terminator on 2017/7/31.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import "CIContext+fixBug.h"
@implementation CIContext (fixBug)
+ (CIContext *)swiftContextWithOptions:(NSDictionary<NSString *, id> *)options {
return [CIContext contextWithOptions:options];
}
@end
//
// NSString+Image.h
// Gengmei
//
// Created by Mikasa on 2019/7/4.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
#define kGMSeparator @"-" //分隔符
#define IMAGE_URL_FORMAT_828x1792 @"828x1792_75"
#define IMAGE_URL_FORMAT_1242x2688 @"1242x2688_75"
#define IMAGE_URL_FORMAT_414x896 @"414x896_75"
#define IMAGE_URL_FORMAT_626x1344 @"626x1344_75"
#define IMAGE_URL_FORMAT_279x597 @"279x597_75"
#define IMAGE_URL_FORMAT_207x448 @"207x448_75"
#define IMAGE_URL_FORMAT_310x672 @"310x672_75"
#define IMAGE_URL_FORMAT_300x300_75 @"300x300_75"
#define IMAGE_URL_FORMAT_200x200_75 @"200x200_75"
@interface NSString (Image)
/**
* 适用于单栏展示图片
@return 适用于单栏展示图片
*/
- (NSString *)singleColumn;
/**
* 适用于双栏展示图片
@return 双栏展示图片地址
*/
- (NSString *)doubleColumn;
/**
* 适用于三栏展示图片
@return 三栏展示图片地址
*/
- (NSString *)threeColumn;
/**
* 适用于四栏展示图片
@return 四栏展示图片地址
*/
- (NSString *)fourColumn;
/**
* thumbnail
@return thumbnail图片地址
*/
- (NSString *)thumbnail;
@end
NS_ASSUME_NONNULL_END
//
// NSString+Image.m
// Gengmei
//
// Created by Mikasa on 2019/7/4.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "NSString+Image.h"
#import "UIScreen+GM.h"
@implementation NSString (Image)
/**
* 适用于单栏展示图片
@return 适用于单栏展示图片
*/
- (NSString *)singleColumn {
return [self stringByAppendingFormat:@"%@%@",kGMSeparator,[UIScreen isThreeScale]?IMAGE_URL_FORMAT_1242x2688:IMAGE_URL_FORMAT_828x1792];
}
/**
* 适用于双栏展示图片
@return 双栏展示图片地址
*/
- (NSString *)doubleColumn {
return [self stringByAppendingFormat:@"%@%@",kGMSeparator,[UIScreen isThreeScale]?IMAGE_URL_FORMAT_414x896:IMAGE_URL_FORMAT_279x597];
}
/**
* 适用于三栏展示图片
@return 三栏展示图片地址
*/
- (NSString *)threeColumn {
return [self stringByAppendingFormat:@"%@%@",kGMSeparator,[UIScreen isThreeScale]?IMAGE_URL_FORMAT_414x896:IMAGE_URL_FORMAT_279x597];
}
/**
* 适用于四栏展示图片
@return 四栏展示图片地址
*/
- (NSString *)fourColumn {
return [self stringByAppendingFormat:@"%@%@",kGMSeparator,[UIScreen isThreeScale]?IMAGE_URL_FORMAT_310x672:IMAGE_URL_FORMAT_207x448];
}
/**
* thumbnail
@return thumbnail图片地址
*/
- (NSString *)thumbnail {
return [self stringByAppendingFormat:@"%@%@",kGMSeparator,[UIScreen isThreeScale]?IMAGE_URL_FORMAT_300x300_75:IMAGE_URL_FORMAT_200x200_75];
}
@end
//
// UIButton+ALReClicks.h
// GMAlpha
//
// Created by zhouLiang on 2019/4/4.
// Copyright © 2019 Gengmei. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIButton (ALReClicks)
/**
重复点击的间隔 大于 0 的时候才进行控制
默认值为2s
*/
@property (nonatomic, assign) NSTimeInterval multiControlTimeInterva;
/**
上次点击的时间 外界不使用
*/
@property (nonatomic, assign) NSTimeInterval cs_acceptEventTime;
@end
//
// UIButton+ALReClicks.m
// GMAlpha
//
// Created by zhouLiang on 2019/4/4.
// Copyright © 2019 Gengmei. All rights reserved.
//
#import "UIButton+ALReClicks.h"
#import <objc/runtime.h>
@implementation UIButton (ALReClicks)
static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
static const char *UIControl_acceptEventTime = "UIControl_acceptEventTime";
- (NSTimeInterval)multiControlTimeInterva {
return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
}
- (void)setMultiControlTimeInterva:(NSTimeInterval)multiControlTimeInterva {
objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(multiControlTimeInterva), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSTimeInterval)cs_acceptEventTime {
return [objc_getAssociatedObject(self, UIControl_acceptEventTime) doubleValue];
}
- (void)setCs_acceptEventTime:(NSTimeInterval)cs_acceptEventTime {
objc_setAssociatedObject(self, UIControl_acceptEventTime, @(cs_acceptEventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if (self.multiControlTimeInterva == 0) {
self.multiControlTimeInterva = 0;
}
if (self.multiControlTimeInterva > 0) {
if ([NSDate date].timeIntervalSince1970 - self.cs_acceptEventTime < self.multiControlTimeInterva) {
return;
}
self.cs_acceptEventTime = [NSDate date].timeIntervalSince1970;
}
[super sendAction:action to:target forEvent:event];
}
@end
//
// UIButton+GM.h
// Gengmei
//
// Created by Mikasa on 2019/8/1.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIButton (GM)
@end
NS_ASSUME_NONNULL_END
//
// UIButton+GM.m
// Gengmei
//
// Created by Mikasa on 2019/8/1.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "UIButton+GM.h"
@implementation UIButton (GM)
- (void)highlightedClick:(UIButton *)button {
button.highlighted = NO;
}
@end
//
// UIScreen+GM.h
// Gengmei
//
// Created by Mikasa on 2019/7/4.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface UIScreen (GM)
+ (BOOL)isThreeScale;
@end
NS_ASSUME_NONNULL_END
//
// UIScreen+GM.m
// Gengmei
//
// Created by Mikasa on 2019/7/4.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "UIScreen+GM.h"
@implementation UIScreen (GM)
+ (BOOL)isThreeScale {
CGFloat scale = [UIScreen mainScreen].scale;
if (ABS(scale-3) <= 0.001) {
return YES;
} else {
return NO;
}
}
@end
//
// UIView+GMShadow.h
// Gengmei
//
// Created by lizhen on 2019/3/20.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (GMShadow)
/**
设置四边阴影效果
@param shadowColor 阴影颜色
@param shadowOpacity 阴影透明度
@param shadowRadius 阴影半径
@param shadowOffset 阴影偏移
*/
- (void)addShadow:(UIColor *)shadowColor
shadowOpacity:(CGFloat)shadowOpacity
shadowRadius:(CGFloat)shadowRadius
shadowOffset:(CGSize)shadowOffset;
/**
设置单边阴影效果
@param shadowColor 阴影颜色
@param shadowOpacity 阴影透明度
@param shadowRadius 阴影半径
@param shadowOffset 阴影偏移
@param shdowFrame 单边阴影
*/
- (void)addShadow:(UIColor *)shadowColor
shadowOpacity:(CGFloat)shadowOpacity
shadowRadius:(CGFloat)shadowRadius
shadowOffset:(CGSize)shadowOffset
shadowFrame:(CGRect)shadowFrame;
@end
//
// UIView+GMShadow.m
// Gengmei
//
// Created by lizhen on 2019/3/20.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "UIView+GMShadow.h"
@implementation UIView (GMShadow)
#pragma mark - 设置四边阴影效果
- (void)addShadow:(UIColor *)shadowColor
shadowOpacity:(CGFloat)shadowOpacity
shadowRadius:(CGFloat)shadowRadius
shadowOffset:(CGSize)shadowOffset {
self.layer.shadowColor = shadowColor.CGColor;
self.layer.shadowOffset = shadowOffset;
self.layer.shadowOpacity = shadowOpacity;
self.layer.shadowRadius = shadowRadius;
}
#pragma mark - 设置单边阴影效果
- (void)addShadow:(UIColor *)shadowColor shadowOpacity:(CGFloat)shadowOpacity shadowRadius:(CGFloat)shadowRadius shadowOffset:(CGSize)shadowOffset shadowFrame:(CGRect)shadowFrame {
self.layer.shadowColor = shadowColor.CGColor;
self.layer.shadowOffset = shadowOffset;
self.layer.shadowOpacity = shadowOpacity;
self.layer.shadowRadius = shadowRadius;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:shadowFrame];
self.layer.shadowPath = path.CGPath;
}
@end
//
// GMTableViewCell+Layout.h
// Gengmei
//
// Created by wangyang on 2017/7/19.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#define EDGE 20.0
#define CONTENT_WIDTH [GMTableViewCell contentWidth]
#define MARGIN_TOP 15
#define MARGIN_BOTTOM 20.5
#define TITLE_LINESPACING 0 // title/content行间距
#define MARGIN_TITLE_VIDEO 15 // title与视频(一张大图)间距
#define MARGIN_CONTENT_VIDEO 16 // content与视频(一张大图)间距
#define MARGIN_TITLE_CONTENT 4
#define MARGIN_USERINFO_CONTENT 12 // userInfoView与content间距/userInfoView与title间距
#define MARGIN_USERINFO_IMAGE 16 // userInfoView与图片间距
#define IMAGE_TOP 20
#define IMAGE_WIDTH 155
#define TITLE_SIZE 18
#define CONTENT_SIZE 14
#define TITLE_MAXHEIGHT 76
#define CONTENT_MAXHEIGHT 40
#define TITLE_RIGHT_IMAGE 12
#import "GMTableViewCell.h"
@interface GMTableViewCell (Layout)
+ (CGSize)cellImageSize;
+ (CGFloat)contentWidth;
- (void)useEdgeBottomLine;
@end
//
// GMTableViewCell+Layout.m
// Gengmei
//
// Created by wangyang on 2017/7/19.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import "GMTableViewCell+Layout.h"
#import <Masonry/Masonry.h>
#define IMAGE_COUNT 3
#define IMAGE_SPACE 10
@implementation GMTableViewCell (Layout)
+ (CGSize)cellImageSize {
CGFloat imageWidth = ceil(([self contentWidth] - (IMAGE_COUNT - 1 ) * IMAGE_SPACE) / IMAGE_COUNT);
CGFloat imageHeight = imageWidth;
return CGSizeMake(imageWidth, imageHeight);
}
+ (CGFloat)contentWidth {
return UIScreen.mainScreen.bounds.size.width - EDGE * 2;
}
- (void)useEdgeBottomLine {
[self.bottomLine mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(20);
make.right.mas_equalTo(-20);
}];
[self.contentView bringSubviewToFront:self.bottomLine];
}
@end
//
// NSObject+EasySubClass.h
// Gengmei
//
// Created by wangyang on 2019/9/5.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
利用运行时创建 subclass,以方便调试 UI 时区分基础的 UIView,UILabel 等基础视图
*/
@interface NSObject (EasySubClass)
+ (instancetype)initWithSubclassName:(NSString *)clsName;
@end
NS_ASSUME_NONNULL_END
//
// NSObject+EasySubClass.m
// Gengmei
//
// Created by wangyang on 2019/9/5.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "NSObject+EasySubClass.h"
#import <objc/runtime.h>
@implementation NSObject (EasySubClass)
+ (instancetype)initWithSubclassName:(NSString *)clsName {
const char *subclassName = clsName.UTF8String;
Class subclass = objc_getClass(subclassName);
if (subclass == nil) {
subclass = objc_allocateClassPair(self, subclassName, 0);
if (subclass == nil) {
return [self new];
}
objc_registerClassPair(subclass);
}
return [subclass new];
}
@end
//
// UIAlertController+GM.swift
// GMKit
//
// Created by wangyang on 16/7/7.
// Copyright © 2016年 licong. All rights reserved.
//
import Foundation
// 因为
@objc public extension UIAlertController {
@objc static func showOKAlert(withTitle title: String?, message: String? = nil, actionTitle: String = "好", actionHandler: (() -> Void)? = nil) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: actionTitle, style: .default) { (_) in
actionHandler?()
}
alert.addAction(action)
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
}
@objc static func showCustomAlert(withTitle title: String?, message: String?) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
return alert
}
@objc static func showCustomActionSheet(withTitle title: String?, message: String?) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
return alert
}
@objc func addAction(_ title: String, actionHandler:(() -> Void)?) {
let action = UIAlertAction(title: title, style: .default) { (_) in
actionHandler?()
}
addAction(action)
}
@objc static func alert(_ title: String, leftTitle: String?, rightTitle: String?, leftAlterAction: (() -> Void)?, rightAlertAction: (() -> Void)?) -> UIAlertController {
let alertController = UIAlertController(title: title, message: "", preferredStyle: UIAlertController.Style.alert)
var leftAction: UIAlertAction
var rightAction: UIAlertAction
if let leftTitle = leftTitle {
leftAction = UIAlertAction(title: leftTitle, style: UIAlertAction.Style.default) { (_) -> Void in
if let action = leftAlterAction { action() }
}
alertController.addAction(leftAction)
}
if let rightTitle = rightTitle {
rightAction = UIAlertAction(title: rightTitle, style: UIAlertAction.Style.default) { (_) -> Void in
if let action = rightAlertAction { action() }
}
alertController.addAction(rightAction)
}
return alertController
}
}
//
// UIImage+Extension.swift
// Gengmei
//
// Created by 汪俊 on 2017/2/15.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import Foundation
@objc public extension UIImage {
/// 转为和屏幕scale一致的image
func screenScaleImage() -> UIImage? {
guard let imageData = self.pngData() else { return nil }
guard let scaleImage = UIImage(data: imageData, scale: UIScreen.main.scale) else { return nil }
return scaleImage
}
}
//
// UIImage+GIFImages.h
// Gengmei
//
// Created by wangyang on 2017/11/2.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface GMGIF: NSObject
@property (nonatomic, copy, readonly) NSArray<UIImage *> *images;
@property (nonatomic, assign, readonly) NSTimeInterval duration;
- (nullable instancetype)initWithName:(NSString *)name;
@end
NS_ASSUME_NONNULL_END
//
// UIImage+GIFImages.m
// Gengmei
//
// Created by wangyang on 2017/11/2.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import "UIImage+GIFImages.h"
@interface GMGIF ()
@property (nonatomic, copy) NSArray<UIImage *> *images;
@property (nonatomic, assign) NSTimeInterval duration;
@end
@implementation GMGIF
- (instancetype)initWithName:(NSString *)name {
self = [super init];
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
NSData *data = [NSData dataWithContentsOfFile:path];
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!image) {
continue;
}
duration += [GMGIF sd_frameDurationAtIndex:i source:source];
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CGImageRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
CFRelease(source);
if (images.count == 0) {
NSLog(@"gif中没有图片");
return nil;
}
self.images = images;
self.duration = duration;
return self;
}
+ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
}
else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
// for more information.
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}
@end
//
// UIImage+GMloadImage.h
// Gengmei
//
// Created by 刘鹿杰的mac on 2019/5/6.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (GMloadImage)
// 下载图片
+ (UIImage *)loadOriginalImageWithString:(id )string;
@end
NS_ASSUME_NONNULL_END
//
// UIImage+GMloadImage.m
// Gengmei
//
// Created by 刘鹿杰的mac on 2019/5/6.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "UIImage+GMloadImage.h"
@implementation UIImage (GMloadImage)
+ (UIImage *)loadOriginalImageWithString:(id )string{
UIImage* image = nil;
if ([string isKindOfClass:[UIImage class]]){
image = (UIImage *)string;
} else if ([string isKindOfClass:[NSString class]]) {
NSString *url = (NSString *)string;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1.5];
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
image = [UIImage imageWithData: data];
//如果远程的图片下载不下来,则使用默认图
if (image == nil) {
image = [UIImage imageNamed:@"icon"];
}
}
return image;
}
@end
/*
File: UIImage+ImageEffects.h
Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur.
Version: 1.0
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2013 Apple Inc. All Rights Reserved.
Copyright © 2013 Apple Inc. All rights reserved.
WWDC 2013 License
NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013
Session. Please refer to the applicable WWDC 2013 Session for further
information.
IMPORTANT: This Apple software is supplied to you by Apple Inc.
("Apple") in consideration of your agreement to the following terms, and
your use, installation, modification or redistribution of this Apple
software constitutes acceptance of these terms. If you do not agree with
these terms, please do not use, install, modify or redistribute this
Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a non-exclusive license, under
Apple's copyrights in this original Apple software (the "Apple
Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES
NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
EA1002
5/3/2013
*/
@import UIKit;
@interface UIImage (ImageEffects)
- (UIImage *)applyLightEffect;
- (UIImage *)applyLightEffect2;
- (UIImage *)applyLightEffectcolor:(float)color alf:(float)alf radiu:(float)radiu Factor:(float)Factor;
- (UIImage *)applyExtraLightEffect;
- (UIImage *)applyDarkEffect;
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;
- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;
@end
/*
File: UIImage+ImageEffects.m
Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur.
Version: 1.0
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2013 Apple Inc. All Rights Reserved.
Copyright © 2013 Apple Inc. All rights reserved.
WWDC 2013 License
NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013
Session. Please refer to the applicable WWDC 2013 Session for further
information.
IMPORTANT: This Apple software is supplied to you by Apple Inc.
("Apple") in consideration of your agreement to the following terms, and
your use, installation, modification or redistribution of this Apple
software constitutes acceptance of these terms. If you do not agree with
these terms, please do not use, install, modify or redistribute this
Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a non-exclusive license, under
Apple's copyrights in this original Apple software (the "Apple
Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES
NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
EA1002
5/3/2013
*/
#import "UIImage+ImageEffects.h"
@import Accelerate;
#import <float.h>
@implementation UIImage (ImageEffects)
- (UIImage *)applyLightEffect
{
UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}
- (UIImage *)applyLightEffect2
{
UIColor *tintColor = [UIColor colorWithWhite:0.5 alpha:0.0];
return [self applyBlurWithRadius:15 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}
- (UIImage *)applyLightEffectcolor:(float)color alf:(float)alf radiu:(float)radiu Factor:(float)Factor
{
UIColor *tintColor = [UIColor colorWithWhite:color alpha:alf];
return [self applyBlurWithRadius:radiu tintColor:tintColor saturationDeltaFactor:Factor maskImage:nil];
}
- (UIImage *)applyExtraLightEffect
{
UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}
- (UIImage *)applyDarkEffect
{
UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0];
return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}
- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
{
const CGFloat EffectColorAlpha = 0.6;
UIColor *effectColor = tintColor;
NSInteger componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
if (componentCount == 2) {
CGFloat b;
if ([tintColor getWhite:&b alpha:NULL]) {
effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
}
}
else {
CGFloat r, g, b;
if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
}
}
return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
}
- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
{
// Check pre-conditions.
if (self.size.width < 1 || self.size.height < 1) {
NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
return nil;
}
if (!self.CGImage) {
NSLog (@"*** error: image must be backed by a CGImage: %@", self);
return nil;
}
if (maskImage && !maskImage.CGImage) {
NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
return nil;
}
CGRect imageRect = { CGPointZero, self.size };
UIImage *effectImage = self;
BOOL hasBlur = blurRadius > __FLT_EPSILON__;
BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
if (hasBlur || hasSaturationChange) {
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef effectInContext = UIGraphicsGetCurrentContext();
CGContextScaleCTM(effectInContext, 1.0, -1.0);
CGContextTranslateCTM(effectInContext, 0, -self.size.height);
CGContextDrawImage(effectInContext, imageRect, self.CGImage);
vImage_Buffer effectInBuffer;
effectInBuffer.data = CGBitmapContextGetData(effectInContext);
effectInBuffer.width = CGBitmapContextGetWidth(effectInContext);
effectInBuffer.height = CGBitmapContextGetHeight(effectInContext);
effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
vImage_Buffer effectOutBuffer;
effectOutBuffer.data = CGBitmapContextGetData(effectOutContext);
effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext);
effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext);
effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);
if (hasBlur) {
// A description of how to compute the box kernel width from the Gaussian
// radius (aka standard deviation) appears in the SVG spec:
// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
//
// For larger values of 's' (s >= 2.0), an approximation can be used: Three
// successive box-blurs build a piece-wise quadratic convolution kernel, which
// approximates the Gaussian kernel to within roughly 3%.
//
// let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
//
// ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
//
CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
if (radius % 2 != 1) {
radius += 1; // force radius to be odd so that the three box-blur methodology works.
}
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
}
BOOL effectImageBuffersAreSwapped = NO;
if (hasSaturationChange) {
CGFloat s = saturationDeltaFactor;
CGFloat floatingPointSaturationMatrix[] = {
0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
0, 0, 0, 1,
};
const int32_t divisor = 256;
NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
int16_t saturationMatrix[matrixSize];
for (NSUInteger i = 0; i < matrixSize; ++i) {
saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
}
if (hasBlur) {
vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
effectImageBuffersAreSwapped = YES;
}
else {
vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
}
}
if (!effectImageBuffersAreSwapped)
effectImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (effectImageBuffersAreSwapped)
effectImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
// Set up output context.
UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef outputContext = UIGraphicsGetCurrentContext();
CGContextScaleCTM(outputContext, 1.0, -1.0);
CGContextTranslateCTM(outputContext, 0, -self.size.height);
// Draw base image.
CGContextDrawImage(outputContext, imageRect, self.CGImage);
// Draw effect image.
if (hasBlur) {
CGContextSaveGState(outputContext);
if (maskImage) {
CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
}
CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
CGContextRestoreGState(outputContext);
}
// Add in color tint.
if (tintColor) {
CGContextSaveGState(outputContext);
CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
CGContextFillRect(outputContext, imageRect);
CGContextRestoreGState(outputContext);
}
// Output image is ready.
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
@end
//
// resize.swift
// Gengmei
//
// Created by licong on 2017/4/28.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import UIKit
@objc public extension UIImage {
///对指定图片中心进行拉伸
static func stretchByCenter(name: String) -> UIImage {
var normal = UIImage(named: name)!
let imageWidth = normal.size.width * 0.5
let imageHeight = normal.size.height * 0.5
normal = normal.resizableImage(withCapInsets: UIEdgeInsets(top: imageHeight, left: imageWidth, bottom: imageHeight, right: imageWidth), resizingMode: .stretch)
return normal
}
}
//
// UIImage+water.h
// Gengmei
//
// Created by Q14 on 2019/7/25.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (water)
+ (UIImage *)wterImageWithImage:(UIImage *)image waterImage:(UIImage *)waterImage waterImageRect:(CGRect)rect;
+ (UIImage *)waterMarkWithImage:(UIImage *)bgImage andMarkImageName:(UIImage *)waterImage;
@end
NS_ASSUME_NONNULL_END
//
// UIImage+water.m
// Gengmei
//
// Created by Q14 on 2019/7/25.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "UIImage+water.h"
@implementation UIImage (water)
// 给图片添加图片水印
+ (UIImage *)wterImageWithImage:(UIImage *)image waterImage:(UIImage *)waterImage waterImageRect:(CGRect)rect {
//开启上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
//绘制背景图片
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//绘制水印图片到当前上下文
[waterImage drawInRect:rect];
//从上下文中获取新图片
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
//关闭图形上下文
UIGraphicsEndImageContext();
//返回图片
return newImage;
}
+ (UIImage *)waterMarkWithImage:(UIImage *)bgImage andMarkImageName:(UIImage *)waterImage {
// bgImag.size = [UIImage getScreenImageSize:bgImage];
UIGraphicsBeginImageContextWithOptions(bgImage.size, NO, 0.0);
[bgImage drawInRect:CGRectMake(0, 0, bgImage.size.width, bgImage.size.height)];
CGFloat margin = 24;
CGFloat waterW = waterImage.size.width;
CGFloat waterH = waterImage.size.height;
CGFloat scale = bgImage.size.width/UIScreen.mainScreen.bounds.size.width;
CGFloat waterX = bgImage.size.width - waterW*scale - margin*scale;
CGFloat waterY = bgImage.size.height - waterH*scale - margin*scale;
[waterImage drawInRect:CGRectMake(waterX, waterY, waterW*scale, waterH*scale)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
+ (CGSize)getScreenImageSize:(UIImage *)image {
CGFloat scale1 = image.size.height / image.size.width;
return CGSizeMake(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.width*scale1);
}
@end
//
// UITextView+LengthLimit.h
// Gengmei
//
// Created by wangyang on 2017/3/9.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
UITextView 输入之字数限制. http://blog.csdn.net/fengsh998/article/details/45421107
*/
@interface UITextView (LimitBase)
@property(nonatomic, assign) NSInteger maxTextLength;
@property(nonatomic, readonly, assign) NSInteger textLength;
@end
@interface UITextView (SimpleLimit)
/**
对字数进行简单限制。该方法可以就对绝大部分需求。例如需求只限制最大长度,没有提示性交互,没有特殊字符过滤时,使用该方法即可以
在 UITextViewDelegate textViewDidChange中调用
*/
- (void)s_textViewDidChange;
@end
@interface UITextView (ComplexLimit)
/**
对字数进行复杂限制。如果需求有在输入时的交互提示,有特殊字符过滤时,需要使用下面方法。需要配合 c_textViewDidChange 同时使用
在 UITextViewDelegate textView:shouldChangeTextInRange:replacementText: 调用并返回
*/
- (BOOL)c_shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
/**
对字数进行复杂限制。需要配合 c_shouldChangeTextInRange:replacementText 同时使用
在 UITextViewDelegate textViewDidChange中调用
*/
- (void)c_textViewDidChange;
@end
//
// UITextView+LengthLimit.m
// Gengmei
//
// Created by wangyang on 2017/3/9.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import "UITextView+LengthLimit.h"
#import <objc/runtime.h>
@implementation UITextView (LimitBase)
- (NSInteger)maxTextLength {
NSNumber *length = objc_getAssociatedObject(self, @selector(maxTextLength));
return length.integerValue;
}
- (void)setMaxTextLength:(NSInteger)maxTextLength {
objc_setAssociatedObject(self, @selector(maxTextLength), @(maxTextLength), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSInteger)textLength {
NSNumber *length = objc_getAssociatedObject(self, @selector(textLength));
return length.integerValue;
}
- (void)setTextLength:(NSInteger)textLength {
objc_setAssociatedObject(self, @selector(textLength), @(textLength), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@implementation UITextView (SimpleLimit)
- (void)s_textViewDidChange {
NSString *toBeString = self.text;
UITextRange *selectedRange = [self markedTextRange];
UITextPosition *position = [self positionFromPosition:selectedRange.start offset:0];
NSInteger length = self.textLength;
// 没有高亮选择的字,则对已输入的文字进行字数统计和限制
if (!position){
if (toBeString.length > self.maxTextLength){
NSRange rangeIndex = [toBeString rangeOfComposedCharacterSequenceAtIndex:self.maxTextLength];
if (rangeIndex.length == 1){
self.text = [toBeString substringToIndex:self.maxTextLength];
} else{
NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, self.maxTextLength)];
self.text = [toBeString substringWithRange:rangeRange];
}
length = self.text.length;
} else {
NSString *selectedText = [self textInRange:selectedRange];
length = self.text.length - selectedText.length;
}
}
if (length > self.maxTextLength) {
self.textLength = self.maxTextLength;
} else {
self.textLength = length;
}
}
@end
@implementation UITextView (ComplexLimit)
- (BOOL)c_shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (text.length==0) { //Delete any cases
if(range.length > 1){
//Delete whole word
}
else if(range.length == 1){
//Delete single letter
}
else if(range.length == 0){
//Tap delete key when textField empty
}
return YES;
}
UITextRange *selectedRange = [self markedTextRange];
//获取高亮部分
UITextPosition *pos = [self positionFromPosition:selectedRange.start offset:0];
//获取高亮部分内容
// NSString * selectedtext = [self textInRange:selectedRange];
//如果有高亮且当前字数开始位置小于最大限制时允许输入
if (selectedRange && pos) {
NSInteger startOffset = [self offsetFromPosition:self.beginningOfDocument toPosition:selectedRange.start];
NSInteger endOffset = [self offsetFromPosition:self.beginningOfDocument toPosition:selectedRange.end];
NSRange offsetRange = NSMakeRange(startOffset, endOffset - startOffset);
if (offsetRange.location < self.maxTextLength) {
return YES;
}
else
{
return NO;
}
}
NSString *comcatstr = [self.text stringByReplacingCharactersInRange:range withString:text];
NSInteger canInputLen = self.maxTextLength - comcatstr.length;
if (canInputLen >= 0)
{
return YES;
}
else
{
NSInteger len = text.length + canInputLen;
//防止当text.length + caninputlen < 0时,使得rg.length为一个非法最大正数出错
NSRange rg = {0,MAX(len,0)};
if (rg.length > 0)
{
NSString *s = @"";
//判断是否只普通的字符或asc码(对于中文和表情返回NO)
BOOL asc = [text canBeConvertedToEncoding:NSASCIIStringEncoding];
if (asc) {
s = [text substringWithRange:rg];//因为是ascii码直接取就可以了不会错
}
else
{
__block NSInteger idx = 0;
__block NSString *trimString = @"";//截取出的字串
//使用字符串遍历,这个方法能准确知道每个emoji是占一个unicode还是两个
[text enumerateSubstringsInRange:NSMakeRange(0, [text length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock: ^(NSString* substring, NSRange substringRange, NSRange enclosingRange, BOOL* stop) {
NSInteger steplen = substring.length;
if (idx >= rg.length) {
*stop = YES; //取出所需要就break,提高效率
return ;
}
trimString = [trimString stringByAppendingString:substring];
idx = idx + steplen;//这里变化了,使用了字串占的长度来作为步长
}];
s = trimString;
}
//rang是指从当前光标处进行替换处理(注意如果执行此句后面返回的是YES会触发didchange事件)
[self setText:[self.text stringByReplacingCharactersInRange:range withString:s]];
//既然是超出部分截取了,那一定是最大限制了。
self.textLength = self.maxTextLength;
}
return NO;
}
}
- (void)c_textViewDidChange
{
UITextRange *selectedRange = [self markedTextRange];
//获取高亮部分
UITextPosition *pos = [self positionFromPosition:selectedRange.start offset:0];
//如果在变化中是高亮部分在变,就不要计算字符了
if (selectedRange && pos) {
return;
}
NSString *nsTextContent = self.text;
NSInteger existTextNum = nsTextContent.length;
if (existTextNum > self.maxTextLength)
{
//截取到最大位置的字符(由于超出截部分在should时被处理了所在这里这了提高效率不再判断)
NSString *s = [nsTextContent substringToIndex:self.maxTextLength];
[self setText:s];
self.textLength = self.maxTextLength;
} else {
self.textLength = existTextNum;
}
}
@end
//
// UIView+CornerRadius.h
// Gengmei
//
// Created by wangyang on 2017/12/7.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (CornerRadius)
/**
通过添加一个额外UIImageView来完成圆角
确保在 self 被addSubview之后再调用该方法
*/
- (void)addCornerRadius5;
/**
设置圆角
@param cornerRadii 半径
@param corners 圆角位置
*/
- (void)containerRectCorner:(CGSize)cornerRadii byRoundingCorners:(UIRectCorner)corners;
@end
//
// UIView+CornerRadius.m
// Gengmei
//
// Created by wangyang on 2017/12/7.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
#import "UIView+CornerRadius.h"
#import <Masonry/Masonry.h>
@implementation UIView (CornerRadius)
- (void)addCornerRadius5 {
UIImageView *mask = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"diaryCoverMask"]];
mask.userInteractionEnabled = NO;
[self.superview addSubview:mask];
[mask mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
}
- (void)containerRectCorner:(CGSize)cornerRadii byRoundingCorners:(UIRectCorner)corners {
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:cornerRadii];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;
self.layer.mask = maskLayer;
}
@end
//
// UIView+Layer.swift
// Gengmei
//
// Created by wangyang on 2017/6/7.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import UIKit
@objc public extension UIView {
func setCornerRadius(_ radisu: CGFloat) {
layer.cornerRadius = radisu
clipsToBounds = true
}
}
//
// UIView+LikeAnimation.h
// test
//
// Created by wangyang on 16/9/21.
// Copyright © 2016年 北京更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (LikeAnimation)
- (void)addLikeAnimationWithFrame:(CGRect)frame NS_SWIFT_NAME(addLikeAnimation(withFrame:));
- (void)addLikeAnimationFrom:(CGPoint)point;
@end
//
// UIView+LikeAnimation.m
// test
//
// Created by wangyang on 16/9/21.
// Copyright © 2016年 北京更美互动信息科技有限公司. All rights reserved.
//
#import "UIView+LikeAnimation.h"
@implementation UIView (LikeAnimation)
- (void)addLikeAnimationWithFrame:(CGRect)frame {
UIImageView *likeView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"topic_zan_pink"]];
likeView.frame = frame;
[likeView addLikeAnimationFrom:likeView.center];
[self addSubview:likeView];
}
- (void)addLikeAnimationFrom:(CGPoint)point {
CGFloat totalTime = 1;
// 放大
CABasicAnimation *scaleBig = [CABasicAnimation animationWithKeyPath:@"transform"];
scaleBig.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
scaleBig.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.5, 2.5, 1.0)];
scaleBig.removedOnCompletion = YES;
scaleBig.beginTime = 0;
scaleBig.duration = 0.5 * totalTime;
scaleBig.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
// 缩小
CABasicAnimation *scaleSmall = [CABasicAnimation animationWithKeyPath:@"transform"];
scaleSmall.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.5, 2.5, 1.0)];
scaleSmall.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.5, 1.0)];
scaleSmall.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
scaleSmall.removedOnCompletion = YES;
scaleSmall.beginTime = 0.5 * totalTime;
scaleSmall.duration = 0.5 * totalTime;
// 渐隐
CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
alphaAnimation.fromValue = @1;
alphaAnimation.toValue = @0.25;
alphaAnimation.removedOnCompletion = YES;
alphaAnimation.beginTime = 0.5 * totalTime;
alphaAnimation.duration = 0.5 * totalTime;
// 旋转
CABasicAnimation *rotate =
[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotate.fromValue = [NSNumber numberWithFloat:0]; // 开始时的角度
rotate.toValue = [NSNumber numberWithFloat:M_PI_4]; // 结束时的角度
rotate.beginTime = 0;
rotate.duration = 0.5 * totalTime;
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
rotate.removedOnCompletion = NO;
rotate.fillMode = kCAFillModeForwards;
// 路径
UIBezierPath *movePath = [UIBezierPath bezierPath];
[movePath moveToPoint:point];
[movePath addQuadCurveToPoint:CGPointMake(point.x + 35, point.y - 43) controlPoint:CGPointMake(point.x + 27, point.y - 115)];
CAKeyframeAnimation * posAnim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
posAnim.path = movePath.CGPath;
posAnim.removedOnCompletion = YES;
// 组合动画
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:scaleBig, scaleSmall, posAnim, rotate, alphaAnimation, nil];
group.duration = 1 * totalTime;
group.autoreverses = NO;
group.repeatCount = 1;
[self.layer addAnimation:group forKey:nil];
[self performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1 * totalTime inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
}
@end
//
// UIView+PointInside.swift
// Gengmei
//
// Created by wangyang on 2017/10/30.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import Foundation
@objc public extension UIView {
/// 为view竖直方向增加一些热区
func gm_point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if bounds.height > 35 {
return bounds.contains(point)
}
let heightDelta = 35 - bounds.size.height
let maxBounds = bounds.insetBy(dx: 0, dy: -0.5 * heightDelta)
return maxBounds.contains(point)
}
}
//
// UIView+ScreenshotImage.swift
// Gengmei
//
// Created by wangyang on 2017/3/23.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import Foundation
@objc public extension UIView {
func screenshot() -> UIImage {
if self is UIScrollView {
let scrollView = self as! UIScrollView
let savedContentOffset = scrollView.contentOffset
let savedFrame = scrollView.frame
// 使用scale才可以创建出符合屏幕分辨率的图片
// UIGraphicsBeginImageContext(scrollView.contentSize)
UIGraphicsBeginImageContextWithOptions(scrollView.contentSize, false, UIScreen.main.scale)
scrollView.contentOffset = .zero
frame = CGRect(x: 0, y: 0, width: scrollView.contentSize.width, height: scrollView.contentSize.height)
layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
scrollView.contentOffset = savedContentOffset
scrollView.frame = savedFrame
return image!
}
// UIGraphicsBeginImageContext(self.bounds.size)
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
//
// UIView+TileSubviews.h
// Gengmei
//
// Created by wangyang on 2016/10/26.
// Copyright © 2016年 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (TileSubviews)
/**
按照参数设置好每个subview的frame,并返回view的总体高度,该高度包含padding的top与bottom
|----------------------------------|
| padding.top |
| |--------------| |-------| |
| | Label | | Image | |
| | | | | |
| |--------------| |-------| |
| padding.bottom |
|----------------------------------|
@param views 待摆放的subviews
@param padding 父视图与subviews整体的间距
@param spacing 每个subview之间的水平、竖直方向的间距
@param maxWidth 父view的最大宽度,包含padding的left与right
@param caculater 计算每个subview的大小, 可以为nil,将自动使用每个view.intrinsicContentSize
@return view的总体高度
*/
- (CGFloat)layoutSubviews:(NSArray<UIView *> *)views
padding:(UIEdgeInsets)padding
spacing:(CGPoint)spacing
maxWidth:(CGFloat)maxWidth
subviewSize:(CGSize (^ __nullable)(NSUInteger idx))caculater;
- (CGFloat)layoutSubviews:(NSArray<UIView *> *)views
padding:(UIEdgeInsets)padding
spacing:(CGPoint)spacing
maxWidth:(CGFloat)maxWidth
singleLine:(BOOL)singleLine
subviewSize:(CGSize (^ __nullable)(NSUInteger idx))caculater;
@end
NS_ASSUME_NONNULL_END
//
// UIView+TileSubviews.m
// Gengmei
//
// Created by wangyang on 2016/10/26.
// Copyright © 2016年 更美互动信息科技有限公司. All rights reserved.
//
#import "UIView+TileSubviews.h"
#import "UIView+Layout.h"
@implementation UIView (TileSubviews)
- (CGFloat)layoutSubviews:(NSArray<UIView *> *)views
padding:(UIEdgeInsets)padding
spacing:(CGPoint)spacing
maxWidth:(CGFloat)maxWidth
subviewSize:(CGSize (^)(NSUInteger idx))caculater {
__block CGFloat allHeight = 0;
__block UIView *preView;
[views enumerateObjectsUsingBlock:^(UIView * obj, NSUInteger idx, BOOL *stop) {
UIView *item = views[idx];
CGSize size = item.intrinsicContentSize;
if (caculater) {
size = caculater(idx);
}
views[idx].size = size;
if (idx == 0) {
item.left = padding.left;
item.top = padding.top;
preView = item;
} else {
//如果当前button超出了屏幕,则换行
NSInteger totleW = preView.right + spacing.x + size.width + padding.right;
if (totleW > maxWidth) {
item.left = padding.left;
item.top = preView.bottom + spacing.y;
}else{
item.left = preView.right + spacing.x;
item.top = preView.top;
}
}
preView = item;
}];
allHeight = preView.bottom + padding.bottom;
return allHeight;
}
- (CGFloat)layoutSubviews:(NSArray<UIView *> *)views
padding:(UIEdgeInsets)padding
spacing:(CGPoint)spacing
maxWidth:(CGFloat)maxWidth
singleLine:(BOOL)singleLine
subviewSize:(CGSize (^)(NSUInteger idx))caculater {
__block CGFloat allHeight = 0;
__block UIView *preView;
[views enumerateObjectsUsingBlock:^(UIView * obj, NSUInteger idx, BOOL *stop) {
UIView *item = views[idx];
CGSize size = item.intrinsicContentSize;
if (caculater) {
size = caculater(idx);
}
views[idx].size = size;
if (idx == 0) {
item.left = padding.left;
item.top = padding.top;
preView = item;
} else {
//如果当前button超出了屏幕,则换行
NSInteger totleW = preView.right + spacing.x + size.width + padding.right;
if (totleW > maxWidth) {
if (singleLine) {
[item removeFromSuperview];
} else {
item.left = padding.left;
item.top = preView.bottom + spacing.y;
preView = item;
}
}else{
item.left = preView.right + spacing.x;
item.top = preView.top;
preView = item;
}
}
}];
allHeight = preView.bottom + padding.bottom;
return allHeight;
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
/**
These following class are provided to use `UIGraphicsImageRenderer` with polyfill, which allows write cross-platform(AppKit/UIKit) code and avoid runtime version check.
Compared to `UIGraphicsBeginImageContext`, `UIGraphicsImageRenderer` use dynamic bitmap from your draw code to generate CGContext, not always use ARGB8888, which is more performant on RAM usage.
Which means, if you draw CGImage/CIImage which contains grayscale only, the underlaying bitmap context use grayscale, it's managed by system and not a fixed type. (actually, the `kCGContextTypeAutomatic`)
For usage, See more in Apple's documentation: https://developer.apple.com/documentation/uikit/uigraphicsimagerenderer
For UIKit on iOS/tvOS 10+, these method just use the same `UIGraphicsImageRenderer` API.
For others (macOS/watchOS or iOS/tvOS 10-), these method use the `SDImageGraphics.h` to implements the same behavior (but without dynamic bitmap support)
*/
typedef void (^SDGraphicsImageDrawingActions)(CGContextRef _Nonnull context);
typedef NS_ENUM(NSInteger, SDGraphicsImageRendererFormatRange) {
SDGraphicsImageRendererFormatRangeUnspecified = -1,
SDGraphicsImageRendererFormatRangeAutomatic = 0,
SDGraphicsImageRendererFormatRangeExtended,
SDGraphicsImageRendererFormatRangeStandard
};
/// A set of drawing attributes that represent the configuration of an image renderer context.
@interface SDGraphicsImageRendererFormat : NSObject
/// The display scale of the image renderer context.
/// The default value is equal to the scale of the main screen.
@property (nonatomic) CGFloat scale;
/// A Boolean value indicating whether the underlying Core Graphics context has an alpha channel.
/// The default value is NO.
@property (nonatomic) BOOL opaque;
/// Specifying whether the bitmap context should use extended color.
/// For iOS 12+, the value is from system `preferredRange` property
/// For iOS 10-11, the value is from system `prefersExtendedRange` property
/// For iOS 9-, the value is `.standard`
@property (nonatomic) SDGraphicsImageRendererFormatRange preferredRange;
/// Init the default format. See each properties's default value.
- (nonnull instancetype)init;
/// Returns a new format best suited for the main screen’s current configuration.
+ (nonnull instancetype)preferredFormat;
@end
/// A graphics renderer for creating Core Graphics-backed images.
@interface SDGraphicsImageRenderer : NSObject
/// Creates an image renderer for drawing images of a given size.
/// @param size The size of images output from the renderer, specified in points.
/// @return An initialized image renderer.
- (nonnull instancetype)initWithSize:(CGSize)size;
/// Creates a new image renderer with a given size and format.
/// @param size The size of images output from the renderer, specified in points.
/// @param format A SDGraphicsImageRendererFormat object that encapsulates the format used to create the renderer context.
/// @return An initialized image renderer.
- (nonnull instancetype)initWithSize:(CGSize)size format:(nonnull SDGraphicsImageRendererFormat *)format;
/// Creates an image by following a set of drawing instructions.
/// @param actions A SDGraphicsImageDrawingActions block that, when invoked by the renderer, executes a set of drawing instructions to create the output image.
/// @note You should not retain or use the context outside the block, it's non-escaping.
/// @return A UIImage object created by the supplied drawing actions.
- (nonnull UIImage *)imageWithActions:(nonnull NS_NOESCAPE SDGraphicsImageDrawingActions)actions;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDGraphicsImageRenderer.h"
#import "SDImageGraphics.h"
@interface SDGraphicsImageRendererFormat ()
#if SD_UIKIT
@property (nonatomic, strong) UIGraphicsImageRendererFormat *uiformat API_AVAILABLE(ios(10.0), tvos(10.0));
#endif
@end
@implementation SDGraphicsImageRendererFormat
@synthesize scale = _scale;
@synthesize opaque = _opaque;
@synthesize preferredRange = _preferredRange;
#pragma mark - Property
- (CGFloat)scale {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
return self.uiformat.scale;
} else {
return _scale;
}
#else
return _scale;
#endif
}
- (void)setScale:(CGFloat)scale {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
self.uiformat.scale = scale;
} else {
_scale = scale;
}
#else
_scale = scale;
#endif
}
- (BOOL)opaque {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
return self.uiformat.opaque;
} else {
return _opaque;
}
#else
return _opaque;
#endif
}
- (void)setOpaque:(BOOL)opaque {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
self.uiformat.opaque = opaque;
} else {
_opaque = opaque;
}
#else
_opaque = opaque;
#endif
}
- (SDGraphicsImageRendererFormatRange)preferredRange {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
if (@available(iOS 12.0, tvOS 12.0, *)) {
return (SDGraphicsImageRendererFormatRange)self.uiformat.preferredRange;
} else {
BOOL prefersExtendedRange = self.uiformat.prefersExtendedRange;
if (prefersExtendedRange) {
return SDGraphicsImageRendererFormatRangeExtended;
} else {
return SDGraphicsImageRendererFormatRangeStandard;
}
}
} else {
return _preferredRange;
}
#else
return _preferredRange;
#endif
}
- (void)setPreferredRange:(SDGraphicsImageRendererFormatRange)preferredRange {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
if (@available(iOS 12.0, tvOS 12.0, *)) {
self.uiformat.preferredRange = (UIGraphicsImageRendererFormatRange)preferredRange;
} else {
switch (preferredRange) {
case SDGraphicsImageRendererFormatRangeExtended:
self.uiformat.prefersExtendedRange = YES;
break;
case SDGraphicsImageRendererFormatRangeStandard:
self.uiformat.prefersExtendedRange = NO;
default:
// Automatic means default
break;
}
}
} else {
_preferredRange = preferredRange;
}
#else
_preferredRange = preferredRange;
#endif
}
- (instancetype)init {
self = [super init];
if (self) {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.10, *)) {
UIGraphicsImageRendererFormat *uiformat = [[UIGraphicsImageRendererFormat alloc] init];
self.uiformat = uiformat;
} else {
#endif
#if SD_WATCH
CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale;
#elif SD_UIKIT
CGFloat screenScale = [UIScreen mainScreen].scale;
#elif SD_MAC
CGFloat screenScale = [NSScreen mainScreen].backingScaleFactor;
#endif
self.scale = screenScale;
self.opaque = NO;
self.preferredRange = SDGraphicsImageRendererFormatRangeStandard;
#if SD_UIKIT
}
#endif
}
return self;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
- (instancetype)initForMainScreen {
self = [super init];
if (self) {
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.0, *)) {
UIGraphicsImageRendererFormat *uiformat;
// iOS 11.0.0 GM does have `preferredFormat`, but iOS 11 betas did not (argh!)
if ([UIGraphicsImageRenderer respondsToSelector:@selector(preferredFormat)]) {
uiformat = [UIGraphicsImageRendererFormat preferredFormat];
} else {
uiformat = [UIGraphicsImageRendererFormat defaultFormat];
}
self.uiformat = uiformat;
} else {
#endif
#if SD_WATCH
CGFloat screenScale = [WKInterfaceDevice currentDevice].screenScale;
#elif SD_UIKIT
CGFloat screenScale = [UIScreen mainScreen].scale;
#elif SD_MAC
CGFloat screenScale = [NSScreen mainScreen].backingScaleFactor;
#endif
self.scale = screenScale;
self.opaque = NO;
self.preferredRange = SDGraphicsImageRendererFormatRangeStandard;
#if SD_UIKIT
}
#endif
}
return self;
}
#pragma clang diagnostic pop
+ (instancetype)preferredFormat {
SDGraphicsImageRendererFormat *format = [[SDGraphicsImageRendererFormat alloc] initForMainScreen];
return format;
}
@end
@interface SDGraphicsImageRenderer ()
@property (nonatomic, assign) CGSize size;
@property (nonatomic, strong) SDGraphicsImageRendererFormat *format;
#if SD_UIKIT
@property (nonatomic, strong) UIGraphicsImageRenderer *uirenderer API_AVAILABLE(ios(10.0), tvos(10.0));
#endif
@end
@implementation SDGraphicsImageRenderer
- (instancetype)initWithSize:(CGSize)size {
return [self initWithSize:size format:SDGraphicsImageRendererFormat.preferredFormat];
}
- (instancetype)initWithSize:(CGSize)size format:(SDGraphicsImageRendererFormat *)format {
NSParameterAssert(format);
self = [super init];
if (self) {
self.size = size;
self.format = format;
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.0, *)) {
UIGraphicsImageRendererFormat *uiformat = format.uiformat;
self.uirenderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:uiformat];
}
#endif
}
return self;
}
- (UIImage *)imageWithActions:(NS_NOESCAPE SDGraphicsImageDrawingActions)actions {
NSParameterAssert(actions);
#if SD_UIKIT
if (@available(iOS 10.0, tvOS 10.0, *)) {
UIGraphicsImageDrawingActions uiactions = ^(UIGraphicsImageRendererContext *rendererContext) {
if (actions) {
actions(rendererContext.CGContext);
}
};
return [self.uirenderer imageWithActions:uiactions];
} else {
#endif
SDGraphicsBeginImageContextWithOptions(self.size, self.format.opaque, self.format.scale);
CGContextRef context = SDGraphicsGetCurrentContext();
if (actions) {
actions(context);
}
UIImage *image = SDGraphicsGetImageFromCurrentImageContext();
SDGraphicsEndImageContext();
return image;
#if SD_UIKIT
}
#endif
}
@end
Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<img src="http://snapkit.io/images/banner.jpg" alt="" />
SnapKit is a DSL to make Auto Layout easy on both iOS and OS X.
[![Build Status](https://travis-ci.org/SnapKit/SnapKit.svg)](https://travis-ci.org/SnapKit/SnapKit)
[![Platform](https://img.shields.io/cocoapods/p/SnapKit.svg?style=flat)](https://github.com/SnapKit/SnapKit)
[![Cocoapods Compatible](https://img.shields.io/cocoapods/v/SnapKit.svg)](https://cocoapods.org/pods/SnapKit)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
#### ⚠️ **To use with Swift 3.x please ensure you are using >= 3.0.0** ⚠️
#### ⚠️ **To use with Swift 4.x please ensure you are using >= 4.0.0** ⚠️
## Contents
- [Requirements](#requirements)
- [Migration Guides](#migration-guides)
- [Communication](#communication)
- [Installation](#installation)
- [Usage](#usage)
- [Credits](#credits)
- [License](#license)
## Requirements
- iOS 8.0+ / Mac OS X 10.11+ / tvOS 9.0+
- Xcode 9.0+
- Swift 3.0+
## Communication
- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit). (Tag 'snapkit')
- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit).
- If you **found a bug**, open an issue.
- If you **have a feature request**, open an issue.
- If you **want to contribute**, submit a pull request.
## Installation
### CocoaPods
[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
```bash
$ gem install cocoapods
```
> CocoaPods 1.1.0+ is required to build SnapKit 4.0.0+.
To integrate SnapKit into your Xcode project using CocoaPods, specify it in your `Podfile`:
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!
target '<Your Target Name>' do
pod 'SnapKit', '~> 4.0.0'
end
```
Then, run the following command:
```bash
$ pod install
```
### Carthage
[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
```bash
$ brew update
$ brew install carthage
```
To integrate SnapKit into your Xcode project using Carthage, specify it in your `Cartfile`:
```ogdl
github "SnapKit/SnapKit" ~> 4.0.0
```
Run `carthage update` to build the framework and drag the built `SnapKit.framework` into your Xcode project.
### Manually
If you prefer not to use either of the aforementioned dependency managers, you can integrate SnapKit into your project manually.
---
## Usage
### Quick Start
```swift
import SnapKit
class MyViewController: UIViewController {
lazy var box = UIView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(box)
box.snp.makeConstraints { (make) -> Void in
make.width.height.equalTo(50)
make.center.equalTo(self.view)
}
}
}
```
### Resources
- [Documentation](http://snapkit.io/docs/)
- [F.A.Q.](http://snapkit.io/faq/)
## Credits
- Robert Payne ([@robertjpayne](https://twitter.com/robertjpayne))
- Many other contributors
## License
SnapKit is released under the MIT license. See LICENSE for details.
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public final class Constraint {
internal let sourceLocation: (String, UInt)
internal let label: String?
private let from: ConstraintItem
private let to: ConstraintItem
private let relation: ConstraintRelation
private let multiplier: ConstraintMultiplierTarget
private var constant: ConstraintConstantTarget {
didSet {
self.updateConstantAndPriorityIfNeeded()
}
}
private var priority: ConstraintPriorityTarget {
didSet {
self.updateConstantAndPriorityIfNeeded()
}
}
public var layoutConstraints: [LayoutConstraint]
public var isActive: Bool {
set {
if newValue {
activate()
}
else {
deactivate()
}
}
get {
for layoutConstraint in self.layoutConstraints {
if layoutConstraint.isActive {
return true
}
}
return false
}
}
// MARK: Initialization
internal init(from: ConstraintItem,
to: ConstraintItem,
relation: ConstraintRelation,
sourceLocation: (String, UInt),
label: String?,
multiplier: ConstraintMultiplierTarget,
constant: ConstraintConstantTarget,
priority: ConstraintPriorityTarget) {
self.from = from
self.to = to
self.relation = relation
self.sourceLocation = sourceLocation
self.label = label
self.multiplier = multiplier
self.constant = constant
self.priority = priority
self.layoutConstraints = []
// get attributes
let layoutFromAttributes = self.from.attributes.layoutAttributes
let layoutToAttributes = self.to.attributes.layoutAttributes
// get layout from
let layoutFrom = self.from.layoutConstraintItem!
// get relation
let layoutRelation = self.relation.layoutRelation
for layoutFromAttribute in layoutFromAttributes {
// get layout to attribute
let layoutToAttribute: LayoutAttribute
#if os(iOS) || os(tvOS)
if layoutToAttributes.count > 0 {
if self.from.attributes == .edges && self.to.attributes == .margins {
switch layoutFromAttribute {
case .left:
layoutToAttribute = .leftMargin
case .right:
layoutToAttribute = .rightMargin
case .top:
layoutToAttribute = .topMargin
case .bottom:
layoutToAttribute = .bottomMargin
default:
fatalError()
}
} else if self.from.attributes == .margins && self.to.attributes == .edges {
switch layoutFromAttribute {
case .leftMargin:
layoutToAttribute = .left
case .rightMargin:
layoutToAttribute = .right
case .topMargin:
layoutToAttribute = .top
case .bottomMargin:
layoutToAttribute = .bottom
default:
fatalError()
}
} else if self.from.attributes == self.to.attributes {
layoutToAttribute = layoutFromAttribute
} else {
layoutToAttribute = layoutToAttributes[0]
}
} else {
if self.to.target == nil && (layoutFromAttribute == .centerX || layoutFromAttribute == .centerY) {
layoutToAttribute = layoutFromAttribute == .centerX ? .left : .top
} else {
layoutToAttribute = layoutFromAttribute
}
}
#else
if self.from.attributes == self.to.attributes {
layoutToAttribute = layoutFromAttribute
} else if layoutToAttributes.count > 0 {
layoutToAttribute = layoutToAttributes[0]
} else {
layoutToAttribute = layoutFromAttribute
}
#endif
// get layout constant
let layoutConstant: CGFloat = self.constant.constraintConstantTargetValueFor(layoutAttribute: layoutToAttribute)
// get layout to
var layoutTo: AnyObject? = self.to.target
// use superview if possible
if layoutTo == nil && layoutToAttribute != .width && layoutToAttribute != .height {
layoutTo = layoutFrom.superview
}
// create layout constraint
let layoutConstraint = LayoutConstraint(
item: layoutFrom,
attribute: layoutFromAttribute,
relatedBy: layoutRelation,
toItem: layoutTo,
attribute: layoutToAttribute,
multiplier: self.multiplier.constraintMultiplierTargetValue,
constant: layoutConstant
)
// set label
layoutConstraint.label = self.label
// set priority
layoutConstraint.priority = LayoutPriority(rawValue: self.priority.constraintPriorityTargetValue)
// set constraint
layoutConstraint.constraint = self
// append
self.layoutConstraints.append(layoutConstraint)
}
}
// MARK: Public
@available(*, deprecated:3.0, message:"Use activate().")
public func install() {
self.activate()
}
@available(*, deprecated:3.0, message:"Use deactivate().")
public func uninstall() {
self.deactivate()
}
public func activate() {
self.activateIfNeeded()
}
public func deactivate() {
self.deactivateIfNeeded()
}
@discardableResult
public func update(offset: ConstraintOffsetTarget) -> Constraint {
self.constant = offset.constraintOffsetTargetValue
return self
}
@discardableResult
public func update(inset: ConstraintInsetTarget) -> Constraint {
self.constant = inset.constraintInsetTargetValue
return self
}
@discardableResult
public func update(priority: ConstraintPriorityTarget) -> Constraint {
self.priority = priority.constraintPriorityTargetValue
return self
}
@discardableResult
public func update(priority: ConstraintPriority) -> Constraint {
self.priority = priority.value
return self
}
@available(*, deprecated:3.0, message:"Use update(offset: ConstraintOffsetTarget) instead.")
public func updateOffset(amount: ConstraintOffsetTarget) -> Void { self.update(offset: amount) }
@available(*, deprecated:3.0, message:"Use update(inset: ConstraintInsetTarget) instead.")
public func updateInsets(amount: ConstraintInsetTarget) -> Void { self.update(inset: amount) }
@available(*, deprecated:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
public func updatePriority(amount: ConstraintPriorityTarget) -> Void { self.update(priority: amount) }
@available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
public func updatePriorityRequired() -> Void {}
@available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
public func updatePriorityHigh() -> Void { fatalError("Must be implemented by Concrete subclass.") }
@available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
public func updatePriorityMedium() -> Void { fatalError("Must be implemented by Concrete subclass.") }
@available(*, obsoleted:3.0, message:"Use update(priority: ConstraintPriorityTarget) instead.")
public func updatePriorityLow() -> Void { fatalError("Must be implemented by Concrete subclass.") }
// MARK: Internal
internal func updateConstantAndPriorityIfNeeded() {
for layoutConstraint in self.layoutConstraints {
let attribute = (layoutConstraint.secondAttribute == .notAnAttribute) ? layoutConstraint.firstAttribute : layoutConstraint.secondAttribute
layoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: attribute)
let requiredPriority = ConstraintPriority.required.value
if (layoutConstraint.priority.rawValue < requiredPriority), (self.priority.constraintPriorityTargetValue != requiredPriority) {
layoutConstraint.priority = LayoutPriority(rawValue: self.priority.constraintPriorityTargetValue)
}
}
}
internal func activateIfNeeded(updatingExisting: Bool = false) {
guard let item = self.from.layoutConstraintItem else {
print("WARNING: SnapKit failed to get from item from constraint. Activate will be a no-op.")
return
}
let layoutConstraints = self.layoutConstraints
if updatingExisting {
var existingLayoutConstraints: [LayoutConstraint] = []
for constraint in item.constraints {
existingLayoutConstraints += constraint.layoutConstraints
}
for layoutConstraint in layoutConstraints {
let existingLayoutConstraint = existingLayoutConstraints.first { $0 == layoutConstraint }
guard let updateLayoutConstraint = existingLayoutConstraint else {
fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)")
}
let updateLayoutAttribute = (updateLayoutConstraint.secondAttribute == .notAnAttribute) ? updateLayoutConstraint.firstAttribute : updateLayoutConstraint.secondAttribute
updateLayoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: updateLayoutAttribute)
}
} else {
NSLayoutConstraint.activate(layoutConstraints)
item.add(constraints: [self])
}
}
internal func deactivateIfNeeded() {
guard let item = self.from.layoutConstraintItem else {
print("WARNING: SnapKit failed to get from item from constraint. Deactivate will be a no-op.")
return
}
let layoutConstraints = self.layoutConstraints
NSLayoutConstraint.deactivate(layoutConstraints)
item.remove(constraints: [self])
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
internal struct ConstraintAttributes : OptionSet, ExpressibleByIntegerLiteral {
typealias IntegerLiteralType = UInt
internal init(rawValue: UInt) {
self.rawValue = rawValue
}
internal init(_ rawValue: UInt) {
self.init(rawValue: rawValue)
}
internal init(nilLiteral: ()) {
self.rawValue = 0
}
internal init(integerLiteral rawValue: IntegerLiteralType) {
self.init(rawValue: rawValue)
}
internal private(set) var rawValue: UInt
internal static var allZeros: ConstraintAttributes { return 0 }
internal static func convertFromNilLiteral() -> ConstraintAttributes { return 0 }
internal var boolValue: Bool { return self.rawValue != 0 }
internal func toRaw() -> UInt { return self.rawValue }
internal static func fromRaw(_ raw: UInt) -> ConstraintAttributes? { return self.init(raw) }
internal static func fromMask(_ raw: UInt) -> ConstraintAttributes { return self.init(raw) }
// normal
internal static var none: ConstraintAttributes { return 0 }
internal static var left: ConstraintAttributes { return 1 }
internal static var top: ConstraintAttributes { return 2 }
internal static var right: ConstraintAttributes { return 4 }
internal static var bottom: ConstraintAttributes { return 8 }
internal static var leading: ConstraintAttributes { return 16 }
internal static var trailing: ConstraintAttributes { return 32 }
internal static var width: ConstraintAttributes { return 64 }
internal static var height: ConstraintAttributes { return 128 }
internal static var centerX: ConstraintAttributes { return 256 }
internal static var centerY: ConstraintAttributes { return 512 }
internal static var lastBaseline: ConstraintAttributes { return 1024 }
@available(iOS 8.0, OSX 10.11, *)
internal static var firstBaseline: ConstraintAttributes { return 2048 }
@available(iOS 8.0, *)
internal static var leftMargin: ConstraintAttributes { return 4096 }
@available(iOS 8.0, *)
internal static var rightMargin: ConstraintAttributes { return 8192 }
@available(iOS 8.0, *)
internal static var topMargin: ConstraintAttributes { return 16384 }
@available(iOS 8.0, *)
internal static var bottomMargin: ConstraintAttributes { return 32768 }
@available(iOS 8.0, *)
internal static var leadingMargin: ConstraintAttributes { return 65536 }
@available(iOS 8.0, *)
internal static var trailingMargin: ConstraintAttributes { return 131072 }
@available(iOS 8.0, *)
internal static var centerXWithinMargins: ConstraintAttributes { return 262144 }
@available(iOS 8.0, *)
internal static var centerYWithinMargins: ConstraintAttributes { return 524288 }
// aggregates
internal static var edges: ConstraintAttributes { return 15 }
internal static var size: ConstraintAttributes { return 192 }
internal static var center: ConstraintAttributes { return 768 }
@available(iOS 8.0, *)
internal static var margins: ConstraintAttributes { return 61440 }
@available(iOS 8.0, *)
internal static var centerWithinMargins: ConstraintAttributes { return 786432 }
internal var layoutAttributes:[LayoutAttribute] {
var attrs = [LayoutAttribute]()
if (self.contains(ConstraintAttributes.left)) {
attrs.append(.left)
}
if (self.contains(ConstraintAttributes.top)) {
attrs.append(.top)
}
if (self.contains(ConstraintAttributes.right)) {
attrs.append(.right)
}
if (self.contains(ConstraintAttributes.bottom)) {
attrs.append(.bottom)
}
if (self.contains(ConstraintAttributes.leading)) {
attrs.append(.leading)
}
if (self.contains(ConstraintAttributes.trailing)) {
attrs.append(.trailing)
}
if (self.contains(ConstraintAttributes.width)) {
attrs.append(.width)
}
if (self.contains(ConstraintAttributes.height)) {
attrs.append(.height)
}
if (self.contains(ConstraintAttributes.centerX)) {
attrs.append(.centerX)
}
if (self.contains(ConstraintAttributes.centerY)) {
attrs.append(.centerY)
}
if (self.contains(ConstraintAttributes.lastBaseline)) {
attrs.append(.lastBaseline)
}
#if os(iOS) || os(tvOS)
if (self.contains(ConstraintAttributes.firstBaseline)) {
attrs.append(.firstBaseline)
}
if (self.contains(ConstraintAttributes.leftMargin)) {
attrs.append(.leftMargin)
}
if (self.contains(ConstraintAttributes.rightMargin)) {
attrs.append(.rightMargin)
}
if (self.contains(ConstraintAttributes.topMargin)) {
attrs.append(.topMargin)
}
if (self.contains(ConstraintAttributes.bottomMargin)) {
attrs.append(.bottomMargin)
}
if (self.contains(ConstraintAttributes.leadingMargin)) {
attrs.append(.leadingMargin)
}
if (self.contains(ConstraintAttributes.trailingMargin)) {
attrs.append(.trailingMargin)
}
if (self.contains(ConstraintAttributes.centerXWithinMargins)) {
attrs.append(.centerXWithinMargins)
}
if (self.contains(ConstraintAttributes.centerYWithinMargins)) {
attrs.append(.centerYWithinMargins)
}
#endif
return attrs
}
}
internal func + (left: ConstraintAttributes, right: ConstraintAttributes) -> ConstraintAttributes {
return left.union(right)
}
internal func +=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
left.formUnion(right)
}
internal func -=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
left.subtract(right)
}
internal func ==(left: ConstraintAttributes, right: ConstraintAttributes) -> Bool {
return left.rawValue == right.rawValue
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection
#else
import AppKit
public typealias ConstraintInterfaceLayoutDirection = NSUserInterfaceLayoutDirection
#endif
public struct ConstraintConfig {
public static var interfaceLayoutDirection: ConstraintInterfaceLayoutDirection = .leftToRight
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintConstantTarget {
}
extension CGPoint: ConstraintConstantTarget {
}
extension CGSize: ConstraintConstantTarget {
}
extension ConstraintInsets: ConstraintConstantTarget {
}
extension ConstraintConstantTarget {
internal func constraintConstantTargetValueFor(layoutAttribute: LayoutAttribute) -> CGFloat {
if let value = self as? CGFloat {
return value
}
if let value = self as? Float {
return CGFloat(value)
}
if let value = self as? Double {
return CGFloat(value)
}
if let value = self as? Int {
return CGFloat(value)
}
if let value = self as? UInt {
return CGFloat(value)
}
if let value = self as? CGSize {
if layoutAttribute == .width {
return value.width
} else if layoutAttribute == .height {
return value.height
} else {
return 0.0
}
}
if let value = self as? CGPoint {
#if os(iOS) || os(tvOS)
switch layoutAttribute {
case .left, .right, .leading, .trailing, .centerX, .leftMargin, .rightMargin, .leadingMargin, .trailingMargin, .centerXWithinMargins:
return value.x
case .top, .bottom, .centerY, .topMargin, .bottomMargin, .centerYWithinMargins, .lastBaseline, .firstBaseline:
return value.y
case .width, .height, .notAnAttribute:
return 0.0
}
#else
switch layoutAttribute {
case .left, .right, .leading, .trailing, .centerX:
return value.x
case .top, .bottom, .centerY, .lastBaseline, .firstBaseline:
return value.y
case .width, .height, .notAnAttribute:
return 0.0
}
#endif
}
if let value = self as? ConstraintInsets {
#if os(iOS) || os(tvOS)
switch layoutAttribute {
case .left, .leftMargin, .centerX, .centerXWithinMargins:
return value.left
case .top, .topMargin, .centerY, .centerYWithinMargins, .lastBaseline, .firstBaseline:
return value.top
case .right, .rightMargin:
return -value.right
case .bottom, .bottomMargin:
return -value.bottom
case .leading, .leadingMargin:
return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.left : value.right
case .trailing, .trailingMargin:
return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.right : -value.left
case .width:
return -(value.left + value.right)
case .height:
return -(value.top + value.bottom)
case .notAnAttribute:
return 0.0
}
#else
switch layoutAttribute {
case .left, .centerX:
return value.left
case .top, .centerY, .lastBaseline, .firstBaseline:
return value.top
case .right:
return -value.right
case .bottom:
return -value.bottom
case .leading:
return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.left : value.right
case .trailing:
return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.right : -value.left
case .width:
return -(value.left + value.right)
case .height:
return -(value.top + value.bottom)
case .notAnAttribute:
return 0.0
}
#endif
}
return 0.0
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintDSL {
var target: AnyObject? { get }
func setLabel(_ value: String?)
func label() -> String?
}
extension ConstraintDSL {
public func setLabel(_ value: String?) {
objc_setAssociatedObject(self.target as Any, &labelKey, value, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
public func label() -> String? {
return objc_getAssociatedObject(self.target as Any, &labelKey) as? String
}
}
private var labelKey: UInt8 = 0
public protocol ConstraintBasicAttributesDSL : ConstraintDSL {
}
extension ConstraintBasicAttributesDSL {
// MARK: Basics
public var left: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.left)
}
public var top: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top)
}
public var right: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.right)
}
public var bottom: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom)
}
public var leading: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leading)
}
public var trailing: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.trailing)
}
public var width: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.width)
}
public var height: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height)
}
public var centerX: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerX)
}
public var centerY: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerY)
}
public var edges: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.edges)
}
public var size: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.size)
}
public var center: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.center)
}
}
public protocol ConstraintAttributesDSL : ConstraintBasicAttributesDSL {
}
extension ConstraintAttributesDSL {
// MARK: Baselines
@available(*, deprecated:3.0, message:"Use .lastBaseline instead")
public var baseline: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.lastBaseline)
}
@available(iOS 8.0, OSX 10.11, *)
public var lastBaseline: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.lastBaseline)
}
@available(iOS 8.0, OSX 10.11, *)
public var firstBaseline: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.firstBaseline)
}
// MARK: Margins
@available(iOS 8.0, *)
public var leftMargin: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leftMargin)
}
@available(iOS 8.0, *)
public var topMargin: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.topMargin)
}
@available(iOS 8.0, *)
public var rightMargin: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.rightMargin)
}
@available(iOS 8.0, *)
public var bottomMargin: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottomMargin)
}
@available(iOS 8.0, *)
public var leadingMargin: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leadingMargin)
}
@available(iOS 8.0, *)
public var trailingMargin: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.trailingMargin)
}
@available(iOS 8.0, *)
public var centerXWithinMargins: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerXWithinMargins)
}
@available(iOS 8.0, *)
public var centerYWithinMargins: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerYWithinMargins)
}
@available(iOS 8.0, *)
public var margins: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.margins)
}
@available(iOS 8.0, *)
public var centerWithinMargins: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerWithinMargins)
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintDescription {
internal let item: LayoutConstraintItem
internal var attributes: ConstraintAttributes
internal var relation: ConstraintRelation? = nil
internal var sourceLocation: (String, UInt)? = nil
internal var label: String? = nil
internal var related: ConstraintItem? = nil
internal var multiplier: ConstraintMultiplierTarget = 1.0
internal var constant: ConstraintConstantTarget = 0.0
internal var priority: ConstraintPriorityTarget = 1000.0
internal lazy var constraint: Constraint? = {
guard let relation = self.relation,
let related = self.related,
let sourceLocation = self.sourceLocation else {
return nil
}
let from = ConstraintItem(target: self.item, attributes: self.attributes)
return Constraint(
from: from,
to: related,
relation: relation,
sourceLocation: sourceLocation,
label: self.label,
multiplier: self.multiplier,
constant: self.constant,
priority: self.priority
)
}()
// MARK: Initialization
internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) {
self.item = item
self.attributes = attributes
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintInsetTarget: ConstraintConstantTarget {
}
extension Int: ConstraintInsetTarget {
}
extension UInt: ConstraintInsetTarget {
}
extension Float: ConstraintInsetTarget {
}
extension Double: ConstraintInsetTarget {
}
extension CGFloat: ConstraintInsetTarget {
}
extension ConstraintInsets: ConstraintInsetTarget {
}
extension ConstraintInsetTarget {
internal var constraintInsetTargetValue: ConstraintInsets {
if let amount = self as? ConstraintInsets {
return amount
} else if let amount = self as? Float {
return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
} else if let amount = self as? Double {
return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
} else if let amount = self as? CGFloat {
return ConstraintInsets(top: amount, left: amount, bottom: amount, right: amount)
} else if let amount = self as? Int {
return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
} else if let amount = self as? UInt {
return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
} else {
return ConstraintInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
#if os(iOS) || os(tvOS)
public typealias ConstraintInsets = UIEdgeInsets
#else
public typealias ConstraintInsets = NSEdgeInsets
#endif
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public final class ConstraintItem {
internal weak var target: AnyObject?
internal let attributes: ConstraintAttributes
internal init(target: AnyObject?, attributes: ConstraintAttributes) {
self.target = target
self.attributes = attributes
}
internal var layoutConstraintItem: LayoutConstraintItem? {
return self.target as? LayoutConstraintItem
}
}
public func ==(lhs: ConstraintItem, rhs: ConstraintItem) -> Bool {
// pointer equality
guard lhs !== rhs else {
return true
}
// must both have valid targets and identical attributes
guard let target1 = lhs.target,
let target2 = rhs.target,
target1 === target2 && lhs.attributes == rhs.attributes else {
return false
}
return true
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#endif
@available(iOS 9.0, OSX 10.11, *)
public extension ConstraintLayoutGuide {
public var snp: ConstraintLayoutGuideDSL {
return ConstraintLayoutGuideDSL(guide: self)
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
#if os(iOS) || os(tvOS)
@available(iOS 9.0, *)
public typealias ConstraintLayoutGuide = UILayoutGuide
#else
@available(OSX 10.11, *)
public typealias ConstraintLayoutGuide = NSLayoutGuide
#endif
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
@available(iOS 9.0, OSX 10.11, *)
public struct ConstraintLayoutGuideDSL: ConstraintAttributesDSL {
@discardableResult
public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
return ConstraintMaker.prepareConstraints(item: self.guide, closure: closure)
}
public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.makeConstraints(item: self.guide, closure: closure)
}
public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.remakeConstraints(item: self.guide, closure: closure)
}
public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.updateConstraints(item: self.guide, closure: closure)
}
public func removeConstraints() {
ConstraintMaker.removeConstraints(item: self.guide)
}
public var target: AnyObject? {
return self.guide
}
internal let guide: ConstraintLayoutGuide
internal init(guide: ConstraintLayoutGuide) {
self.guide = guide
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
#if os(iOS) || os(tvOS)
@available(iOS 8.0, *)
public typealias ConstraintLayoutSupport = UILayoutSupport
#else
public class ConstraintLayoutSupport {}
#endif
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
@available(iOS 8.0, *)
public struct ConstraintLayoutSupportDSL: ConstraintDSL {
public var target: AnyObject? {
return self.support
}
internal let support: ConstraintLayoutSupport
internal init(support: ConstraintLayoutSupport) {
self.support = support
}
public var top: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top)
}
public var bottom: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom)
}
public var height: ConstraintItem {
return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height)
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintMaker {
public var left: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.left)
}
public var top: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.top)
}
public var bottom: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.bottom)
}
public var right: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.right)
}
public var leading: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.leading)
}
public var trailing: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.trailing)
}
public var width: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.width)
}
public var height: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.height)
}
public var centerX: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.centerX)
}
public var centerY: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.centerY)
}
@available(*, deprecated:3.0, message:"Use lastBaseline instead")
public var baseline: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.lastBaseline)
}
public var lastBaseline: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.lastBaseline)
}
@available(iOS 8.0, OSX 10.11, *)
public var firstBaseline: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.firstBaseline)
}
@available(iOS 8.0, *)
public var leftMargin: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.leftMargin)
}
@available(iOS 8.0, *)
public var rightMargin: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.rightMargin)
}
@available(iOS 8.0, *)
public var topMargin: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.topMargin)
}
@available(iOS 8.0, *)
public var bottomMargin: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.bottomMargin)
}
@available(iOS 8.0, *)
public var leadingMargin: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.leadingMargin)
}
@available(iOS 8.0, *)
public var trailingMargin: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.trailingMargin)
}
@available(iOS 8.0, *)
public var centerXWithinMargins: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.centerXWithinMargins)
}
@available(iOS 8.0, *)
public var centerYWithinMargins: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.centerYWithinMargins)
}
public var edges: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.edges)
}
public var size: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.size)
}
public var center: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.center)
}
@available(iOS 8.0, *)
public var margins: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.margins)
}
@available(iOS 8.0, *)
public var centerWithinMargins: ConstraintMakerExtendable {
return self.makeExtendableWithAttributes(.centerWithinMargins)
}
private let item: LayoutConstraintItem
private var descriptions = [ConstraintDescription]()
internal init(item: LayoutConstraintItem) {
self.item = item
self.item.prepare()
}
internal func makeExtendableWithAttributes(_ attributes: ConstraintAttributes) -> ConstraintMakerExtendable {
let description = ConstraintDescription(item: self.item, attributes: attributes)
self.descriptions.append(description)
return ConstraintMakerExtendable(description)
}
internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
let maker = ConstraintMaker(item: item)
closure(maker)
var constraints: [Constraint] = []
for description in maker.descriptions {
guard let constraint = description.constraint else {
continue
}
constraints.append(constraint)
}
return constraints
}
internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
let constraints = prepareConstraints(item: item, closure: closure)
for constraint in constraints {
constraint.activateIfNeeded(updatingExisting: false)
}
}
internal static func remakeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
self.removeConstraints(item: item)
self.makeConstraints(item: item, closure: closure)
}
internal static func updateConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
guard item.constraints.count > 0 else {
self.makeConstraints(item: item, closure: closure)
return
}
let constraints = prepareConstraints(item: item, closure: closure)
for constraint in constraints {
constraint.activateIfNeeded(updatingExisting: true)
}
}
internal static func removeConstraints(item: LayoutConstraintItem) {
let constraints = item.constraints
for constraint in constraints {
constraint.deactivateIfNeeded()
}
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintMakerEditable: ConstraintMakerPriortizable {
@discardableResult
public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
self.description.multiplier = amount
return self
}
@discardableResult
public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue)
}
@discardableResult
public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable {
self.description.constant = amount.constraintOffsetTargetValue
return self
}
@discardableResult
public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable {
self.description.constant = amount.constraintInsetTargetValue
return self
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintMakerExtendable: ConstraintMakerRelatable {
public var left: ConstraintMakerExtendable {
self.description.attributes += .left
return self
}
public var top: ConstraintMakerExtendable {
self.description.attributes += .top
return self
}
public var bottom: ConstraintMakerExtendable {
self.description.attributes += .bottom
return self
}
public var right: ConstraintMakerExtendable {
self.description.attributes += .right
return self
}
public var leading: ConstraintMakerExtendable {
self.description.attributes += .leading
return self
}
public var trailing: ConstraintMakerExtendable {
self.description.attributes += .trailing
return self
}
public var width: ConstraintMakerExtendable {
self.description.attributes += .width
return self
}
public var height: ConstraintMakerExtendable {
self.description.attributes += .height
return self
}
public var centerX: ConstraintMakerExtendable {
self.description.attributes += .centerX
return self
}
public var centerY: ConstraintMakerExtendable {
self.description.attributes += .centerY
return self
}
@available(*, deprecated:3.0, message:"Use lastBaseline instead")
public var baseline: ConstraintMakerExtendable {
self.description.attributes += .lastBaseline
return self
}
public var lastBaseline: ConstraintMakerExtendable {
self.description.attributes += .lastBaseline
return self
}
@available(iOS 8.0, OSX 10.11, *)
public var firstBaseline: ConstraintMakerExtendable {
self.description.attributes += .firstBaseline
return self
}
@available(iOS 8.0, *)
public var leftMargin: ConstraintMakerExtendable {
self.description.attributes += .leftMargin
return self
}
@available(iOS 8.0, *)
public var rightMargin: ConstraintMakerExtendable {
self.description.attributes += .rightMargin
return self
}
@available(iOS 8.0, *)
public var topMargin: ConstraintMakerExtendable {
self.description.attributes += .topMargin
return self
}
@available(iOS 8.0, *)
public var bottomMargin: ConstraintMakerExtendable {
self.description.attributes += .bottomMargin
return self
}
@available(iOS 8.0, *)
public var leadingMargin: ConstraintMakerExtendable {
self.description.attributes += .leadingMargin
return self
}
@available(iOS 8.0, *)
public var trailingMargin: ConstraintMakerExtendable {
self.description.attributes += .trailingMargin
return self
}
@available(iOS 8.0, *)
public var centerXWithinMargins: ConstraintMakerExtendable {
self.description.attributes += .centerXWithinMargins
return self
}
@available(iOS 8.0, *)
public var centerYWithinMargins: ConstraintMakerExtendable {
self.description.attributes += .centerYWithinMargins
return self
}
public var edges: ConstraintMakerExtendable {
self.description.attributes += .edges
return self
}
public var size: ConstraintMakerExtendable {
self.description.attributes += .size
return self
}
@available(iOS 8.0, *)
public var margins: ConstraintMakerExtendable {
self.description.attributes += .margins
return self
}
@available(iOS 8.0, *)
public var centerWithinMargins: ConstraintMakerExtendable {
self.description.attributes += .centerWithinMargins
return self
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintMakerFinalizable {
internal let description: ConstraintDescription
internal init(_ description: ConstraintDescription) {
self.description = description
}
@discardableResult
public func labeled(_ label: String) -> ConstraintMakerFinalizable {
self.description.label = label
return self
}
public var constraint: Constraint {
return self.description.constraint!
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintMakerPriortizable: ConstraintMakerFinalizable {
@discardableResult
public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable {
self.description.priority = amount.value
return self
}
@discardableResult
public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable {
self.description.priority = amount
return self
}
@available(*, deprecated:3.0, message:"Use priority(.required) instead.")
@discardableResult
public func priorityRequired() -> ConstraintMakerFinalizable {
return self.priority(.required)
}
@available(*, deprecated:3.0, message:"Use priority(.high) instead.")
@discardableResult
public func priorityHigh() -> ConstraintMakerFinalizable {
return self.priority(.high)
}
@available(*, deprecated:3.0, message:"Use priority(.medium) instead.")
@discardableResult
public func priorityMedium() -> ConstraintMakerFinalizable {
return self.priority(.medium)
}
@available(*, deprecated:3.0, message:"Use priority(.low) instead.")
@discardableResult
public func priorityLow() -> ConstraintMakerFinalizable {
return self.priority(.low)
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class ConstraintMakerRelatable {
internal let description: ConstraintDescription
internal init(_ description: ConstraintDescription) {
self.description = description
}
internal func relatedTo(_ other: ConstraintRelatableTarget, relation: ConstraintRelation, file: String, line: UInt) -> ConstraintMakerEditable {
let related: ConstraintItem
let constant: ConstraintConstantTarget
if let other = other as? ConstraintItem {
guard other.attributes == ConstraintAttributes.none ||
other.attributes.layoutAttributes.count <= 1 ||
other.attributes.layoutAttributes == self.description.attributes.layoutAttributes ||
other.attributes == .edges && self.description.attributes == .margins ||
other.attributes == .margins && self.description.attributes == .edges else {
fatalError("Cannot constraint to multiple non identical attributes. (\(file), \(line))");
}
related = other
constant = 0.0
} else if let other = other as? ConstraintView {
related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)
constant = 0.0
} else if let other = other as? ConstraintConstantTarget {
related = ConstraintItem(target: nil, attributes: ConstraintAttributes.none)
constant = other
} else if #available(iOS 9.0, OSX 10.11, *), let other = other as? ConstraintLayoutGuide {
related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)
constant = 0.0
} else {
fatalError("Invalid constraint. (\(file), \(line))")
}
let editable = ConstraintMakerEditable(self.description)
editable.description.sourceLocation = (file, line)
editable.description.relation = relation
editable.description.related = related
editable.description.constant = constant
return editable
}
@discardableResult
public func equalTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .equal, file: file, line: line)
}
@discardableResult
public func equalToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
}
return self.relatedTo(other, relation: .equal, file: file, line: line)
}
@discardableResult
public func lessThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
}
@discardableResult
public func lessThanOrEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.")
}
return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
}
@discardableResult
public func greaterThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)
}
@discardableResult
public func greaterThanOrEqualToSuperview(_ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
guard let other = self.description.item.superview else {
fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.")
}
return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintMultiplierTarget {
var constraintMultiplierTargetValue: CGFloat { get }
}
extension Int: ConstraintMultiplierTarget {
public var constraintMultiplierTargetValue: CGFloat {
return CGFloat(self)
}
}
extension UInt: ConstraintMultiplierTarget {
public var constraintMultiplierTargetValue: CGFloat {
return CGFloat(self)
}
}
extension Float: ConstraintMultiplierTarget {
public var constraintMultiplierTargetValue: CGFloat {
return CGFloat(self)
}
}
extension Double: ConstraintMultiplierTarget {
public var constraintMultiplierTargetValue: CGFloat {
return CGFloat(self)
}
}
extension CGFloat: ConstraintMultiplierTarget {
public var constraintMultiplierTargetValue: CGFloat {
return self
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintOffsetTarget: ConstraintConstantTarget {
}
extension Int: ConstraintOffsetTarget {
}
extension UInt: ConstraintOffsetTarget {
}
extension Float: ConstraintOffsetTarget {
}
extension Double: ConstraintOffsetTarget {
}
extension CGFloat: ConstraintOffsetTarget {
}
extension ConstraintOffsetTarget {
internal var constraintOffsetTargetValue: CGFloat {
let offset: CGFloat
if let amount = self as? Float {
offset = CGFloat(amount)
} else if let amount = self as? Double {
offset = CGFloat(amount)
} else if let amount = self as? CGFloat {
offset = CGFloat(amount)
} else if let amount = self as? Int {
offset = CGFloat(amount)
} else if let amount = self as? UInt {
offset = CGFloat(amount)
} else {
offset = 0.0
}
return offset
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public struct ConstraintPriority : ExpressibleByFloatLiteral, Equatable, Strideable {
public typealias FloatLiteralType = Float
public let value: Float
public init(floatLiteral value: Float) {
self.value = value
}
public init(_ value: Float) {
self.value = value
}
public static var required: ConstraintPriority {
return 1000.0
}
public static var high: ConstraintPriority {
return 750.0
}
public static var medium: ConstraintPriority {
#if os(OSX)
return 501.0
#else
return 500.0
#endif
}
public static var low: ConstraintPriority {
return 250.0
}
public static func ==(lhs: ConstraintPriority, rhs: ConstraintPriority) -> Bool {
return lhs.value == rhs.value
}
// MARK: Strideable
public func advanced(by n: FloatLiteralType) -> ConstraintPriority {
return ConstraintPriority(floatLiteral: value + n)
}
public func distance(to other: ConstraintPriority) -> FloatLiteralType {
return other.value - value
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintPriorityTarget {
var constraintPriorityTargetValue: Float { get }
}
extension Int: ConstraintPriorityTarget {
public var constraintPriorityTargetValue: Float {
return Float(self)
}
}
extension UInt: ConstraintPriorityTarget {
public var constraintPriorityTargetValue: Float {
return Float(self)
}
}
extension Float: ConstraintPriorityTarget {
public var constraintPriorityTargetValue: Float {
return self
}
}
extension Double: ConstraintPriorityTarget {
public var constraintPriorityTargetValue: Float {
return Float(self)
}
}
extension CGFloat: ConstraintPriorityTarget {
public var constraintPriorityTargetValue: Float {
return Float(self)
}
}
#if os(iOS) || os(tvOS)
extension UILayoutPriority: ConstraintPriorityTarget {
public var constraintPriorityTargetValue: Float {
return self.rawValue
}
}
#endif
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol ConstraintRelatableTarget {
}
extension Int: ConstraintRelatableTarget {
}
extension UInt: ConstraintRelatableTarget {
}
extension Float: ConstraintRelatableTarget {
}
extension Double: ConstraintRelatableTarget {
}
extension CGFloat: ConstraintRelatableTarget {
}
extension CGSize: ConstraintRelatableTarget {
}
extension CGPoint: ConstraintRelatableTarget {
}
extension ConstraintInsets: ConstraintRelatableTarget {
}
extension ConstraintItem: ConstraintRelatableTarget {
}
extension ConstraintView: ConstraintRelatableTarget {
}
@available(iOS 9.0, OSX 10.11, *)
extension ConstraintLayoutGuide: ConstraintRelatableTarget {
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
internal enum ConstraintRelation : Int {
case equal = 1
case lessThanOrEqual
case greaterThanOrEqual
internal var layoutRelation: LayoutRelation {
get {
switch(self) {
case .equal:
return .equal
case .lessThanOrEqual:
return .lessThanOrEqual
case .greaterThanOrEqual:
return .greaterThanOrEqual
}
}
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public extension ConstraintView {
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_left: ConstraintItem { return self.snp.left }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_top: ConstraintItem { return self.snp.top }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_right: ConstraintItem { return self.snp.right }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_bottom: ConstraintItem { return self.snp.bottom }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_leading: ConstraintItem { return self.snp.leading }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_trailing: ConstraintItem { return self.snp.trailing }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_width: ConstraintItem { return self.snp.width }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_height: ConstraintItem { return self.snp.height }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_centerX: ConstraintItem { return self.snp.centerX }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_centerY: ConstraintItem { return self.snp.centerY }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_baseline: ConstraintItem { return self.snp.baseline }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, OSX 10.11, *)
public var snp_lastBaseline: ConstraintItem { return self.snp.lastBaseline }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, OSX 10.11, *)
public var snp_firstBaseline: ConstraintItem { return self.snp.firstBaseline }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_leftMargin: ConstraintItem { return self.snp.leftMargin }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_topMargin: ConstraintItem { return self.snp.topMargin }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_rightMargin: ConstraintItem { return self.snp.rightMargin }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_bottomMargin: ConstraintItem { return self.snp.bottomMargin }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_leadingMargin: ConstraintItem { return self.snp.leadingMargin }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_trailingMargin: ConstraintItem { return self.snp.trailingMargin }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_centerXWithinMargins: ConstraintItem { return self.snp.centerXWithinMargins }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_centerYWithinMargins: ConstraintItem { return self.snp.centerYWithinMargins }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_edges: ConstraintItem { return self.snp.edges }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_size: ConstraintItem { return self.snp.size }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public var snp_center: ConstraintItem { return self.snp.center }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_margins: ConstraintItem { return self.snp.margins }
@available(iOS, deprecated:3.0, message:"Use newer snp.* syntax.")
@available(iOS 8.0, *)
public var snp_centerWithinMargins: ConstraintItem { return self.snp.centerWithinMargins }
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public func snp_prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
return self.snp.prepareConstraints(closure)
}
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public func snp_makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
self.snp.makeConstraints(closure)
}
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public func snp_remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
self.snp.remakeConstraints(closure)
}
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public func snp_updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
self.snp.updateConstraints(closure)
}
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
public func snp_removeConstraints() {
self.snp.removeConstraints()
}
public var snp: ConstraintViewDSL {
return ConstraintViewDSL(view: self)
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
#if os(iOS) || os(tvOS)
public typealias ConstraintView = UIView
#else
public typealias ConstraintView = NSView
#endif
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public struct ConstraintViewDSL: ConstraintAttributesDSL {
@discardableResult
public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
return ConstraintMaker.prepareConstraints(item: self.view, closure: closure)
}
public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.makeConstraints(item: self.view, closure: closure)
}
public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.remakeConstraints(item: self.view, closure: closure)
}
public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
ConstraintMaker.updateConstraints(item: self.view, closure: closure)
}
public func removeConstraints() {
ConstraintMaker.removeConstraints(item: self.view)
}
public var contentHuggingHorizontalPriority: Float {
get {
return self.view.contentHuggingPriority(for: .horizontal).rawValue
}
set {
self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .horizontal)
}
}
public var contentHuggingVerticalPriority: Float {
get {
return self.view.contentHuggingPriority(for: .vertical).rawValue
}
set {
self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .vertical)
}
}
public var contentCompressionResistanceHorizontalPriority: Float {
get {
return self.view.contentCompressionResistancePriority(for: .horizontal).rawValue
}
set {
self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .horizontal)
}
}
public var contentCompressionResistanceVerticalPriority: Float {
get {
return self.view.contentCompressionResistancePriority(for: .vertical).rawValue
}
set {
self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .vertical)
}
}
public var target: AnyObject? {
return self.view
}
internal let view: ConstraintView
internal init(view: ConstraintView) {
self.view = view
}
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public extension LayoutConstraint {
override public var description: String {
var description = "<"
description += descriptionForObject(self)
if let firstItem = conditionalOptional(from: self.firstItem) {
description += " \(descriptionForObject(firstItem))"
}
if self.firstAttribute != .notAnAttribute {
description += ".\(descriptionForAttribute(self.firstAttribute))"
}
description += " \(descriptionForRelation(self.relation))"
if let secondItem = self.secondItem {
description += " \(descriptionForObject(secondItem))"
}
if self.secondAttribute != .notAnAttribute {
description += ".\(descriptionForAttribute(self.secondAttribute))"
}
if self.multiplier != 1.0 {
description += " * \(self.multiplier)"
}
if self.secondAttribute == .notAnAttribute {
description += " \(self.constant)"
} else {
if self.constant > 0.0 {
description += " + \(self.constant)"
} else if self.constant < 0.0 {
description += " - \(abs(self.constant))"
}
}
if self.priority.rawValue != 1000.0 {
description += " ^\(self.priority)"
}
description += ">"
return description
}
}
private func descriptionForRelation(_ relation: LayoutRelation) -> String {
switch relation {
case .equal: return "=="
case .greaterThanOrEqual: return ">="
case .lessThanOrEqual: return "<="
}
}
private func descriptionForAttribute(_ attribute: LayoutAttribute) -> String {
#if os(iOS) || os(tvOS)
switch attribute {
case .notAnAttribute: return "notAnAttribute"
case .top: return "top"
case .left: return "left"
case .bottom: return "bottom"
case .right: return "right"
case .leading: return "leading"
case .trailing: return "trailing"
case .width: return "width"
case .height: return "height"
case .centerX: return "centerX"
case .centerY: return "centerY"
case .lastBaseline: return "lastBaseline"
case .firstBaseline: return "firstBaseline"
case .topMargin: return "topMargin"
case .leftMargin: return "leftMargin"
case .bottomMargin: return "bottomMargin"
case .rightMargin: return "rightMargin"
case .leadingMargin: return "leadingMargin"
case .trailingMargin: return "trailingMargin"
case .centerXWithinMargins: return "centerXWithinMargins"
case .centerYWithinMargins: return "centerYWithinMargins"
}
#else
switch attribute {
case .notAnAttribute: return "notAnAttribute"
case .top: return "top"
case .left: return "left"
case .bottom: return "bottom"
case .right: return "right"
case .leading: return "leading"
case .trailing: return "trailing"
case .width: return "width"
case .height: return "height"
case .centerX: return "centerX"
case .centerY: return "centerY"
case .lastBaseline: return "lastBaseline"
case .firstBaseline: return "firstBaseline"
}
#endif
}
private func conditionalOptional<T>(from object: Optional<T>) -> Optional<T> {
return object
}
private func conditionalOptional<T>(from object: T) -> Optional<T> {
return Optional.some(object)
}
private func descriptionForObject(_ object: AnyObject) -> String {
let pointerDescription = String(format: "%p", UInt(bitPattern: ObjectIdentifier(object)))
var desc = ""
desc += type(of: object).description()
if let object = object as? ConstraintView {
desc += ":\(object.snp.label() ?? pointerDescription)"
} else if let object = object as? LayoutConstraint {
desc += ":\(object.label ?? pointerDescription)"
} else {
desc += ":\(pointerDescription)"
}
if let object = object as? LayoutConstraint, let file = object.constraint?.sourceLocation.0, let line = object.constraint?.sourceLocation.1 {
desc += "@\((file as NSString).lastPathComponent)#\(line)"
}
desc += ""
return desc
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public class LayoutConstraint : NSLayoutConstraint {
public var label: String? {
get {
return self.identifier
}
set {
self.identifier = newValue
}
}
internal weak var constraint: Constraint? = nil
}
internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool {
guard lhs.firstItem === rhs.firstItem &&
lhs.secondItem === rhs.secondItem &&
lhs.firstAttribute == rhs.firstAttribute &&
lhs.secondAttribute == rhs.secondAttribute &&
lhs.relation == rhs.relation &&
lhs.priority == rhs.priority &&
lhs.multiplier == rhs.multiplier else {
return false
}
return true
}
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
public protocol LayoutConstraintItem: class {
}
@available(iOS 9.0, OSX 10.11, *)
extension ConstraintLayoutGuide : LayoutConstraintItem {
}
extension ConstraintView : LayoutConstraintItem {
}
extension LayoutConstraintItem {
internal func prepare() {
if let view = self as? ConstraintView {
view.translatesAutoresizingMaskIntoConstraints = false
}
}
internal var superview: ConstraintView? {
if let view = self as? ConstraintView {
return view.superview
}
if #available(iOS 9.0, OSX 10.11, *), let guide = self as? ConstraintLayoutGuide {
return guide.owningView
}
return nil
}
internal var constraints: [Constraint] {
return self.constraintsSet.allObjects as! [Constraint]
}
internal func add(constraints: [Constraint]) {
let constraintsSet = self.constraintsSet
for constraint in constraints {
constraintsSet.add(constraint)
}
}
internal func remove(constraints: [Constraint]) {
let constraintsSet = self.constraintsSet
for constraint in constraints {
constraintsSet.remove(constraint)
}
}
private var constraintsSet: NSMutableSet {
let constraintsSet: NSMutableSet
if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet {
constraintsSet = existing
} else {
constraintsSet = NSMutableSet()
objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return constraintsSet
}
}
private var constraintsKey: UInt8 = 0
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
#if os(iOS) || os(tvOS)
import UIKit
#if swift(>=4.2)
typealias LayoutRelation = NSLayoutConstraint.Relation
typealias LayoutAttribute = NSLayoutConstraint.Attribute
#else
typealias LayoutRelation = NSLayoutRelation
typealias LayoutAttribute = NSLayoutAttribute
#endif
typealias LayoutPriority = UILayoutPriority
#else
import AppKit
typealias LayoutRelation = NSLayoutConstraint.Relation
typealias LayoutAttribute = NSLayoutConstraint.Attribute
typealias LayoutPriority = NSLayoutConstraint.Priority
#endif
//
// SnapKit
//
// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if os(iOS) || os(tvOS)
import UIKit
#endif
@available(iOS 8.0, *)
public extension ConstraintLayoutSupport {
public var snp: ConstraintLayoutSupportDSL {
return ConstraintLayoutSupportDSL(support: self)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>4.2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_SnapKit : NSObject
@end
@implementation PodsDummy_SnapKit
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double SnapKitVersionNumber;
FOUNDATION_EXPORT const unsigned char SnapKitVersionString[];
framework module SnapKit {
umbrella header "SnapKit-umbrella.h"
export *
module * { export * }
}
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -suppress-warnings
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/SnapKit
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment