Commit a955fb1d authored by jz's avatar jz

add files

parent 2f7abd9a
......@@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
254220CCDB7FEC958716D0F9 /* Pods_GMShareSDK_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC4C8CE40CC66CCDF175F1F /* Pods_GMShareSDK_Example.framework */; };
5FE0A1911F05616A09111B97 /* libPods-GMShareSDK_Example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6DDAF4612C6D62590ACB4BE /* libPods-GMShareSDK_Example.a */; };
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
......@@ -23,7 +23,7 @@
6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; };
71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; };
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
D23B35D1CE6251505C5CE0C2 /* Pods_GMShareSDK_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB21F612ECB7A93A9931CD51 /* Pods_GMShareSDK_Tests.framework */; };
B6CFE1A7EE9A2EBF4A8A30F4 /* libPods-GMShareSDK_Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE54D6F74100635E750A5047 /* libPods-GMShareSDK_Tests.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -39,7 +39,6 @@
/* Begin PBXFileReference section */
035B645BC46FB80B490A9FBE /* Pods-GMShareSDK_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMShareSDK_Tests.release.xcconfig"; path = "Target Support Files/Pods-GMShareSDK_Tests/Pods-GMShareSDK_Tests.release.xcconfig"; sourceTree = "<group>"; };
174E39EBC691D1A6D6E7E128 /* Pods-GMShareSDK_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMShareSDK_Example.release.xcconfig"; path = "Target Support Files/Pods-GMShareSDK_Example/Pods-GMShareSDK_Example.release.xcconfig"; sourceTree = "<group>"; };
2DC4C8CE40CC66CCDF175F1F /* Pods_GMShareSDK_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GMShareSDK_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5EFECF96C065D7562836F22B /* Pods-GMShareSDK_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMShareSDK_Tests.debug.xcconfig"; path = "Target Support Files/Pods-GMShareSDK_Tests/Pods-GMShareSDK_Tests.debug.xcconfig"; sourceTree = "<group>"; };
6003F58A195388D20070C39A /* GMShareSDK_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GMShareSDK_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
......@@ -66,7 +65,8 @@
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
B0EC0126CB08246293DA5519 /* Pods-GMShareSDK_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GMShareSDK_Example.debug.xcconfig"; path = "Target Support Files/Pods-GMShareSDK_Example/Pods-GMShareSDK_Example.debug.xcconfig"; sourceTree = "<group>"; };
CB31F369DA0CC8DE5739239C /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
DB21F612ECB7A93A9931CD51 /* Pods_GMShareSDK_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GMShareSDK_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CE54D6F74100635E750A5047 /* libPods-GMShareSDK_Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-GMShareSDK_Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
D6DDAF4612C6D62590ACB4BE /* libPods-GMShareSDK_Example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-GMShareSDK_Example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -77,7 +77,7 @@
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
254220CCDB7FEC958716D0F9 /* Pods_GMShareSDK_Example.framework in Frameworks */,
5FE0A1911F05616A09111B97 /* libPods-GMShareSDK_Example.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -88,7 +88,7 @@
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */,
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */,
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */,
D23B35D1CE6251505C5CE0C2 /* Pods_GMShareSDK_Tests.framework in Frameworks */,
B6CFE1A7EE9A2EBF4A8A30F4 /* libPods-GMShareSDK_Tests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -123,8 +123,8 @@
6003F58F195388D20070C39A /* CoreGraphics.framework */,
6003F591195388D20070C39A /* UIKit.framework */,
6003F5AF195388D20070C39A /* XCTest.framework */,
2DC4C8CE40CC66CCDF175F1F /* Pods_GMShareSDK_Example.framework */,
DB21F612ECB7A93A9931CD51 /* Pods_GMShareSDK_Tests.framework */,
D6DDAF4612C6D62590ACB4BE /* libPods-GMShareSDK_Example.a */,
CE54D6F74100635E750A5047 /* libPods-GMShareSDK_Tests.a */,
);
name = Frameworks;
sourceTree = "<group>";
......@@ -207,7 +207,7 @@
6003F586195388D20070C39A /* Sources */,
6003F587195388D20070C39A /* Frameworks */,
6003F588195388D20070C39A /* Resources */,
1E6638650B5821ED2D4A5A72 /* [CP] Embed Pods Frameworks */,
353A74336C214C746CEE5C52 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
......@@ -295,22 +295,22 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
1E6638650B5821ED2D4A5A72 /* [CP] Embed Pods Frameworks */ = {
353A74336C214C746CEE5C52 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-GMShareSDK_Example/Pods-GMShareSDK_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/GMShareSDK/GMShareSDK.framework",
"${PODS_ROOT}/Target Support Files/Pods-GMShareSDK_Example/Pods-GMShareSDK_Example-resources.sh",
"${PODS_ROOT}/WeiboSDK/libWeiboSDK/WeiboSDK.bundle",
);
name = "[CP] Embed Pods Frameworks";
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GMShareSDK.framework",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GMShareSDK_Example/Pods-GMShareSDK_Example-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GMShareSDK_Example/Pods-GMShareSDK_Example-resources.sh\"\n";
showEnvVarsInLog = 0;
};
C3B22D8ECB0F537CE6B82DCE /* [CP] Check Pods Manifest.lock */ = {
......
use_frameworks!
#use_frameworks!
platform :ios, '8.0'
#require 'pry'
#open source
source 'https://github.com/CocoaPods/Specs.git'
#our company
source 'git@git.wanmeizhensuo.com:gengmeiios/GMSpecs.git'
target 'GMShareSDK_Example' do
pod 'GMShareSDK', :path => '../'
......
PODS:
- GMShareSDK (0.1.0)
- Base64nl (1.2)
- BDOpenSDKKit (1.0.0)
- DouyinOpenSDK (1.4.1):
- BDOpenSDKKit (~> 1.0.0)
- GMFoundation (1.0.2):
- Base64nl (= 1.2)
- GMKit (1.1.4):
- GMKit/Category (= 1.1.4)
- GMKit/Color (= 1.1.4)
- GMKit/Constant (= 1.1.4)
- GMKit/FDFullscreenPopGesture (= 1.1.4)
- GMKit/Kit (= 1.1.4)
- GMKit/Protocol (= 1.1.4)
- Masonry
- SDWebImage
- GMKit/Category (1.1.4):
- GMKit/Color (= 1.1.4)
- GMKit/Constant (= 1.1.4)
- GMKit/Protocol (= 1.1.4)
- Masonry
- SDWebImage
- GMKit/Color (1.1.4):
- Masonry
- SDWebImage
- GMKit/Constant (1.1.4):
- Masonry
- SDWebImage
- GMKit/FDFullscreenPopGesture (1.1.4):
- Masonry
- SDWebImage
- GMKit/Kit (1.1.4):
- GMKit/Category (= 1.1.4)
- GMKit/Color (= 1.1.4)
- GMKit/Constant (= 1.1.4)
- GMKit/Protocol (= 1.1.4)
- Masonry
- SDWebImage
- GMKit/Protocol (1.1.4):
- Masonry
- SDWebImage
- GMShareSDK (0.1.0):
- DouyinOpenSDK
- GMFoundation
- GMKit
- WechatOpenSDK
- WeiboSDK
- Masonry (1.1.0)
- SDWebImage (5.4.0):
- SDWebImage/Core (= 5.4.0)
- SDWebImage/Core (5.4.0)
- WechatOpenSDK (1.8.6)
- WeiboSDK (3.1.3)
DEPENDENCIES:
- GMShareSDK (from `../`)
SPEC REPOS:
"git@git.wanmeizhensuo.com:gengmeiios/GMSpecs.git":
- GMFoundation
- GMKit
https://github.com/cocoapods/specs.git:
- Base64nl
- BDOpenSDKKit
- DouyinOpenSDK
- Masonry
- SDWebImage
- WechatOpenSDK
- WeiboSDK
EXTERNAL SOURCES:
GMShareSDK:
:path: "../"
SPEC CHECKSUMS:
GMShareSDK: 2c3a3b816eae7ca8614333605a5c0615321c7215
Base64nl: a497bdcd1c01ea793d36b399016195a8713c0e95
BDOpenSDKKit: 3fb530ce73f85a7d6ee69e7fd3d9158444c5bd09
DouyinOpenSDK: 5ba83de22963ba7a3ba70c8ff11dfcb2885ecc2b
GMFoundation: c3a842044cb34e27ca831ec7aedca85c1399bbfb
GMKit: 11c9ab9a317f381a05b0e1e577dd95a495625edf
GMShareSDK: 7b526f0e0bed23eecb8f27da08c7cd6e66be08f8
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
SDWebImage: 5bf6aec6481ae2a062bdc59f9d6c1d1e552090e0
WechatOpenSDK: 368ae03b72ee3ea1328c4f11326fbb5d2721d118
WeiboSDK: acb067053668102cf07d01aa7604350162c2e466
PODFILE CHECKSUM: 9ff4536b9b3f79ff5f4703b2beaf332c9d475030
PODFILE CHECKSUM: 2ac9940f13453015746009e8a777570546d03d30
COCOAPODS: 1.7.4
//
// Base64.h
//
// Version 1.2
//
// Created by Nick Lockwood on 12/01/2012.
// Copyright (C) 2012 Charcoal Design
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/Base64
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import <Foundation/Foundation.h>
@interface NSData (Base64)
+ (NSData *)dataWithBase64EncodedString:(NSString *)string;
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
- (NSString *)base64EncodedString;
@end
@interface NSString (Base64)
+ (NSString *)stringWithBase64EncodedString:(NSString *)string;
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
- (NSString *)base64EncodedString;
- (NSString *)base64DecodedString;
- (NSData *)base64DecodedData;
@end
//
// Base64.m
//
// Version 1.2
//
// Created by Nick Lockwood on 12/01/2012.
// Copyright (C) 2012 Charcoal Design
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/Base64
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an aacknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import "Base64.h"
#pragma GCC diagnostic ignored "-Wselector"
#import <Availability.h>
#if !__has_feature(objc_arc)
#error This library requires automatic reference counting
#endif
@implementation NSData (Base64)
+ (NSData *)dataWithBase64EncodedString:(NSString *)string
{
if (![string length]) return nil;
NSData *decoded = nil;
#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
if (![NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)])
{
decoded = [[self alloc] initWithBase64Encoding:[string stringByReplacingOccurrencesOfString:@"[^A-Za-z0-9+/=]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [string length])]];
}
else
#endif
{
decoded = [[self alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters];
}
return [decoded length]? decoded: nil;
}
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
{
if (![self length]) return nil;
NSString *encoded = nil;
#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
if (![NSData instancesRespondToSelector:@selector(base64EncodedStringWithOptions:)])
{
encoded = [self base64Encoding];
}
else
#endif
{
switch (wrapWidth)
{
case 64:
{
return [self base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
case 76:
{
return [self base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
}
default:
{
encoded = [self base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
}
}
}
if (!wrapWidth || wrapWidth >= [encoded length])
{
return encoded;
}
wrapWidth = (wrapWidth / 4) * 4;
NSMutableString *result = [NSMutableString string];
for (NSUInteger i = 0; i < [encoded length]; i+= wrapWidth)
{
if (i + wrapWidth >= [encoded length])
{
[result appendString:[encoded substringFromIndex:i]];
break;
}
[result appendString:[encoded substringWithRange:NSMakeRange(i, wrapWidth)]];
[result appendString:@"\r\n"];
}
return result;
}
- (NSString *)base64EncodedString
{
return [self base64EncodedStringWithWrapWidth:0];
}
@end
@implementation NSString (Base64)
+ (NSString *)stringWithBase64EncodedString:(NSString *)string
{
NSData *data = [NSData dataWithBase64EncodedString:string];
if (data)
{
return [[self alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
return nil;
}
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
return [data base64EncodedStringWithWrapWidth:wrapWidth];
}
- (NSString *)base64EncodedString
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
return [data base64EncodedString];
}
- (NSString *)base64DecodedString
{
return [NSString stringWithBase64EncodedString:self];
}
- (NSData *)base64DecodedData
{
return [NSData dataWithBase64EncodedString:self];
}
@end
Base64
Version 1.2, Feburary 7th, 2014
Copyright (C) 2012 Charcoal Design
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
\ No newline at end of file
NOTE: As of iOS 7 and Mac OS 10.9, this library is not longer needed
----------------------------------------------------------------------
In the iOS 7 and Mac OS 10.9 SDKs, Apple introduced new base64 methods on NSData that make it unnecessary to use a 3rd party base 64 decoding library. What's more, they exposed access to private base64 methods that are retrospectively available back as far as IOS 4 and Mac OS 6.
Although use of this library is no longer required, you may still find it useful, as it abstracts the complexity of supporting the deprecated Base64 methods for older OS versions, and also provides some additional utility functions, such as arbitrary wrap widths and NSString encoding.
Purpose
--------------
Base64 is a set of categories that provide methods to encode and decode data as a base-64-encoded string.
Supported OS & SDK Versions
-----------------------------
* Supported build target - iOS 7.0 / Mac OS 10.9 (Xcode 5.0, Apple LLVM compiler 5.0)
* Earliest supported deployment target - iOS 5.0 / Mac OS 10.7
* Earliest compatible deployment target - iOS 4.3 / Mac OS 10.6
NOTE: 'Supported' means that the library has been tested with this version. 'Compatible' means that the library should work on this iOS version (i.e. it doesn't rely on any unavailable SDK features) but is no longer being tested for compatibility and may require tweaking or bug fixes to run correctly.
ARC Compatibility
------------------
As of version 1.1, Base64 requires ARC. If you wish to use Base64 in a non-ARC project, just add the -fobjc-arc compiler flag to the Base64.m file. To do this, go to the Build Phases tab in your target settings, open the Compile Sources group, double-click Base64.m in the list and type -fobjc-arc into the popover.
If you wish to convert your whole project to ARC, comment out the #error line in Base64.m, then run the Edit > Refactor > Convert to Objective-C ARC... tool in Xcode and make sure all files that you wish to use ARC for (including Base64.m) are checked.
Thread Safety
--------------
All the Base64 methods should be safe to call from multiple threads concurrently.
Installation
--------------
To use the Base64 category in an app, just drag the category files (demo files and assets are not needed) into your project and import the header file into any class where you wish to make use of the Base64 functionality.
NSData Extensions
----------------------
Base64 extends NSData with the following methods:
+ (NSData *)dataWithBase64EncodedString:(NSString *)string;
Takes a base-64-encoded string and returns an autoreleased NSData object containing the decoded data. Any non-base-64 characters in the string are ignored, so it is safe to pass a string containing line breaks or other delimiters.
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
Encodes the data as a base-64-encoded string and returns it. The wrapWidth argument allows you to specify the number of characters at which the output should wrap onto a new line. The value of wrapWidth must be a multiple of four. Values that are not a multiple of four will be truncated to the nearest multiple. A value of zero indicates that the data should not wrap.
- (NSString *)base64EncodedString;
Encodes the data as a base-64-encoded string without any wrapping (line breaks).
NSString Extensions
----------------------
Base64 extends NSString with the following methods:
+ (NSString *)stringWithBase64EncodedString:(NSString *)string;
Takes a base-64-encoded string and returns an autoreleased NSString object containing the decoded data, interpreted using UTF8 encoding. The vast majority of use cases for Base64 encoding use Ascii or UTF8 strings, so this should be sufficient for most purposes. If you do need to decode string data in an encoding other than UTF8, convert your string to an NSData object first and then use the NSData dataWithBase64EncodedString: method instead.
- (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth;
Converts the string data to UTF8 data and then encodes the data as a base-64-encoded string and returns it. The wrapWidth argument allows you to specify the number of characters at which the output should wrap onto a new line. The value of wrapWidth must be a multiple of four. Values that are not a multiple of four will be truncated to the nearest multiple. A value of zero indicates that the data should not wrap.
- (NSString *)base64EncodedString;
Encodes the string as UTF8 data and then encodes that as a base-64-encoded string without any wrapping (line breaks).
- (NSString *)base64DecodedString;
Treats the string as a base-64-encoded string and returns an autoreleased NSString object containing the decoded data, interpreted using UTF8 encoding. Any non-base-64 characters in the string are ignored, so it is safe to use a string containing line breaks or other delimiters.
- (NSData *)base64DecodedData;
Treats the string as base-64-encoded data and returns an autoreleased NSData object containing the decoded data. Any non-base-64 characters in the string are ignored, so it is safe to use a string containing line breaks or other delimiters.
\ No newline at end of file
//
// DouyinOpenSDKApi.h
// 所有Api接口
//
// Created by 抖音短视频 on 18/9/2017.
// Copyright (c) 2018年 抖音短视频. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "DouyinOpenSDKApiObject.h"
NS_ASSUME_NONNULL_BEGIN
@protocol DouyinOpenSDKApiDelegate <NSObject>
@optional
/**
接收并处理来自抖音短视频的请求消息
@param req 抖音短视频主动发送的具体请求内容
*/
- (void)didReceiveRequest:(DouyinOpenSDKBaseReq * _Nonnull)req;
/**
第三方应用程序通过sendReq向抖音短视频发送请求后,收到来自抖音短视频的响应
@param resp 抖音短视频回应的具体内容
*/
- (void)didReceiveResponse:(DouyinOpenSDKBaseResp * _Nonnull)resp;
@end
@protocol DouyinOpenSDKLogDelegate <NSObject>
/**
接收来自抖音短视频的日志,可供调试用
@param log 日志内容
*/
- (void)onLog:(NSString *)log;
@end
@interface DouyinOpenSDKApi : NSObject
/**
设置SDK日志代理,可供调试
同时仅允许存在一个日志代理,每次调用将覆盖之前的delegate
SDK会弱引用这个logDelegate
@param logDelegate 日志代理
*/
+ (void)registerLogDelegate:(id<DouyinOpenSDKLogDelegate>)logDelegate;
/**
清除SDK日志代理,停止调试
会清除之前设置的日志代理
*/
+ (void)unregisterLogDelegate;
/**
向抖音短视频注册第三方应用
需要在每次启动第三方应用程序时调用。第一次调用后,将添加到头条的可用应用列表中
@attention 必须在主线程执行
@param appId 第三方应用在抖音短视频开放平台申请的appId(appId也称ClientKey)
@return 成功返回YES,否则返回NO
*/
+ (BOOL)registerAppId:(NSString * _Nonnull)appId;
/**
处理抖音短视频通过URL启动第三方应用时传递的数据,需在[application:openURL:sourceApplication:annotation:]或者[application:handleOpenURL:]中调用
@attention 必须在主线程执行
@param url 启动第三方应用的URL
@param delegate DouyinOpenSDKApiDelegate对象,用来接收抖音短视频触发的消息
@return 成功处理返回YES,否则返回NO
*/
+ (BOOL)handleOpenURL:(NSURL * _Nonnull)url
delegate:(id<DouyinOpenSDKApiDelegate> _Nullable)delegate;
/**
获取当前SDK的版本
@return 返回SDK当前版本号
*/
+ (nonnull NSString *)currentVersion;
/**
判断用户是否安装了抖音短视频
@return 安装返回YES,否则返回NO
*/
+ (BOOL)isAppInstalled;
/**
判断当前抖音短视频版本是否支持授权登录
@return 支持返回YES,否则返回NO
*/
+ (BOOL)isAppSupportAuthorization;
/**
判断当前TOREPLACEPRODUCTNAME版本是否支持分享
@return 支持返回YES,否则返回NO
*/
+ (BOOL)isAppSupportShare;
/**
获取抖音短视频在iTunes上的下载地址
@return 返回抖音短视频的安装地址
*/
+ (nonnull NSString *)getAppiTunesUrl;
/**
由第三方APP给抖音短视频发送请求,抖音短视频处理完成后通过didReceiveResponse:回调
@attention 必须运行在主线程
@param req 发送给抖音短视频的请求
@return 发送请求成功返回YES,否则返回NO并终止流程
*/
+ (BOOL)sendReq:(DouyinOpenSDKBaseReq * _Nonnull)req;
/*! @brief 发送Auth请求,唤起抖音短视频客户端,若用户没安装抖音短视频则唤起web授权页,等待抖音短视频返回response
*
* 函数调用后,会切换到抖音短视频的界面。第三方应用程序等待抖音短视频返回response
* @param req 具体的发送请求,在调用函数后,请自己释放。
* @param viewController 当前界面对象,用于展示抖音短视频的web授权页。
* @param delegate DouyinOpenSDKApiDelegate对象,用来接收抖音短视频触发的消息。
* @return 成功返回YES,失败返回NO。
*/
+ (BOOL)sendAuthReq:(DouyinOpenSDKSendAuthReq*)req viewController:(UIViewController*)viewController delegate:(id<DouyinOpenSDKApiDelegate>)delegate;
/**
进行web授权页预加载缓存,针对web页展示慢做的优化,使授权请求中展示web页更快
若无需求可以不调用
@param req 预加载的授权请求
*/
+ (void)preloadWebAuthWithReq:(DouyinOpenSDKSendAuthReq *)req;
/**
清理web授权页预加载缓存
若无需求可以不调用
*/
+ (void)clearPreloadWebAuthCache;
/**
抖音短视频给第三方APP发送请求后,第三方APP通过didReceiveRequest:接收到请求后,第三方APP使用SendResp:给抖音短视频回送响应
@attention 必须运行在主线程
@param resp 回送给抖音短视频的响应
@return 发送请求成功返回YES,否则返回NO并终止流程
*/
+ (BOOL)sendResp:(DouyinOpenSDKBaseResp * _Nonnull)resp;
@end
NS_ASSUME_NONNULL_END
//
// DouyinOpenSDKApiObject.h
// Api对象,包含所有接口和对象数据定义
//
// Created by 抖音短视频 on 18/9/2017.
// Copyright (c) 2018年 抖音短视频. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, DouyinOpenSDKErrorCode) {
DouyinOpenSDKSuccess = 0, /** 成功 */
DouyinOpenSDKErrorCodeCommon = -1, /** 通用错误类型 <包括网络错误> */
DouyinOpenSDKErrorCodeUserCanceled = -2, /** 用户手动取消 */
DouyinOpenSDKErrorCodeSendFailed = -3, /** 发送失败 */
DouyinOpenSDKErrorCodeAuthDenied = -4, /** 权限错误 */
DouyinOpenSDKErrorCodeUnsupported = -5, /** 不支持 */
};
#pragma mark - DouyinOpenSDKBaseReq
@interface DouyinOpenSDKBaseReq : NSObject
@end
#pragma mark - DouyinOpenSDKSendAuthReq
/**
第三方程序向抖音短视频请求认证授权的消息结构
第三方程序向抖音短视频发送认证用户的某些权限的请求,抖音短视频处理完成后会向第三方回送一个处理结果。
*/
@interface DouyinOpenSDKSendAuthReq : DouyinOpenSDKBaseReq
/**
第三方应用程序向抖音短视频申请的必需权限类型,最终在抖音短视频App授权完成后根据实际授权结果返回给第三方应用;
例如 [NSOrderedSet orderedSetWithObjects:@"user_info", ..., nil]
*/
@property (nonatomic, strong, nullable) NSOrderedSet<NSString *> *permissions;
/**
第三方应用程序向抖音短视频申请的附加权限类型,用户可以勾选是否给予这部分权限,最终在抖音短视频App授权完成后根据实际授权结果返回给第三方应用;
@key permission 权限
@key defaultChecked 初始勾选状态,@"1"表示勾选,@"0"表示未勾选
例如 [NSOrderedSet orderedSetWithObjects:@{@"permission":@"user_info",@"defaultChecked":@"0"}, ..., nil]
*/
@property (nonatomic, strong, nullable) NSOrderedSet<NSDictionary<NSString *,NSString *> *> *additionalPermissions;
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频App回传
*/
@property (nonatomic, copy, nullable) NSString *state;
@end
#pragma mark - DouyinOpenSDKBaseResp
@interface DouyinOpenSDKBaseResp : NSObject
/**
错误码
*/
@property (nonatomic, assign) DouyinOpenSDKErrorCode errCode;
/**
错误描述
*/
@property (nonatomic, copy, nullable) NSString *errString;
@end
#pragma mark - DouyinOpenSDKSendAuthResp
/**
抖音短视频处理完成第三方应用的认证与权限申请后,回送给第三方应用的处理结果。
第三方程序向抖音短视频申请权限认证,需要调用DouyinOpenSDKApi的[sendAuthReq:viewController:delegate:]函数,向抖音短视频发送DouyinOpenSDKSendAuthReq的请求,抖音短视频处理完成后会向第三方回送一个DouyinOpenSDKSendAuthResp对象的响应。
*/
@interface DouyinOpenSDKSendAuthResp : DouyinOpenSDKBaseResp
/**
第三方应用向抖音短视频申请某些权限,最终在抖音短视频App授权完成后根据实际授权结果返回给第三方应用
*/
@property (nonatomic, copy, readonly, nullable) NSString *code;
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频回传
*/
@property (nonatomic, copy, readonly, nullable) NSString *state;
/**
抖音短视频用户同意给予第三方应用程序的权限,若授权成功则包括全部必需权限和用户勾选的附加权限;
*/
@property (nonatomic, strong, nullable) NSOrderedSet<NSString *> *grantedPermissions;
@end
#pragma mark - DouyinOpenSDKShareReq
/**
分享捆绑抖音小程序相关信息数据结构
*/
@interface DouyinOpenSDKMPInfo : NSObject
@property (nonatomic, copy) NSString *identifier;
@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) NSString *desc;
@property (nonatomic, copy, nullable) NSString *startPageURL;
+ (DouyinOpenSDKMPInfo *)mpInfoWithIdentifier:(NSString *)identifier
title:(nullable NSString *)title
desc:(nullable NSString *)desc
startPageURL:(nullable NSString *)startPageURL;
@end
typedef NS_ENUM(NSUInteger, DouyinOpenSDKShareMediaType) {
DouyinOpenSDKShareMediaTypeImage = 0, // 对应 PHAssetMediaTypeImage
DouyinOpenSDKShareMediaTypeVideo, // 对应 PHAssetMediaTypeVideo
};
@interface DouyinOpenSDKShareReq : DouyinOpenSDKBaseReq
/**
第三方应用程序向抖音短视频分享的视频或图片在 **相册** 中的中的local identifier,上限为12个,内容须全部为图片,或者全部为视频。
若内容为视频,视频总时长应该大于3s;
图片的宽高比应满足:1/2.2<=宽高比<=2.2;
视频分辨率应满足:1/2.2<=宽高像素比<=2.2;
请三方应用程序自行检查分享的内容是否满足要求;
此处需注意,带品牌logo或品牌水印的视频,会命中抖音的审核逻辑,有比较大的概率导致分享视频推荐降权处理/分享视频下架处理/分享账号被封禁处理,请予以重视;
强烈建议第三方应用自行处理好分享内容中的不合规水印。
*/
@property (nonatomic, strong) NSArray *localIdentifiers;
/**
urlPaths在相册中对应的Media类型,urlPaths里面的必须都是同一种类型
*/
@property (nonatomic, assign) DouyinOpenSDKShareMediaType mediaType;
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频App回传
*/
@property (nonatomic, copy, nullable) NSString *state;
/**
对应视频的 #话题 功能,需要额外申请权限,字符长度不能超过 35
*/
@property (nonatomic, copy, nullable) NSString *hashtag;
/**
对应的小程序信息
*/
@property (nonatomic, strong, nullable) DouyinOpenSDKMPInfo *mpInfo;
@end
#pragma mark - DouyinOpenSDKShareResp
/**
抖音短视频完成视频分享处理后,给第三方应用的处理结果。
*/
@interface DouyinOpenSDKShareResp : DouyinOpenSDKBaseResp
/**
第三方应用程序用来标识请求的唯一性,最后跳转回第三方程序时由抖音短视频回传
*/
@property (nonatomic, copy, readonly, nullable) NSString *state;
@end
NS_ASSUME_NONNULL_END
//
// NSAttributedString+GMSize.h
// Gengmei
//
// Created by wangyang on 7/22/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSAttributedString (GMSize)
+ (NSMutableAttributedString *)string:(NSString *)string font:(UIFont *)font color:(UIColor *)color shadow:(BOOL)needShadow;
/**
实际调用 [self attributedStringWithString:string trimBothEndSpace:YES trimInnerReturn:YES font:font color:color lineSpacing:0];
*/
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color;
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color paragraphStyle:(NSMutableParagraphStyle *)paragraphStyle;
/**
* @brief 适用于为整个 string 添加属性,其中的 paragraphStyle 为 mutable 的,可以取出来再次修改
@note 最佳使用方法: 用该方法创建 attributedString,再使用 sizeForBoundingRectSize: 方法来计算大小.
@note 默认为 TruncatingTail
*/
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string trimBothEndSpace:(BOOL)tripSpace trimInnerReturn:(BOOL)trimReturn font:(UIFont *)font color:(UIColor *)color lineSpacing:(CGFloat)spacing;
/**
* @brief 使用该方法返回 attributedString 的大小。比如指定{320, 99},那么就会返回一个不超过该大小的 size,且宽高都经过 ceilf 处理
*
* @param maxSize 指定的最大的 string 大小。
*
* @return 经过 ceilf 处理的最大 size
*/
- (CGSize)sizeForBoundingRectSize:(CGSize)maxSize;
@end
@interface NSMutableAttributedString (GM)
- (void)addJustifiedAligment;
@end
@interface NSMutableAttributedString (Attributed)
- (NSMutableAttributedString *)addColor:(UIColor *)color;
- (NSMutableAttributedString *)addLineSpace:(NSInteger)space;
- (NSMutableAttributedString *)addShadow:(CGFloat)blur;
@end
//
// NSAttributedString+GMSize.m
// Gengmei
//
// Created by wangyang on 7/22/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSAttributedString+GMSize.h"
#import "NSNull+Empty.h"
#import "NSString+GM.h"
@implementation NSAttributedString (GMSize)
+ (NSMutableAttributedString *)string:(NSString *)string font:(UIFont *)font color:(UIColor *)color shadow:(BOOL)needShadow{
if (!font) {
NSAssert(0, @"请传递一个正常的字体参数");
}
if (!color) {
NSAssert(0, @"请传递一个正常的字体参数");
}
if (![string isNonEmpty]) {
return [[NSMutableAttributedString alloc] initWithString:@"" attributes:nil];;
}
NSMutableDictionary *stringAttribute = [@{NSForegroundColorAttributeName:color,
NSFontAttributeName:font} mutableCopy];
if (needShadow) {
NSShadow *shadow = [NSShadow new];
shadow.shadowOffset = CGSizeZero;
shadow.shadowBlurRadius = 5;
stringAttribute[NSShadowAttributeName] = shadow;
}
NSMutableAttributedString *attriString = [[NSMutableAttributedString alloc] initWithString:string attributes:stringAttribute];
return attriString;
}
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color {
return [self attributedStringWithString:string trimBothEndSpace:YES trimInnerReturn:YES font:font color:color lineSpacing:0];
}
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color paragraphStyle:(NSMutableParagraphStyle *)paragraphStyle{
NSString *trimString = string;
trimString = [string trimBothEnd];
trimString = [trimString trimInnerReturn];
if (!trimString) {
trimString = @"";
}
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:trimString attributes:@{NSFontAttributeName:font, NSForegroundColorAttributeName:color, NSParagraphStyleAttributeName:paragraphStyle}];
return [attributedString mutableCopy];
}
+ (NSMutableAttributedString *)attributedStringWithString:(NSString *)string trimBothEndSpace:(BOOL)tripSpace trimInnerReturn:(BOOL)trimReturn font:(UIFont *)font color:(UIColor *)color lineSpacing:(CGFloat)spacing {
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = spacing;
style.lineBreakMode = NSLineBreakByTruncatingTail;
style.alignment = NSTextAlignmentLeft;
NSString *trimString = string;
if (tripSpace) {
trimString = [string trimBothEnd];
}
if (trimReturn) {
trimString = [trimString trimInnerReturn];
}
if (!trimString) {
trimString = @"";
}
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:trimString attributes:@{NSFontAttributeName:font, NSForegroundColorAttributeName:color, NSParagraphStyleAttributeName:style}];
return [attributedString mutableCopy];
}
- (CGSize)sizeForBoundingRectSize:(CGSize)maxSize{
// mutableCopy 以防修复原来的 string
NSMutableAttributedString *string = [self mutableCopy];
if (![string.string isNonEmpty]) {
return CGSizeZero;
}
// 修改 lineBreakMode 为 NSLineBreakByWordWrapping,因为 Truncate tail 会在 boundingRectWithSize 中指定,在这里指定了,反而会导致 boundingRectWithSize 方法计算不准确
NSMutableParagraphStyle *originStyle = [self attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL];
originStyle.lineBreakMode = NSLineBreakByWordWrapping;
CGSize size = [string boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine context:[[NSStringDrawingContext alloc] init]].size;
// 修改 lineBreakMode 为 NSLineBreakByTruncatingTail,不然不显示...
originStyle.lineBreakMode = NSLineBreakByTruncatingTail;
return CGSizeMake(ceilf(size.width), ceilf(size.height));
}
@end
@implementation NSMutableAttributedString (GM)
- (void)addJustifiedAligment {
if (self.length == 0) {
return;
}
NSRange range = NSMakeRange(0, self.length);
NSDictionary *dic = [self attributesAtIndex:0 effectiveRange:&range];
NSMutableParagraphStyle *style = dic[NSParagraphStyleAttributeName];
if (!style) {
style = [[NSMutableParagraphStyle alloc] init];
}
style.alignment = NSTextAlignmentJustified;
style.firstLineHeadIndent = 0.001; // important: must have a value to make alignment work
[self addAttribute:NSBaselineOffsetAttributeName value:@0 range:range];
}
@end
@implementation NSMutableAttributedString (Attributed)
- (NSMutableAttributedString *)addColor:(UIColor *)color {
[self addAttributes:@{NSForegroundColorAttributeName: color} range:NSMakeRange(0, self.length)];
return self;
}
- (NSMutableAttributedString *)addLineSpace:(NSInteger)space {
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = space;
style.lineBreakMode = NSLineBreakByTruncatingTail;
[self addAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, self.length)];
return self;
}
- (NSMutableAttributedString *)addShadow:(CGFloat)blur {
NSShadow *shadow = [NSShadow new];
shadow.shadowOffset = CGSizeZero;
shadow.shadowBlurRadius = blur;
[self addAttributes:@{NSShadowAttributeName: shadow} range:NSMakeRange(0, self.length)];
return self;
}
@end
//
// NSDate+DateFormat.h
// Gengmei
//
// Created by Sean Lee on 4/14/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDate (DateFormat)
/**
* @author licong, 16-12-29 16:12:03
*
* 日期格式化成年月日型的字符串(eg:2015-4-14)
*
* @return 返回格式化后的字符串
*
* @since 5.8
*/
-(NSString *)dateFormatToString;
@end
//
// NSDate+DateFormat.m
// Gengmei
//
// Created by Sean Lee on 4/14/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSDate+DateFormat.h"
@implementation NSDate (DateFormat)
-(NSString *)dateFormatToString {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
return [formatter stringFromDate:self];
}
@end
//
// NSFileManager+FolderSize.h
// ZhengXing
//
// Created by wangyang on 3/19/15.
// Copyright (c) 2015 Wanmei Creative. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSFileManager (FolderSize)
- (BOOL)getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)directoryURL error:(NSError * __autoreleasing *)error;
@end
//
// NRFileManager.m
// NRFoundation
//
// Created by Nikolai Ruhe on 2015-02-22.
// Copyright (c) 2015 Nikolai Ruhe. All rights reserved.
//
#import "NSFileManager+FolderSize.h"
@implementation NSFileManager (FolderSize)
// This method calculates the accumulated size of a directory on the volume in bytes.
//
// As there's no simple way to get this information from the file system it has to crawl the entire hierarchy,
// accumulating the overall sum on the way. The resulting value is roughly equivalent with the amount of bytes
// that would become available on the volume if the directory would be deleted.
//
// Caveat: There are a couple of oddities that are not taken into account (like symbolic links, meta data of
// directories, hard links, ...).
- (BOOL)getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)directoryURL error:(NSError * __autoreleasing *)error
{
NSParameterAssert(size != NULL);
NSParameterAssert(directoryURL != nil);
// We'll sum up content size here:
unsigned long long accumulatedSize = 0;
// prefetching some properties during traversal will speed up things a bit.
NSArray *prefetchedProperties = @[
NSURLIsRegularFileKey,
NSURLFileAllocatedSizeKey,
NSURLTotalFileAllocatedSizeKey,
];
// The error handler simply signals errors to outside code.
__block BOOL errorDidOccur = NO;
BOOL (^errorHandler)(NSURL *, NSError *) = ^(NSURL *url, NSError *localError) {
if (error != NULL)
*error = localError;
errorDidOccur = YES;
return NO;
};
// We have to enumerate all directory contents, including subdirectories.
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL
includingPropertiesForKeys:prefetchedProperties
options:(NSDirectoryEnumerationOptions)0
errorHandler:errorHandler];
// Start the traversal:
for (NSURL *contentItemURL in enumerator) {
// Bail out on errors from the errorHandler.
if (errorDidOccur)
return NO;
// Get the type of this item, making sure we only sum up sizes of regular files.
NSNumber *isRegularFile;
if (! [contentItemURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:error])
return NO;
if (! [isRegularFile boolValue])
continue; // Ignore anything except regular files.
// To get the file's size we first try the most comprehensive value in terms of what the file may use on disk.
// This includes metadata, compression (on file system level) and block size.
NSNumber *fileSize;
if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLTotalFileAllocatedSizeKey error:error])
return NO;
// In case the value is unavailable we use the fallback value (excluding meta data and compression)
// This value should always be available.
if (fileSize == nil) {
if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLFileAllocatedSizeKey error:error])
return NO;
NSAssert(fileSize != nil, @"huh? NSURLFileAllocatedSizeKey should always return a value");
}
// We're good, add up the value.
accumulatedSize += [fileSize unsignedLongLongValue];
}
// Bail out on errors from the errorHandler.
if (errorDidOccur)
return NO;
// We finally got it.
*size = accumulatedSize;
return YES;
}
@end
//
// NSNull+Empty.h
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSNull (Empty)
- (BOOL)isNonEmpty;
/**
* @brief 我们极力避免使用 string.length 的方式来判断空字符串。但是 string.length 除了用来判断,可能还会用在其它非判断的功能上。为了避免 [NSNull length] 而引起的 crash,还是给 NSNull 添加一个 length 方法比较安全。并且在 debug 情况下打印 log,以提示使用了 length 方法
*
* @return 0
*/
- (NSUInteger)length;
@end
//
// NSNull+Empty.m
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSNull+Empty.h"
@implementation NSNull (Empty)
- (BOOL) isNonEmpty {
return NO;
}
- (NSUInteger)length{
NSAssert(0, @"注意:向 NSNull 发送了 length 消息");
return 0;
}
@end
//
// UIViewController+KeyboardAnimation.h
// yingshibaokaoyan
//
// Created by wangyang on 7/17/14.
// Copyright (c) 2014 com.zkyj.yingshibao.kaoyao. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
* 当键盘弹出或者收起时,会执行的block。在这个block里实现需要的UI变动
*
* @param keyboardFrame 将键盘转换为视图所在坐标第后,整个键盘View的Frame
* @param duration 动画时间
* @param curve 动画效果
* @param notifcation 通知
*/
typedef void(^ShowKeyboardAnimation)(CGRect keyboardFrame, CGFloat duration, NSInteger curve, NSNotification *notifcation);
typedef void(^HideKeyboardAnimation)(CGFloat duration, NSInteger curve, NSNotification *notifcation);
/**
* 使用该类别,以方便的控制键盘事件
*/
@interface NSObject (KeyboardAnimation)
- (void)observeKeyboardForView:(UIView *)view showKeyboardAnimation:(ShowKeyboardAnimation)animation1 hideKeyboardAnimation:(HideKeyboardAnimation)animation2;
- (void)removeObservKeyboard;
@end
//
// UIViewController+KeyboardAnimation.m
// yingshibaokaoyan
//
// Created by wangyang on 7/17/14.
// Copyright (c) 2014 com.zkyj.yingshibao.kaoyao. All rights reserved.
//
#import "NSObject+KeyboardAnimation.h"
#import <objc/runtime.h>
static const char kwy_targetView;
static const char kwy_showAnimationblock;
static const char kwy_hideAnimationblock;
@interface NSObject ()
@property (nonatomic, weak) UIView *wy_targetView;
@property (nonatomic, copy) ShowKeyboardAnimation wy_showAnimationblock;
@property (nonatomic, copy) HideKeyboardAnimation wy_hideAnimationblock;
@end
@implementation NSObject (KeyboardAnimation)
#pragma mark - 属性get、set
- (ShowKeyboardAnimation)wy_showAnimationblock
{
return objc_getAssociatedObject(self, &kwy_showAnimationblock);
}
- (void)setWy_showAnimationblock:(ShowKeyboardAnimation)wy_showAnimationblock
{
objc_setAssociatedObject(self, &kwy_showAnimationblock, wy_showAnimationblock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (HideKeyboardAnimation)wy_hideAnimationblock
{
return objc_getAssociatedObject(self, &kwy_hideAnimationblock);
}
- (void)setWy_hideAnimationblock:(HideKeyboardAnimation)wy_hideAnimationblock
{
objc_setAssociatedObject(self, &kwy_hideAnimationblock, wy_hideAnimationblock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (UIView *)wy_targetView
{
return objc_getAssociatedObject(self, &kwy_targetView);
}
- (void)setWy_targetView:(UIView *)wy_targetView
{
objc_setAssociatedObject(self, &kwy_targetView, wy_targetView, OBJC_ASSOCIATION_ASSIGN);
}
#pragma mark - 监听
- (void)observeKeyboardForView:(UIView *)view showKeyboardAnimation:(ShowKeyboardAnimation)animation1 hideKeyboardAnimation:(HideKeyboardAnimation)animation2
{
self.wy_showAnimationblock = animation1;
self.wy_targetView = view;
self.wy_hideAnimationblock = animation2;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)removeObservKeyboard
{
self.wy_showAnimationblock = nil;
self.wy_targetView = nil;
self.wy_hideAnimationblock = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - 监听响应
- (void)keyboardWillShow:(NSNotification *)note{
// get keyboard size and loctaion
CGRect keyboardFrame;
[[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardFrame];
// Need to translate the bounds to account for rotation.
keyboardFrame = [[UIApplication sharedApplication].keyWindow convertRect:keyboardFrame toView:self.wy_targetView.superview];
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
self.wy_showAnimationblock(keyboardFrame, [duration doubleValue], [curve integerValue], note);
}
- (void)keyboardWillHide:(NSNotification *)note{
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
self.wy_hideAnimationblock([duration doubleValue], [curve integerValue], note);
}
@end
//
// NSString+DateFormat.h
// Gengmei
//
// Created by Sean Lee on 4/15/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (DateFormat)
/**
* @author licong, 16-12-29 16:12:14
*
* String类型的日期转为冒号式的NSDate
*
* @return 返回一个NSDate对象
*
* @since 5.8
*/
-(NSDate *)stringFormatToColonDate;
/**
* @author licong, 16-12-29 16:12:59
*
* String类型的日期转为破折号式的NSDate
*
* @return 返回一个NSDate对象
*
* @since 5.8
*/
-(NSDate *)stringformatToDashDate;
@end
//
// NSString+DateFormat.m
// Gengmei
//
// Created by Sean Lee on 4/15/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSString+DateFormat.h"
@implementation NSString (DateFormat)
-(NSDate *)stringFormatToColonDate{
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
return [formatter dateFromString:self];
}
- (NSDate *)stringformatToDashDate{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy:MM:dd"];
return [dateFormatter dateFromString:self];
}
@end
//
// NSString+Encrypt.h
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* @brief
AES块长度 128 byte
加密模式CBC,cipher block chaining
数据长度不到128byte时需要填充(即no padding自定义填充)
填充方法s + (128 - len(s) % 128) * chr(128 - len(s) % 128) 将数字转成char字符拼接尾部
加密密钥 Up[K+ub%pliOnsO5UavFBd)cw5VcyHSX
初始向量需要附加在加密后的auth_user_id中 传给服务器,final auth_user_id = base64(iv+encrypted(user_id_auth))
*/
@interface NSString (Encrypt)
/**
* @brief AES256加密
*
* @param key 32位的密钥
*
* @return 返回加密后的密文
*/
- (NSString *)AES256EncryptedStringForKey:(NSString *)key;
/**
* @brief AES256解密
*
* @param key 32位的密钥
*
* @return 返回解密后的明文
*/
- (NSString *)AES256DecryptedStringForKey:(NSString *)key;
/**
* @brief MD5加密
*
* @return MD5加密后的String
*/
- (NSString *) stringFromMD5;
@end
//
// NSString+Encrypt.m
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSString+Encrypt.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
#import <Base64nl/Base64.h>
@implementation NSString (Encrypt)
- (NSString *)AES256EncryptedStringForKey:(NSString *)key
{
//密钥
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
//明文数据
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
//IV:初始化16字节的随机向量
char iv[16];
for (int i = 0; i<16; i++) {
iv[i] = arc4random()%255;//一个字节长的随机数
}
//Create Cryptor
CCCryptorStatus create = CCCryptorCreateWithMode(kCCEncrypt,
kCCModeCBC, //CBC模式
kCCAlgorithmAES128, //分组密码块长度
ccNoPadding, //无填充模式
iv, // can be NULL, because null is full of zeros
keyData.bytes, //密钥
keyData.length, //密钥长度
NULL,
0,
0,
0, //这里参数只在CTR下有用,本初填0即可
&cryptor);
if (create == kCCSuccess){
size_t numBytesCrypted;
//自定义填充明文算法
NSUInteger dataLength = [data length];
int diff = 128 - (dataLength % 128);
unsigned long newSize = 0;
if(diff > 0)
newSize = dataLength + diff;
char dataPtr[newSize];
memcpy(dataPtr, [data bytes], [data length]);
for(int i = 0; i < diff; i++){
char character = diff;
dataPtr[i + dataLength] = character;
}
/*初始化加密后的data,并开辟好空间长度,查阅相关文档:对于分组密码,加密后的数据长度总是小于或者等于 加密前数据长度+单个分组密码块长度之和*/
NSMutableData *cipherData= [NSMutableData dataWithLength: sizeof(dataPtr)+kCCBlockSizeAES128];
/*Update Cryptor,得到加密后data以及我们需要的数据长度,这里可以看到cipherData的长度是小于或者等于outLength的
*/
CCCryptorStatus update = CCCryptorUpdate(cryptor,
dataPtr,
sizeof(dataPtr),
cipherData.mutableBytes,
cipherData.length,
&numBytesCrypted);
if (update == kCCSuccess){
//通过outLength截图我们需要的数据长度
cipherData.length = numBytesCrypted;
//Final Cryptor,最终生成最终的密文,装载给cipherData
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherData.mutableBytes, //void *dataOut,
cipherData.length, //size_t dataOutAvailable,
&numBytesCrypted); //size_t *dataOutMoved)
if (final == kCCSuccess){
//Release Cryptor
CCCryptorRelease(cryptor);
}
//最终结果= 初始向量+密文,这样服务器才可以拿到初始向量,用密钥解码
NSMutableData *resultData= [NSMutableData dataWithLength:0];
[resultData appendBytes:iv length:sizeof(iv)];
[resultData appendBytes:cipherData.bytes length:cipherData.length];
//最终结果再base64转码
NSString * resultStr = [resultData base64EncodedString];//[GTMBase64 stringByEncodingData:resultData];
return resultStr;
}
}
else{
NSLog(@"加密失败");
}
return nil;
}
- (NSString *)AES256DecryptedStringForKey:(NSString *)key {
//Key to Data
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
// Init cryptor
CCCryptorRef cryptor = NULL;
//IV:获取密文里的随机向量
NSData *data = [self base64DecodedData];
NSMutableData * iv = [NSMutableData dataWithBytes:data.bytes length:kCCKeySizeAES256];
// Create Cryptor
CCCryptorStatus createDecrypt = CCCryptorCreateWithMode(kCCDecrypt, // operation
kCCModeCBC, // mode CTR
kCCAlgorithmAES, // Algorithm
ccNoPadding, // padding
iv.bytes, // can be NULL, because null is full of zeros
keyData.bytes, // key
keyData.length, // keylength
NULL, //const void *tweak
0, //size_t tweakLength,
0, //int numRounds,
0, //CCModeOptions options,
&cryptor); //CCCryptorRef *cryptorRef
if (createDecrypt == kCCSuccess)
{
// Alloc Data Out
NSMutableData * realData = [NSMutableData dataWithBytes:data.bytes + 16 length:data.length - 16];
NSMutableData *cipherDataDecrypt = [NSMutableData dataWithLength:realData.length + kCCBlockSizeAES128];
//alloc number of bytes written to data Out
size_t outLengthDecrypt;
//Update Cryptor
CCCryptorStatus updateDecrypt = CCCryptorUpdate(cryptor,
realData.bytes, //const void *dataIn,
realData.length, //size_t dataInLength,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (updateDecrypt == kCCSuccess)
{
//Cut Data Out with nedded length
cipherDataDecrypt.length = outLengthDecrypt;
//Final Cryptor
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
cipherDataDecrypt.mutableBytes, //void *dataOut,
cipherDataDecrypt.length, // size_t dataOutAvailable,
&outLengthDecrypt); // size_t *dataOutMoved)
if (final == kCCSuccess){
CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
}
// Data to String
NSMutableString* cipherFinalDecrypt = [[NSMutableString alloc] initWithData:cipherDataDecrypt encoding:NSUTF8StringEncoding];
int diff = [cipherFinalDecrypt characterAtIndex:cipherDataDecrypt.length - 1]; // 128字节的明文(填充字符)中填充字符的个数
[cipherFinalDecrypt deleteCharactersInRange:NSMakeRange(cipherFinalDecrypt.length - diff, diff)];
return cipherFinalDecrypt;
}
}
else{
NSLog(@"解密密失败");
}
return nil;
}
- (NSString *)stringFromMD5
{
if(self == nil || [self length] == 0)
return nil;
const char *value = [self UTF8String];
unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(value, (uint32_t)strlen(value), outputBuffer);
NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
[outputString appendFormat:@"%02x",outputBuffer[count]];
}
return outputString;
}
+ (BOOL)validKey:(NSString*)key
{
if(key == nil || key.length != kCCKeySizeAES256){
return NO;
}
return YES;
}
@end
//
// NSString+GM.h
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
* 常用且按功能块比较难划分的扩展方法
*/
@interface NSString (GM)
/**
* @author licong, 16-12-28 12:12:13
*
* 判断一个字符串是否为空(包括nil/@""/nil)
*
* @return 布尔值,YES表示字符串不为空,NO表示字符串为空
*
* @since 5.8
*/
- (BOOL)isNonEmpty;
/*!
* @author zhaiguojun, 16-04-21
*
* @brief 把字典和数组转成string
*
* 相当于调用 [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
* @return 转换后的string
*
* @since 5.9.3
*/
+ (NSString*)convertToPrettyPrintedJsonString:(id)object;
/**
把字典和数组转成简短的json string
相当于调用 [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
*/
+ (NSString *)convertToBriefJsonString:(id)object;
/**
* @author licong, 16-12-28 12:12:16
*
* 得到非空string
*
* @return 返回一个非空的字符串
*
* @since 5.8
*/
+ (NSString *)safeStringWithString:(NSString *)string;
/**
* @brief 是否为纯数字
*
* @param string 要检查的字符串
*
*/
+ (BOOL)isPureInt:(NSString *)string;
/**
* @brief 是否为手机号
*
* @param mobileNum 0~9 11位即可
*
*/
+ (BOOL)isMobileNumber:(NSString *)mobileNum;
/**
* 问题来自于服务器返回Str 我们当做int来解析会crash 古做一下兼容(目前来看 7.3.0 之前不会发生crash 7.3.0之后必crash)
*/
- (unsigned long long)unsignedLongLongValue;
/**
* @brief 是否为邮箱格式
*
* @param string 要检查的字符串
*
*/
+ (BOOL)isValidateEmail:(NSString *)email;
@end
/**
*
* 将类似URL的query参数解析成字典
*
*/
@interface NSString (paresQuery)
/**
* @author licong, 16-12-28 18:12:14
*
* 解析url中的query,转成字典格式
*
* @return 解析好的字典
*
* @since 5.8
*/
- (NSDictionary*)urlQueryToDictionary;
/**
* @author licong, 16-12-28 18:12:11
*
* 解析query字符串为字典比如:a=b&c=d
*
* @return 解析好的字典
*
* @since 5.8
*/
- (NSDictionary*)queryToDictionary;
@end
/**
*
* 根据String的Font计算String的size
*
*/
@interface NSString (calculatorSize)
/**
* @author licong, 16-12-28 18:12:38
*
* 计算String当行间距为0的时候的高度和宽度
*
* @param font String的font
* @param size String限定的size
*
* @return String实际(如果是多行,则经过折行后)的size
*
* @since 5.8
*/
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size;
/**
* @author licong, 16-12-28 18:12:05
*
* 计算String在某个行间距下,高度和宽度
*
* @param font String的font
* @param size String限定的size
* @param lineSpacing 设定的行间距
*
* @return String在设定的行间距下,实际(如果是多行,则经过折行后)的size
*
* @since 5.8
*/
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size lineSpacing:(CGFloat)lineSpacing;
@end
@interface NSString (URLEncoding)
/**
* @author licong, 16-12-29 16:12:45
*
* URL编码
*
* @return 编码后的URL
*
* @since 5.8
*/
- (NSString*) URLEncodedString;
/**
* @author licong, 16-12-29 16:12:08
*
* URL解码
*
* @return 解码URL
*
* @since 5.8
*/
- (NSString*) URLDecodedString;
/**
URL编码
@return 编码后的URL
*/
- (NSString *)URLEncodeString;
@end
@interface NSString (Trim)
/**
* @author licong, 16-12-28 18:12:04
*
* 去除字符串两头的空白(空格及换行)
*
* @return 无空格的字符串
*
* @since 5.8
*/
- (NSString *)trimBothEnd;
- (NSString *)trimSpace;
- (NSString *)trimInnerReturn;
- (NSString *)trimNewlinesToOne;
@end
//
// NSString+GM.m
// Gengmei
//
// Created by licong on 12/28/15.
// Copyright © 2015 Wanmeichuangyi. All rights reserved.
//
#import "NSString+GM.h"
#import "NSNull+Empty.h"
@implementation NSString (GM)
+ (NSString *)safeStringWithString:(NSString *)string{
if ([string isNonEmpty]) {
return string;
}else{
return @"";
}
}
- (BOOL)isNonEmpty {
NSMutableCharacterSet *emptyStringSet = [[NSMutableCharacterSet alloc] init];
[emptyStringSet formUnionWithCharacterSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[emptyStringSet formUnionWithCharacterSet: [NSCharacterSet characterSetWithCharactersInString: @" "]];
if ([self length] == 0) {
return NO;
}
NSString* str = [self stringByTrimmingCharactersInSet:emptyStringSet];
return [str length] > 0;
}
+ (NSString *)convertToPrettyPrintedJsonString:(id)object
{
return [self convertToJsonString:object withOption:NSJSONWritingPrettyPrinted];
}
+ (NSString *)convertToBriefJsonString:(id)object
{
return [self convertToJsonString:object withOption:0];;
}
+ (NSString *)convertToJsonString:(id)object withOption:(NSJSONWritingOptions)opt {
NSString *jsonString = @"";
NSError *error;
if (!object) {
NSAssert(0, @"convertToJsonString object 是nil");
return @"";
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object
options:opt
error:&error];
if (!jsonData) {
NSAssert(0, @"convertToJsonString NSJSONSerialization 出现错误");
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
if (jsonString == nil) {
NSAssert(0, @"convertToJsonString jsonString 是nil");
jsonString = @"";
}
return jsonString;
}
+ (BOOL)isPureInt:(NSString *)string{
NSScanner* scan = [NSScanner scannerWithString:string];
int val;
return [scan scanInt:&val] && [scan isAtEnd];
}
+ (BOOL)isMobileNumber:(NSString *)mobileNum{
NSString *ALL = @"\\d{11}$";
NSPredicate *regextestall = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", ALL];
return [regextestall evaluateWithObject:mobileNum];
}
- (unsigned long long)unsignedLongLongValue {
return self.longLongValue;
}
//利用正则表达式验证
+ (BOOL)isValidateEmail:(NSString *)email {
NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
return [emailTest evaluateWithObject:email];
}
@end
@implementation NSString (paresQuery)
- (NSDictionary*)urlQueryToDictionary{
NSURL* url1 = [NSURL URLWithString:self];
if (!url1) {
return nil;
}
NSString* query = [url1 query];
return [query queryToDictionary];
}
- (NSDictionary*)queryToDictionary {
@try {
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
NSArray* components = [self componentsSeparatedByString:@"&"];
for (NSString* component in components) {
NSArray* keyValue = [component componentsSeparatedByString:@"="];
if ([keyValue count] > 1) {
NSString * key = [[keyValue objectAtIndex:0] URLDecodedString];
NSString * value = [keyValue objectAtIndex:1];
//参数中依然包含超过2个“=”号(多数发生在common_webview后的url参数中),则后面的数组的元素需要拼接成一个字符串
if ([keyValue count]>2) {
for (int i=2; i<[keyValue count]; i++) {
value=[value stringByAppendingString:@"="];
value=[value stringByAppendingString:keyValue[i]];
}
}
//因为这种情况服务器和客户端都转义了一次,所以要两次反转义还原中文
while ([value rangeOfString:@"%"].length != 0) {
value = [value URLDecodedString];
}
[dict setObject: value forKey: key];
}
}
return dict;
}
@catch (NSException *exception) {}
}
@end
@implementation NSString (calculatorSize)
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size{
return [self sizeWithFont:font boundSize:size lineSpacing:0];
}
- (CGSize)sizeWithFont:(UIFont *)font boundSize:(CGSize)size lineSpacing:(CGFloat)lineSpacing{
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
paragraphStyle.lineSpacing = lineSpacing;
NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle};
CGSize resultSize = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine attributes:attributes context:nil].size;
return CGSizeMake(ceil(resultSize.width), ceil(resultSize.height));
}
@end
@implementation NSString (URLEncoding)
- (NSString *)URLEncodedString {
NSString *result = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)self,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]"),
kCFStringEncodingUTF8));
return result;
}
- (NSString*)URLDecodedString {
NSString *result = (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
(CFStringRef)self,
CFSTR(""),
kCFStringEncodingUTF8));
return result;
}
- (NSString *)URLEncodeString {
NSString *encodedString = [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
return encodedString;
}
@end
@implementation NSString (Trim)
//去空格只局限于首尾空格
- (NSString *)trimBothEnd {
NSMutableCharacterSet* emptyStringSet = [[NSMutableCharacterSet alloc] init];
[emptyStringSet formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[emptyStringSet formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@" "]];
NSString *string = [self stringByTrimmingCharactersInSet:emptyStringSet];
return string;
}
//去掉字符串中所有的空格
- (NSString *)trimSpace {
NSString *string = [self stringByReplacingOccurrencesOfString:@" " withString:@""];
return string;
}
- (NSString *)trimInnerReturn {
NSString *string = self;
string = [self stringByReplacingOccurrencesOfString:@"\r" withString:@""];
string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
return string;
}
- (NSString *)trimNewlinesToOne {
if (![self isNonEmpty]) {
return @"";
}
NSError *error = nil;
NSRegularExpression *exp = [[NSRegularExpression alloc] initWithPattern:@"\n+" options:0 error:&error];
if (error != nil) {
return self;
}
NSString *result = [exp stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, self.length) withTemplate:@"\n"];
return result;
}
@end
Copyright (c) 2016 licong <1240690490@qq.com>
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.
# GMFoundation
[![CI Status](http://img.shields.io/travis/licong/GMFoundation.svg?style=flat)](https://travis-ci.org/licong/GMFoundation)
[![Version](https://img.shields.io/cocoapods/v/GMFoundation.svg?style=flat)](http://cocoapods.org/pods/GMFoundation)
[![License](https://img.shields.io/cocoapods/l/GMFoundation.svg?style=flat)](http://cocoapods.org/pods/GMFoundation)
[![Platform](https://img.shields.io/cocoapods/p/GMFoundation.svg?style=flat)](http://cocoapods.org/pods/GMFoundation)
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
## Installation
GMFoundation is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod "GMFoundation"
```
## Author
licong, 1240690490@qq.com
## License
GMFoundation is available under the MIT license. See the LICENSE file for more info.
Copyright (c) 2016 北京更美互动信息科技有限公司
仅限北京更美互动信息科技有限公司内部使用
//
// UIDevice+Reso.m
// Simple UIDevice Category for handling different iOSs hardware resolutions
//
// Created by Alejandro Luengo on 29/09/14.
// (c) 2014 Intelygenz
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, UIDeviceResolution) {
UnknowDevice = 0, //未知设备
iPhone35Inches = 1, //3.5英寸、iphone4s
iPhone40Inches = 2, //4英寸iphone5、iphone5c、iphone5s
iPhone47Inches = 3, //4.7英寸iphone6、iphone7、iphone8
iPhone55Inches = 4, //5.5英寸iphone6 plus、iphone7 plus、iphone8 plus
iPhone58Inches = 5, //5.5英寸iphoneX
iPhoneXRInches = 6, //iphone XR
iPhoneXSMaxInches = 7 //iphone XS Max
};
typedef NS_ENUM(NSInteger, GMDeviceType) {
GMDeviceTypeUnknow = 0,
GMDeviceTypeSimulator,
GMDeviceTypeIPad,
GMDeviceTypeIPod,
GMDeviceTypeIPhone4,
GMDeviceTypeIPhone4S,
GMDeviceTypeIPhone5,
GMDeviceTypeIPhone5S,
GMDeviceTypeIPhone5C,
GMDeviceTypeIPhone6,
GMDeviceTypeIPhone6P,
GMDeviceTypeIPhone6S,
GMDeviceTypeIPhone6SP,
GMDeviceTypeIPhone7,
GMDeviceTypeIPhone7P,
GMDeviceTypeIPhone8,
GMDeviceTypeIPhone8P,
GMDeviceTypeIPhoneX,
GMDeviceTypeIPhoneXR,
GMDeviceTypeIPhoneXS,
GMDeviceTypeIPhoneXSMax,
};
typedef NS_ENUM(NSUInteger, GMDeviceAspectRatioType) {
GMDeviceAspectRatioTypeNarrow, //iPad、iphone4s、iphone5
GMDeviceAspectRatioTypeNormal, // Normal
GMDeviceAspectRatioTypeWide, // Plus、Max
};
@interface UIDevice (Resolutions)
/**
* @author licong, 16-12-29 17:12:54
*
* 判断设备的类型(eg:当前设备是5还是6s)
*
* @return 返回设备类型
*
* @since 5.8
*/
+ (UIDeviceResolution)resolutionType;
+ (GMDeviceAspectRatioType)aspectRatioType;
+ (NSString *)platform;
/**
获取设备的deviceId,如果能去到idfa,就返回idfa,否则就返回idfv
@author zhaiguojun 16-10-31 in (null)
@return deviceId
@since 6.5.0
*/
+ (NSString *)deviceId;
/**
获取设备详细类型,目前只到6s,和6s plus
@author zhaiguojun 16-09-18 in (null)
@return model
@since 6.3.0
*/
+ (NSString*)deviceVersion;
@end
//
// UIDevice+Reso.m
// Simple UIDevice Category for handling different iOSs hardware resolutions
//
// Created by Alejandro Luengo on 29/09/14.
// (c) 2014 Intelygenz
// iPhone 6 Plus 736x414 points 2208x1242 pixels 3x scale
// iPhone 6 667x375 points 1334x750 pixels 2x scale
// iPhone 5 568x320 points 1136x640 pixels 2x scale
// iPhone 4s 480x320 points 960x640 pixels 2x scale
// iPad 1024x768 points 1024x768 pixels 1x scale
// iPad Retina 1024x768 points 2048x1536 pixels 2x scale
#import "UIDevice+Resolutions.h"
#import "sys/utsname.h"
#import <AdSupport/AdSupport.h>
@implementation UIDevice (Resolutions)
+ (NSString *)deviceId {
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
if (![idfa isEqualToString:@"00000000-0000-0000-0000-000000000000"]) {
return idfa;
}
return idfv;
}
+ (UIDeviceResolution)resolutionType
{
UIScreenMode *mode = [UIScreen mainScreen].preferredMode;
if (mode.size.height == 960) {
return iPhone35Inches;
}
else if (mode.size.height == 1136) {
return iPhone40Inches;
}
else if (mode.size.height == 1334) {
return iPhone47Inches;
}
else if (mode.size.height == 2208) {
return iPhone55Inches;
}
else if (mode.size.height == 2436) {
return iPhone58Inches;
}
else if (mode.size.height == 1792) {
return iPhoneXRInches;
}
else if (mode.size.height == 2688) {
return iPhoneXSMaxInches;
}
else
return UnknowDevice;
}
+ (GMDeviceAspectRatioType)aspectRatioType {
UIDevice *device = [UIDevice currentDevice];
if ([device.model containsString:@"iPad"])
return GMDeviceAspectRatioTypeNarrow;
NSString *deviceVersion = [self deviceVersion];
UIScreenMode *mode = [UIScreen mainScreen].preferredMode;
if ([deviceVersion containsString:@"iPhone 4"] || [deviceVersion containsString:@"iPhone 5"] || mode.size.height == 960 || mode.size.height == 1136)
return GMDeviceAspectRatioTypeNarrow;
else if ([deviceVersion containsString:@"Plus"] || [deviceVersion containsString:@"Max"])
return GMDeviceAspectRatioTypeWide;
else
return GMDeviceAspectRatioTypeNormal;
}
+ (NSString *)platform {
struct utsname systemInfo;
uname(&systemInfo);
NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
return platform;
}
+ (NSString*)deviceVersion{
NSString *platform = [self platform];
//iPhone
if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4";
if ([platform isEqualToString:@"iPhone3,2"]) return @"iPhone 4";
if ([platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4";
if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4S";
if ([platform isEqualToString:@"iPhone5,1"]) return @"iPhone 5";
if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5";
if ([platform isEqualToString:@"iPhone5,3"]) return @"iPhone 5C";
if ([platform isEqualToString:@"iPhone5,4"]) return @"iPhone 5C";
if ([platform isEqualToString:@"iPhone6,1"]) return @"iPhone 5S";
if ([platform isEqualToString:@"iPhone6,2"]) return @"iPhone 5S";
if ([platform isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus";
if ([platform isEqualToString:@"iPhone7,2"]) return @"iPhone 6";
if ([platform isEqualToString:@"iPhone8,1"]) return @"iPhone 6s";
if ([platform isEqualToString:@"iPhone8,2"]) return @"iPhone 6s Plus";
if ([platform isEqualToString:@"iPhone8,3"]) return @"iPhoneSE";
if ([platform isEqualToString:@"iPhone8,4"]) return @"iPhoneSE";
if ([platform isEqualToString:@"iPhone9,1"]) return @"iPhone 7";
if ([platform isEqualToString:@"iPhone9,3"]) return @"iPhone 7";
if ([platform isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus";
if ([platform isEqualToString:@"iPhone9,4"]) return @"iPhone 7 Plus";
if ([platform isEqualToString:@"iPhone10,1"]) return @"iPhone 8";
if ([platform isEqualToString:@"iPhone10,4"]) return @"iPhone 8";
if ([platform isEqualToString:@"iPhone10,2"]) return @"iPhone 8 Plus";
if ([platform isEqualToString:@"iPhone10,5"]) return @"iPhone 8 Plus";
if ([platform isEqualToString:@"iPhone10,3"]) return @"iPhone X";
if ([platform isEqualToString:@"iPhone10,6"]) return @"iPhone X";
if ([platform isEqualToString:@"iPhone11,8"]) return @"iPhone XR";
if ([platform isEqualToString:@"iPhone11,2"]) return @"iPhone XS";
if ([platform isEqualToString:@"iPhone11,4"]) return @"iPhone XS Max";
if ([platform isEqualToString:@"iPhone11,6"]) return @"iPhone XS Max";
return @"iphone X ++";
}
@end
//
// UIImage+GM.h
// Gengmei
//
// Created by licong on 15/12/29. Rewrite by wangyang on 2016-7-4
// Copyright © 2016年 Wanmeichuangyi. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIImage (GM)
/**
* @brief 通过颜色生成图片
*
* @param color 颜色
*/
+ (UIImage *)imageWithColor:(UIColor *)color;
/**
* @author licong, 16-12-29 18:12:48
*
* 将图片调整到设定大小
*
* @param size 设定的图片大小
*
* @return 得到设定大小后的图片
*
* @since 5.8
*/
- (UIImage *)resizedImageWithSize:(CGSize)size;
/**
使用该方法的前提条件是认为这个图片为3倍图,使用该方法将返回一个适用于当前设备scale的UIImage实例。
比如一张90像素x90像素的网络下载的图片,使用该方法
- iPhone 8 Plus机型将返回一个size为(30, 30),scale=3的UIImage;
- iPhone 8 机型将返回返回一个size为(30, 30),scale=2的UIImage;
*/
- (UIImage *)resizeToDeviceScale;
/**
* @author wangyang in 2016-7-1
*
* 参考rotatedWithTransform
*/
- (UIImage *)rotatedWithAngle:(double)angle;
/**
* @author wangyang in 2016-7-1
*
* 使用这个方法旋转图片,导出的图片的imageOrientation为Up,绘制时会同时考虑待旋转图片的原 imageOrientation 与参数 transform
@note
1. 使用这个方法进行旋转,导出的图片大小可能会发生变化。比如旋转45度,那么能容下原图的bounds肯定要大一些;比如旋转90度,图片的高宽就会互换。
2. 旋转角度为0时,可以用来将图片的imageOrientation重置为Up。
* @return 新图片
*/
- (UIImage *)rotatedWithTransform:(CGAffineTransform)transform;
/**
* @author wangyang in 2016-7-4
*
* 裁剪图片
*/
- (UIImage *)imageWithCropRect:(CGRect)rect;
@end
//
// UIImage+GM.m
// Gengmei
//
// Created by licong on 15/12/29. Rewrite by wangyang on 2016-7-4
// Copyright © 2016年 Wanmeichuangyi. All rights reserved.
//
#import "UIImage+GM.h"
@implementation UIImage (GM)
#pragma mark - 从颜色生成图片
+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#pragma mark - 改变大小
- (UIImage *)resizedImageWithSize:(CGSize)size {
UIGraphicsBeginImageContext(size);
CGRect rect = CGRectMake(0, 0, size.width, size.height);
// CGContextDrawImage时需要额外考虑UIImage.imageOrientation,drawInRect可以自动帮我们做好这件事
[self drawInRect:rect];
// 另外,我们不需要指定使用 CGContextSetInterpolationQuality,使用默认值Hight就可以。参考http://stackoverflow.com/questions/5685884/imagequality-with-cgcontextsetinterpolationquality
UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImg;
}
- (UIImage *)resizeToDeviceScale {
CGSize newSize = CGSizeMake(ceilf(self.size.width / 3), ceilf(self.size.height / 3));
UIGraphicsBeginImageContextWithOptions(newSize, NO, [UIScreen mainScreen].scale);
CGRect rect = CGRectMake(0, 0, newSize.width, newSize.height);
// CGContextDrawImage时需要额外考虑UIImage.imageOrientation,drawInRect可以自动帮我们做好这件事
[self drawInRect:rect];
// 另外,我们不需要指定使用 CGContextSetInterpolationQuality,使用默认值Hight就可以。参考http://stackoverflow.com/questions/5685884/imagequality-with-cgcontextsetinterpolationquality
UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImg;
}
#pragma mark - 旋转
- (UIImage *)rotatedWithAngle:(double)angle
{
CGAffineTransform transform = CGAffineTransformMakeRotation(angle * M_PI / 180);
return [self rotatedWithTransform:transform];
}
- (UIImage *)rotatedWithTransform:(CGAffineTransform)transform {
// 旋转后图片的大小
CGRect rotatedRect = CGRectApplyAffineTransform(CGRectMake(0, 0, self.size.width, self.size.height), transform);
rotatedRect.origin.x = 0;
rotatedRect.origin.y = 0;
CGSize rotatedSize = rotatedRect.size;
UIGraphicsBeginImageContextWithOptions(rotatedSize, YES, self.scale);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
// 将 origin 图片的移动中间, 这样我们就可以绕着中心点旋转
CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2);
// 旋转画布布
CGContextConcatCTM(bitmap, transform);
// 再将 origin 移回来
CGContextTranslateCTM(bitmap, rotatedSize.width / -2, rotatedSize.height / -2);
// drawInRect 会考虑图片的 orientation,也会考虑当前Context的变换
[self drawInRect:rotatedRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#pragma mark - 剪切
- (UIImage *)imageWithCropRect:(CGRect)rect
{
CGImageRef croppedImage = CGImageCreateWithImageInRect(self.CGImage, rect);
UIImage *image = [UIImage imageWithCGImage:croppedImage];
CGImageRelease(croppedImage);
return image;
}
@end
//
// UILabel+CopyExtern.h
// CopyLabel
//
// Created by XingBo on 14-4-1.
// Copyright (c) 2014年 XingBo. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UILabel (CopyExtern)
- (void)attachTapHandler;
@end
//
// UILabel+CopyExtern.m
// CopyLabel
//
// Created by XingBo on 14-4-1.
// Copyright (c) 2014年 XingBo. All rights reserved.
//
#import "UILabel+CopyExtern.h"
@implementation UILabel (CopyExtern)
-(BOOL)canBecomeFirstResponder
{
return YES;
}
// 可以响应的方法
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return (action == @selector(copyText:));
}
//针对于响应方法的实现
-(void)copyText:(id)sender
{
UIPasteboard *pboard = [UIPasteboard generalPasteboard];
/**
fix帖子详情页 楼主发帖复制崩溃bug
因为某些富文本label只设置了attributedText,导致self.text为nil崩溃
*/
if (self.text) {
pboard.string = self.text;
}else{
pboard.string = self.attributedText.string;
}
}
//UILabel默认是不接收事件的,我们需要自己添加touch事件
-(void)attachTapHandler{
self.userInteractionEnabled = YES; //用户交互的总开关
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self addGestureRecognizer:longPress];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillShowMenuNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerWillHideMenuNotification object:nil];
}
#pragma mark - notifation methods
- (void)menuShow:(NSNotification *)sender
{
if (self.isFirstResponder) {
self.backgroundColor = [UIColor grayColor];
}
}
- (void)menuHide:(NSNotification *)sender
{
self.backgroundColor = [UIColor clearColor];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)handleTap:(UIGestureRecognizer*) recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self becomeFirstResponder];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuShow:) name:UIMenuControllerWillShowMenuNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuHide:) name:UIMenuControllerWillHideMenuNotification object:nil];
[[UIMenuController sharedMenuController] setMenuItems:nil];
UIMenuItem *copyLink = [[UIMenuItem alloc] initWithTitle:@"复制"
action:@selector(copyText:)];
[[UIMenuController sharedMenuController] setMenuItems:[NSArray arrayWithObjects:copyLink, nil]];
[[UIMenuController sharedMenuController] setTargetRect:self.frame inView:self.superview];
[[UIMenuController sharedMenuController] setMenuVisible:YES animated: YES];
// label复制选中时的背景颜色
self.backgroundColor = [UIColor clearColor];
}
}
@end
//
// UITextView+Keyboard.h
// ZhengXing
//
// Created by Tulipa on 14-8-22.
// Copyright (c) 2014年 Wanmei Creative. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UITextView (Keyboard)
@property (nonatomic, assign) BOOL hasCloseButton;
@end
@interface UITextField (Keyboard)
@property (nonatomic, assign) BOOL hasCloseButton;
@end
//
// UITextView+Keyboard.m
// ZhengXing
//
// Created by Tulipa on 14-8-22.
// Copyright (c) 2014年 Wanmei Creative. All rights reserved.
//
#import "UITextView+Keyboard.h"
#import "UIView+Layout.h"
@implementation UITextView (Keyboard)
- (BOOL)hasCloseButton
{
return self.inputAccessoryView != nil;
}
- (void)setHasCloseButton:(BOOL)hasCloseButton
{
if (hasCloseButton)
{
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeButton setBackgroundImage:[UIImage imageNamed:@"keyboard"] forState:UIControlStateNormal];
[closeButton sizeToFit];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, closeButton.height)];
[view addSubview:closeButton];
[view setBackgroundColor:[UIColor clearColor]];
[closeButton setRight:view.width];
[closeButton setTop:0];
[closeButton addTarget:self action:@selector(resignFirstResponder) forControlEvents:UIControlEventTouchUpInside];
self.inputAccessoryView = view;
}
else
{
self.inputAccessoryView = nil;
}
}
@end
@implementation UITextField (Keyboard)
- (BOOL)hasCloseButton
{
return self.inputAccessoryView != nil;
}
- (void)setHasCloseButton:(BOOL)hasCloseButton
{
if (hasCloseButton)
{
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeButton setBackgroundImage:[UIImage imageNamed:@"keyboard"] forState:UIControlStateNormal];
[closeButton sizeToFit];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, closeButton.height)];
[view addSubview:closeButton];
[view setBackgroundColor:[UIColor clearColor]];
[closeButton setRight:view.width];
[closeButton setTop:0];
[closeButton addTarget:self action:@selector(resignFirstResponder) forControlEvents:UIControlEventTouchUpInside];
self.inputAccessoryView = view;
}
else
{
self.inputAccessoryView = nil;
}
}
@end
//
// UIView+Layout.h
// Gengmei
//
// Created by licong on 15/12/29.
// Copyright © 2015年 Wanmeichuangyi. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (Layout)
/**
* Shortcut for frame.origin.x.
*
* Sets frame.origin.x = left
*/
@property (nonatomic) CGFloat left;
/**
* Shortcut for frame.origin.y
*
* Sets frame.origin.y = top
*/
@property (nonatomic) CGFloat top;
/**
* Shortcut for frame.origin.x + frame.size.width
*
* Sets frame.origin.x = right - frame.size.width
*/
@property (nonatomic) CGFloat right;
/**
* Shortcut for frame.origin.y + frame.size.height
*
* Sets frame.origin.y = bottom - frame.size.height
*/
@property (nonatomic) CGFloat bottom;
/**
* Shortcut for frame.size.width
*
* Sets frame.size.width = width
*/
@property (nonatomic) CGFloat width;
/**
* Shortcut for frame.size.height
*
* Sets frame.size.height = height
*/
@property (nonatomic) CGFloat height;
/**
* Shortcut for center.x
*
* Sets center.x = centerX
*/
@property (nonatomic) CGFloat centerX;
/**
* Shortcut for center.y
*
* Sets center.y = centerY
*/
@property (nonatomic) CGFloat centerY;
/**
* Return the x coordinate on the screen.
*/
@property (nonatomic, readonly) CGFloat screenX;
/**
* Return the y coordinate on the screen.
*/
@property (nonatomic, readonly) CGFloat screenY;
/**
* Return the x coordinate on the screen, taking into account scroll views.
*/
@property (nonatomic, readonly) CGFloat screenViewX;
/**
* Return the y coordinate on the screen, taking into account scroll views.
*/
@property (nonatomic, readonly) CGFloat screenViewY;
/**
* Return the view frame on the screen, taking into account scroll views.
*/
@property (nonatomic, readonly) CGRect screenFrame;
/**
* Shortcut for frame.origin
*/
@property (nonatomic) CGPoint origin;
/**
* Shortcut for frame.size
*/
@property (nonatomic) CGSize size;
/**
* Return the width in portrait or the height in landscape.
*/
@property (nonatomic, readonly) CGFloat orientationWidth;
/**
* Return the height in portrait or the width in landscape.
*/
@property (nonatomic, readonly) CGFloat orientationHeight;
/**
* Finds the first descendant view (including this view) that is a member of a particular class.
*/
- (UIView*)descendantOrSelfWithClass:(Class)cls;
/**
* Finds the first ancestor view (including this view) that is a member of a particular class.
*/
- (UIView*)ancestorOrSelfWithClass:(Class)cls;
/**
* Removes all subviews.
*/
- (void)removeAllSubviews;
@end
@interface UIView (GestureAction)
/**
Attaches the given block for a single tap action to the receiver.
@param block The block to execute.
*/
- (void)setTapActionWithBlock:(void (^)(void))block;
//- (void)removeTapAction;
/**
Attaches the given block for a long press action to the receiver.
@param block The block to execute.
*/
- (void)setLongPressActionWithBlock:(void (^)(void))block;
@end
//
// UIView+Layout.m
// Gengmei
//
// Created by licong on 15/12/29.
// Copyright © 2015年 Wanmeichuangyi. All rights reserved.
//
#import "UIView+Layout.h"
#import <objc/runtime.h>
static char kDTActionHandlerTapBlockKey;
static char kDTActionHandlerTapGestureKey;
static char kDTActionHandlerLongPressBlockKey;
static char kDTActionHandlerLongPressGestureKey;
@implementation UIView (Layout)
- (CGFloat)left {
return self.frame.origin.x;
}
- (void)setLeft:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (CGFloat)top {
return self.frame.origin.y;
}
- (void)setTop:(CGFloat)y {
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (CGFloat)right {
return self.frame.origin.x + self.frame.size.width;
}
- (void)setRight:(CGFloat)right {
CGRect frame = self.frame;
frame.origin.x = right - frame.size.width;
self.frame = frame;
}
- (CGFloat)bottom {
return self.frame.origin.y + self.frame.size.height;
}
- (void)setBottom:(CGFloat)bottom {
CGRect frame = self.frame;
frame.origin.y = bottom - frame.size.height;
self.frame = frame;
}
- (CGFloat)centerX {
return self.center.x;
}
- (void)setCenterX:(CGFloat)centerX {
self.center = CGPointMake(centerX, self.center.y);
}
- (CGFloat)centerY {
return self.center.y;
}
- (void)setCenterY:(CGFloat)centerY {
self.center = CGPointMake(self.center.x, centerY);
}
- (CGFloat)width {
return self.frame.size.width;
}
- (void)setWidth:(CGFloat)width {
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (CGFloat)height {
return self.frame.size.height;
}
- (void)setHeight:(CGFloat)height {
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)screenX {
CGFloat x = 0.0f;
for (UIView* view = self; view; view = view.superview) {
x += view.left;
}
return x;
}
- (CGFloat)screenY {
CGFloat y = 0.0f;
for (UIView* view = self; view; view = view.superview) {
y += view.top;
}
return y;
}
- (CGFloat)screenViewX {
CGFloat x = 0.0f;
for (UIView* view = self; view; view = view.superview) {
x += view.left;
if ([view isKindOfClass:[UIScrollView class]]) {
UIScrollView* scrollView = (UIScrollView*)view;
x -= scrollView.contentOffset.x;
}
}
return x;
}
- (CGFloat)screenViewY {
CGFloat y = 0;
for (UIView* view = self; view; view = view.superview) {
y += view.top;
if ([view isKindOfClass:[UIScrollView class]]) {
UIScrollView* scrollView = (UIScrollView*)view;
y -= scrollView.contentOffset.y;
}
}
return y;
}
- (CGRect)screenFrame {
return CGRectMake(self.screenViewX, self.screenViewY, self.width, self.height);
}
- (CGPoint)origin {
return self.frame.origin;
}
- (void)setOrigin:(CGPoint)origin {
CGRect frame = self.frame;
frame.origin = origin;
self.frame = frame;
}
- (CGSize)size {
return self.frame.size;
}
- (void)setSize:(CGSize)size {
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
- (CGFloat)orientationWidth {
return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)
? self.height : self.width;
}
- (CGFloat)orientationHeight {
return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)
? self.width : self.height;
}
- (UIView*)descendantOrSelfWithClass:(Class)cls {
if ([self isKindOfClass:cls])
return self;
for (UIView* child in self.subviews) {
UIView* it = [child descendantOrSelfWithClass:cls];
if (it)
return it;
}
return nil;
}
- (UIView*)ancestorOrSelfWithClass:(Class)cls {
if ([self isKindOfClass:cls]) {
return self;
} else if (self.superview) {
return [self.superview ancestorOrSelfWithClass:cls];
} else {
return nil;
}
}
- (void)removeAllSubviews {
while (self.subviews.count) {
UIView* child = self.subviews.lastObject;
[child removeFromSuperview];
}
}
- (CGPoint)offsetFromView:(UIView*)otherView {
CGFloat x = 0.0f, y = 0.0f;
for (UIView* view = self; view && view != otherView; view = view.superview) {
x += view.left;
y += view.top;
}
return CGPointMake(x, y);
}
@end
@implementation UIView (GestureAction)
- (void)setTapActionWithBlock:(void (^)(void))block
{
UITapGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerTapGestureKey);
if (!gesture)
{
gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForTapGesture:)];
[self addGestureRecognizer:gesture];
objc_setAssociatedObject(self, &kDTActionHandlerTapGestureKey, gesture, OBJC_ASSOCIATION_RETAIN);
}
objc_setAssociatedObject(self, &kDTActionHandlerTapBlockKey, block, OBJC_ASSOCIATION_COPY);
}
- (void)__handleActionForTapGesture:(UITapGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateRecognized)
{
void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerTapBlockKey);
if (action)
{
action();
}
}
}
- (void)setLongPressActionWithBlock:(void (^)(void))block
{
UILongPressGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerLongPressGestureKey);
if (!gesture)
{
gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForLongPressGesture:)];
[self addGestureRecognizer:gesture];
objc_setAssociatedObject(self, &kDTActionHandlerLongPressGestureKey, gesture, OBJC_ASSOCIATION_RETAIN);
}
objc_setAssociatedObject(self, &kDTActionHandlerLongPressBlockKey, block, OBJC_ASSOCIATION_COPY);
}
- (void)__handleActionForLongPressGesture:(UITapGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan)
{
void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerLongPressBlockKey);
if (action)
{
action();
}
}
}
@end
//
// UIView+LineWithAutolayout.h
// ZhengXing
//
// Created by wangyang on 11/6/14.
// Copyright (c) 2014 Wanmei Creative. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (LineWithAutolayout)
/**
* @author licong, 16-12-28 19:12:48
*
* alloc一个无固定大小的view,用作分割线
*
* @return 返回一个view
*
* @since 5.8
*/
- (UIView *)addLineWithoutFrame;
/**
* @author licong, 16-12-28 19:12:16
*
* 在指定view(就是self)的最上边缘,加一根与指定view宽度相等的头部边缘线
*
* @return 返回alloc的分割线
*
* @since 5.8
*/
- (UIView *)addTopLine;
/**
* @author licong, 16-12-28 19:12:16
*
* 在view(就是self)的最下边缘,加一根与指定view宽度相等的底部边缘线
*
* @return 返回alloc的分割线
*
* @since 5.8
*/
- (UIView *)addBottomLine;
/**
* @author licong, 16-12-28 19:13:30
*
* 给指定的view(就是self),加一跟中心水平线
*
* @param left 竖直线距离设定的view左边的距离
* @param right 竖直线距离设定的view右边的距离
*
* @return 返回alloc的中心竖直线
*
* @since 5.8
*/
- (UIView *)addCenterHorizontalLineWithLeft:(CGFloat)left right:(CGFloat)right;
/**
* @author licong, 16-12-28 19:12:40
*
* 给指定的view(就是self),加一跟中心竖直线
*
* @param top 竖直线距离设定的view上边的距离
* @param bottom 竖直线距离设定的view下边的距离
*
* @return 返回alloc的中心竖直线
*
* @since 5.8
*/
- (UIView *)addCenterVerticalLineWithTop:(CGFloat)top bottom:(CGFloat)bottom;
/**
* @author licong, 16-12-28 19:12:19
*
* 给指定的view(就是self)的最下边缘,加一根长度可设置的头部边缘线(最长不超过该view的宽度)
*
* @param left 头部边缘线距离设定view左边的距离
* @param right 头部边缘线距离设定view左边的距离
*
* @return 返回长度可设置的头部边缘线
*
* @since 5.8
*/
- (UIView *)addTopLineWithLeft:(CGFloat)left right:(CGFloat)right;
/**
* @author licong, 16-12-28 19:12:16
*
* 给指定的view(就是self)的最下边缘,加一根长度可设置的底部边缘线(最长不超过该view的宽度)
*
* @param left 底部边缘线距离设定view左边缘的距离
* @param right 底部边缘线距离设定view右边缘的距离
*
* @return 返回长度可设置的底部边缘线
*
* @since 5.8
*/
- (UIView *)addBottomLineWithLeft:(CGFloat)left right:(CGFloat)right;
/**
* @author licong, 16-12-29 11:12:02
*
* 给指定的view(就是self),加一根长度可设置的水平线,以Top为Y方向的基准点
*
* @param top 水平线距离设定view上边缘的距离
* @param left 水平线距离设定view左边缘的距离
* @param right 水平线距离设定view右边缘的距离
*
* @return 返回水平线
*
* @since 5.8
*/
- (UIView *)addHorizontalLineWithTop:(CGFloat)top left:(CGFloat)left right:(CGFloat)right;
/**
* @author licong, 16-12-29 11:12:48
*
* 给指定的view(就是self),加一根长度可设置的水平线,以Bottom为Y方向的基准点
*
* @param bottom 水平线距离设定view下边缘的距离
* @param left 水平线距离设定view左边缘的距离
* @param right 水平线距离设定view右边缘的距离
*
* @return 返回水平线
*
* @since 5.8
*/
- (UIView *)addHorizontalLineWithBottom:(CGFloat)bottom left:(CGFloat)left right:(CGFloat)right;
/**
* @author licong, 16-12-29 11:12:48
*
* 给指定的view(就是self),加一根长度可设置的竖直线,以Left为X方向的基准点
*
* @param left 竖直线距离设定view左边缘的距离
* @param top 竖直线距离设定view上边缘的距离
* @param bottom 竖直线距离设定view下边缘的距离
*
* @return 返回竖直线
*
* @since 5.8
*/
- (UIView *)addVerticalLineWithLeft:(CGFloat)left top:(CGFloat)top bottom:(CGFloat)bottom;
/**
* @author licong, 16-12-29 11:12:54
*
* 给指定的view(就是self),加一根长度可设置的竖直线,以Right为X方向的基准点
*
* @param right 竖直线距离设定view右边缘的距离
* @param top 竖直线距离设定view上边缘的距离
* @param bottom 竖直线距离设定view下边缘的距离
*
* @return 返回竖直线
*
* @since 58
*/
- (UIView *)addVerticalLineWithRight:(CGFloat)right top:(CGFloat)top bottom:(CGFloat)bottom;
@end
//
// UIView+LineWithAutolayout.m
// ZhengXing
//
// Created by wangyang on 11/6/14.
// Copyright (c) 2014 Wanmei Creative. All rights reserved.
//
#import "UIView+LineWithAutolayout.h"
#import <Masonry/Masonry.h>
#import <UIColor+GMTheme.h>
@interface OnePixelLine : UIView
@end
@implementation OnePixelLine
@end
@implementation UIView (LineWithAutolayout)
- (UIView *)addLineWithoutFrame{
UIView *line = [OnePixelLine new];
line.backgroundColor = UIColor.separatorLine;
[self addSubview:line];
return line;
}
- (UIView *)addTopLine
{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(0);
make.left.mas_equalTo(0);
make.right.mas_equalTo(0);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addBottomLine
{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(0);
make.left.mas_equalTo(0);
make.right.mas_equalTo(0);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addCenterHorizontalLineWithLeft:(CGFloat)left right:(CGFloat)right{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.mas_equalTo(0);
make.left.mas_equalTo(left);
make.right.mas_equalTo(right);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addCenterVerticalLineWithTop:(CGFloat)top bottom:(CGFloat)bottom{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(top);
make.centerX.mas_equalTo(0);
make.bottom.mas_equalTo(bottom);
make.width.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addTopLineWithLeft:(CGFloat)left right:(CGFloat)right{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(0);
make.left.mas_equalTo(left);
make.right.mas_equalTo(right);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addBottomLineWithLeft:(CGFloat)left right:(CGFloat)right{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(0);
make.left.mas_equalTo(left);
make.right.mas_equalTo(right);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addHorizontalLineWithTop:(CGFloat)top left:(CGFloat)left right:(CGFloat)right{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(top);
make.left.mas_equalTo(left);
make.right.mas_equalTo(right);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addHorizontalLineWithBottom:(CGFloat)bottom left:(CGFloat)left right:(CGFloat)right{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(bottom);
make.left.mas_equalTo(left);
make.right.mas_equalTo(right);
make.height.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addVerticalLineWithLeft:(CGFloat)left top:(CGFloat)top bottom:(CGFloat)bottom{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(top);
make.left.mas_equalTo(left);
make.bottom.mas_equalTo(bottom);
make.width.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
- (UIView *)addVerticalLineWithRight:(CGFloat)right top:(CGFloat)top bottom:(CGFloat)bottom{
UIView *line = [self addLineWithoutFrame];
[line mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(top);
make.right.mas_equalTo(right);
make.bottom.mas_equalTo(bottom);
make.width.offset(1/[UIScreen mainScreen].scale);
}];
return line;
}
@end
//
// UIViewController+ChildSwitch.h
// segmentSwitch
//
// Created by wangyang on 5/13/15.
// Copyright (c) 2015 IGIU. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIViewController (ChildControllerSwitch)
#pragma mark - 只读属性
/**
当前显示的controller
*/
@property (nonatomic, strong) UIViewController *currentController;
/**
将childContainer添加到视图中用来显示所有的child
注意:childContainer只有一个子视图:childScrollView,childScrollView装载了所有的child。
*/
@property (nonatomic, strong) IBOutlet UIView *childContainer;
/**
用来横滑切换chile controller。可以使用childScrollView.scrollEnable来禁止。
其contentSize的高为childContainer.height
*/
@property (nonatomic, strong) UIScrollView *childScrollView;
/**
返回该类别所管理的chile view controllers
*/
@property (nonatomic, copy) NSArray *childs;
#pragma mark - 需要配置的属性
/**
childContainer的size,需要手动计算出来
*/
@property (nonatomic, assign) CGSize childContainerSize;
/**
滑动childScrollView,滑动停止,调用该block。典型使用就是通知segment切换到指定位置
*/
@property (nonatomic, copy) void (^childScrollViewDidEndScroll) (NSInteger index);
#pragma mark - 可选属性
/**
switchToChildControllerAtIndex后会调用
*/
@property (nonatomic, copy) void (^didFinishSwitchChild) (void);
#pragma mark - 方法
/**
* @brief 设置第一个要显示的controller
*
*/
- (void)setFirstController:(UIViewController *)controller;
/**
* @brief 添加待显示的controllers
*
*/
- (void)addOtherController:(NSArray *)otherControllers;
/**
设置第一个需要显示的controller及其它待显示的controllers
*/
- (void)setFirstController:(UIViewController *)controller otherController:(NSArray *)otherControllers;
/**
切换到指定位置的controller
*/
- (void)switchToChildControllerAtIndex:(NSUInteger)index;
@end
//
// UIViewController+ChildSwitch.m
// segmentSwitch
//
// Created by wangyang on 5/13/15.
// Copyright (c) 2015 IGIU. All rights reserved.
//
#import "UIViewController+ChildControllerSwitch.h"
#import <objc/runtime.h>
#import <Masonry/Masonry.h>
#import "UIView+Layout.h"
#import "Constant.h"
@interface NSObject (CustomClass)
@end
@implementation NSObject (CustomClass)
@end
@interface ScrollViewDelegate: NSObject <UIScrollViewDelegate>
@property (nonatomic, copy) void (^scrollViewEndScroll) (void);
@end
@implementation ScrollViewDelegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if (self.scrollViewEndScroll) {
self.scrollViewEndScroll();
}
}
@end
@interface UIViewController ()
@property (nonatomic, strong) ScrollViewDelegate *scrollDelegate;
@end
@implementation UIViewController (ChildControllerSwitch)
/**
* set方法是为了适应IB,如果纯代码可以不用set方法
*/
- (void)setChildContainer:(UIView *)childContainer{
objc_setAssociatedObject(self, @selector(childContainer), childContainer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIView *)childContainer{
UIView *childContainer = objc_getAssociatedObject(self, _cmd);
if (!childContainer) {
childContainer = [[UIView alloc] init];
childContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
objc_setAssociatedObject(self, _cmd, childContainer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return childContainer;
}
- (void)setCurrentController:(UIViewController *)currentController{
objc_setAssociatedObject(self, NSSelectorFromString(@"currentController"), currentController, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIViewController *)currentController{
return objc_getAssociatedObject(self, NSSelectorFromString(@"currentController"));
}
- (void)setChildScrollView:(UIScrollView *)childScrollView {
objc_setAssociatedObject(self, @selector(childScrollView), childScrollView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIScrollView *)childScrollView {
UIScrollView *_childScrollView = objc_getAssociatedObject(self, @selector(childScrollView));
if (_childScrollView == nil) {
_childScrollView = [UIScrollView new];
_childScrollView.delegate = self.scrollDelegate;
_childScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.childContainer addSubview:_childScrollView];
_childScrollView.pagingEnabled = YES;
_childScrollView.scrollsToTop = NO;
_childScrollView.showsHorizontalScrollIndicator = NO;
[_childScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsZero);
}];
objc_setAssociatedObject(self, _cmd, _childScrollView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return _childScrollView;
}
- (void)setScrollDelegate:(ScrollViewDelegate *)scrollDelegate {
objc_setAssociatedObject(self, @selector(scrollDelegate), scrollDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (ScrollViewDelegate *)scrollDelegate {
ScrollViewDelegate *_scrollDelegate = objc_getAssociatedObject(self, @selector(scrollDelegate));
if (_scrollDelegate == nil) {
_scrollDelegate = [ScrollViewDelegate new];
__weak __typeof(self) weakSelf = self;
_scrollDelegate.scrollViewEndScroll = ^{
[weakSelf prepareChangeController];
};
objc_setAssociatedObject(self, _cmd, _scrollDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return _scrollDelegate;
}
- (void)setChildContainerSize:(CGSize)childContainerSize {
NSValue *size = [NSValue valueWithCGSize:childContainerSize];
objc_setAssociatedObject(self, @selector(childContainerSize), size, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (self.childs.count != 0) {
#warning 这个高度是否可以直接使用self.height
self.childScrollView.contentSize = CGSizeMake(childContainerSize.width * self.childs.count , childContainerSize.height);
}
}
- (CGSize)childContainerSize {
NSValue *size = objc_getAssociatedObject(self, @selector(childContainerSize));
if (size == nil) {
return CGSizeZero;
} else {
return [size CGSizeValue];
}
}
- (void)setChildScrollViewDidEndScroll:(void (^) (NSInteger))block {
objc_setAssociatedObject(self, @selector(childScrollViewDidEndScroll), block, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void (^) (NSInteger))childScrollViewDidEndScroll {
id block = objc_getAssociatedObject(self, @selector(childScrollViewDidEndScroll));
return block;
}
- (void)setChilds:(NSArray *)childs {
objc_setAssociatedObject(self, @selector(childs), childs, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSArray *)childs {
NSArray *_childs = objc_getAssociatedObject(self, @selector(childs));
return _childs;
}
- (void)setDidFinishSwitchChild:(void (^) (void))block {
objc_setAssociatedObject(self, @selector(didFinishSwitchChild), block, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void (^) (void))didFinishSwitchChild {
id block = objc_getAssociatedObject(self, @selector(didFinishSwitchChild));
return block;
}
#pragma mark - 方法
- (void)setFirstController:(UIViewController *)controller {
[self addForwardAppearanceMethods:controller];
self.childContainer.size = self.childContainerSize;
self.childScrollView.size = self.childContainerSize;
controller.view.frame = self.childContainer.bounds;
controller.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.childScrollView addSubview:controller.view];
self.currentController = controller;
[self addChildViewController:controller];
[self.currentController didMoveToParentViewController:self];
}
- (void)setFirstController:(UIViewController *)controller otherController:(NSArray *)otherControllers {
NSAssert(controller, @"不能设置nil为第一个controller");
NSAssert(self.childContainer.superview, @"self.childContainer must have a superview");
[self setFirstController:controller];
[self addOtherController:otherControllers];
}
- (void)addOtherController:(NSArray *)otherControllers {
NSAssert(self.currentController, @"不能设置nil为第一个controller");
for (UIViewController *other in otherControllers) {
[self addForwardAppearanceMethods:other];
[self addChildViewController:other];
}
self.childs = [[NSArray arrayWithObject:self.currentController] arrayByAddingObjectsFromArray:otherControllers];
CGSize size = CGSizeMake(self.childContainerSize.width * self.childs.count , self.childContainerSize.height);
self.childScrollView.contentSize = size;
}
- (void)addForwardAppearanceMethods:(UIViewController *)controller {
SEL sel = @selector(shouldAutomaticallyForwardAppearanceMethods);
IMP imp = imp_implementationWithBlock(^(){
return NO;
});
class_addMethod([controller class], sel, imp, "B@:");
}
- (void)switchToChildControllerAtIndex:(NSUInteger)index {
self.childScrollView.contentOffset = CGPointMake(index * self.childContainer.bounds.size.width, 0);
/*
比如A -> B -> A,因为A.view被添加到scrollView中就不会被移除,所以当再次回到A->B,或者B->A时,viewWillAppear等4个方法都不会调用
使用 beginAppearanceTransition:animated:、endAppearanceTransition 可以解决这个问题。
另外需要配合 shouldAutomaticallyForwardAppearanceMethods 使用。
beginAppearanceTransition:animated: 设置为YES触发Child View Controller的viewWillAppear;
beginAppearanceTransition:animated: 设置为NO触发Child View Controller的viewWillDisappear;
endAppearanceTransition 触发Child View Controller的viewDidAppear 和viewDidDisappear
*/
UIViewController *to = self.childViewControllers[index];
UIViewController *from = self.currentController;
if (to == from) {
if (self.didFinishSwitchChild) {
self.didFinishSwitchChild();
}
} else {
if (to.view.superview == nil) {
CGRect frame = self.childContainer.bounds;
frame.origin.x = frame.size.width * index;
frame.size = self.childContainer.size;
to.view.frame = frame;
to.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.childScrollView addSubview:to.view];
[from beginAppearanceTransition:NO animated:NO];
[to didMoveToParentViewController:self];
[from endAppearanceTransition];
} else {
[to beginAppearanceTransition:YES animated:NO];
[from beginAppearanceTransition:NO animated:NO];
[to endAppearanceTransition];
[from endAppearanceTransition];
}
self.currentController = to;
if (self.didFinishSwitchChild) {
self.didFinishSwitchChild();
}
}
}
- (void)prepareChangeController {
int index = self.childScrollView.contentOffset.x / self.childContainer.bounds.size.width;
[self switchToChildControllerAtIndex:index];
if (self.childScrollViewDidEndScroll) {
self.childScrollViewDidEndScroll(index);
}
}
@end
//
// UIColor+GMTheme.h
// Gengmei
// 主题
// Created by Thierry on 1/7/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#define RGBCOLOR_HEX(hexColor) [UIColor colorWithRed: (((hexColor >> 16) & 0xFF))/255.0f \
green: (((hexColor >> 8) & 0xFF))/255.0f \
blue: ((hexColor & 0xFF))/255.0f \
alpha: 1]
NS_ASSUME_NONNULL_BEGIN
@interface UIColor (GMTheme)
/** 医生版主视觉颜色,暂时改为红色,用来区分, (0x3ADBD2) */
@property (nonatomic, class, readonly) UIColor *mainVisual;
/** 医生版辅助颜色, (0xFF7690) */
@property (nonatomic, class, readonly) UIColor *secondaryVisual;
/** 医生版失效颜色, (0xD5D5D5) */
@property (nonatomic, class, readonly) UIColor *disable;
/** 医生版分割线颜色、边框颜色, (0xE5E5E5) */
@property (nonatomic, class, readonly) UIColor *separatorLine;
/** 医生版背景颜色, (0xF5F5F5) */
@property (nonatomic, class, readonly) UIColor *background;
/** 医生版提示背景颜色(黄), (0xF8F4DD) */
@property (nonatomic, class, readonly) UIColor *backgroundTip;
/** 医生版tag背景颜色, (0xF0F0F0) */
@property (nonatomic, class, readonly) UIColor *tagBackground;
/** 一级标题字、主要内容, (0x282828) */
@property (nonatomic, class, readonly) UIColor *headlineText;
/** 正文、普通文字内容, (0x464646) */
@property (nonatomic, class, readonly) UIColor *bodyText;
/** 可点击状态的文字更美绿, (0x4ABAB4) */
@property (nonatomic, class, readonly) UIColor *auxiliaryTextGreen;
/** 文字的更美红, (0xFF7690) */
@property (nonatomic, class, readonly) UIColor *auxiliaryTextRed;
/** 文字的更美黄提示色, (0x9D704F) */
@property (nonatomic, class, readonly) UIColor *auxiliaryTextYellow;
/** 辅助文字色, (0x666666) */
@property (nonatomic, class, readonly) UIColor *auxiliaryTextDark;
/** 辅助文字色, (0x999999) */
@property (nonatomic, class, readonly) UIColor *auxiliaryTextLight;
/** 辅助文字色, (0xcccccc) */
@property (nonatomic, class, readonly) UIColor *auxiliaryTextExtraLight;
/** 目前和MAIN_VISUAL_COLOR一样, (0x3ADBD2) */
@property (nonatomic, class, readonly) UIColor *buttonNormalGreen;
/** (0x1FB2A7) */
@property (nonatomic, class, readonly) UIColor *buttonHighlightGreen;
/** 目前和SECONDARY_VISUAL_COLOR一样, (0xFF7690) */
@property (nonatomic, class, readonly) UIColor *buttonNormalRed;
/** (0xE75873) */
@property (nonatomic, class, readonly) UIColor *buttonHighlightRed;
/** 目前和DISABLE_COLOR一样, (0xD5D5D5) */
@property (nonatomic, class, readonly) UIColor *buttonDisable;
/** 标签选中绿色, (0x24DAE0) */
@property (nonatomic, class, readonly) UIColor *tagSelectedGreen;
/**
用于色值是数字
*/
+ (UIColor *)colorWithHex:(NSInteger)hex;
+ (UIColor *)colorWithHex:(NSInteger)hex alpha:(CGFloat)alpha;
/**
用于色值字符串
*/
+ (UIColor *)colorWithHexString:(NSString *)hexString;
+ (UIColor *)colorWithHexString:(NSString *)hexString alpha:(CGFloat)alpha;
@end
NS_ASSUME_NONNULL_END
//
// UIColor+GMTheme.m
// GMKit
//
// Created by wangyang on 2017/11/8.
//
#import <UIColor+GMTheme.h>
//用户版色值
#ifdef IS_USER
//颜色规范
#define MAIN_VISUAL_COLOR RGBCOLOR_HEX(0x3ADBD2) //主视觉颜色
#define SECONDARY_VISUAL_COLOR RGBCOLOR_HEX(0xFF7690) //辅助颜色
#define SEPARATOR_LINE_COLOR RGBCOLOR_HEX(0xE5E5E5) //分割线颜色、边框颜色
#define BACKGROUND_COLOR RGBCOLOR_HEX(0xF4F3F8) //背景颜色
#define DISABLE_COLOR RGBCOLOR_HEX(0xD5D5D5) //失效颜色
#define BACKGROUND_TIP_COLOR RGBCOLOR_HEX(0xFFFBE4) //提示背景颜色(黄)
#define TAG_BACKGROUND_COLOR RGBCOLOR_HEX(0xF0F0F0) //tag背景颜色
#define TAG_SELECTED_COLOR RGBCOLOR_HEX(0x24DAE0)
//文字颜色
#define HEADLINE_TEXT_COLOR RGBCOLOR_HEX(0x282828) //一级标题字、主要内容
#define BODY_TEXT_COLOR RGBCOLOR_HEX(0x464646) //正文、普通文字内容
#define AUXILIARY_TEXT_GREEN RGBCOLOR_HEX(0x4ABAB4) //可点击状态的文字更美绿
#define AUXILIARY_TEXT_RED RGBCOLOR_HEX(0xFF7690) //文字的更美红
#define AUXILIARY_TEXT_YELLOW RGBCOLOR_HEX(0x9D704F) //文字的更美黄提示色
#define AUXILIARY_TEXT_COLOR_DARK RGBCOLOR_HEX(0x666666) //辅助文字色
#define AUXILIARY_TEXT_COLOR_LIGHT RGBCOLOR_HEX(0x999999) //辅助文字色
#define AUXILIARY_TEXT_COLOR_EXTRA_LIGHT RGBCOLOR_HEX(0xcccccc) //辅助文字色
//按钮颜色
#define BUTTON_NORMAL_GREEN_COLOR RGBCOLOR_HEX(0x3ADBD2) //目前和MAIN_VISUAL_COLOR一样
#define BUTTON_HIGHLIGHT_GREEN_COLOR RGBCOLOR_HEX(0x1FB2A7)
#define BUTTON_NORMAL_RED_COLOR RGBCOLOR_HEX(0xFF7690) //目前和SECONDARY_VISUAL_COLOR一样
#define BUTTON_HIGHLIGHT_RED_COLOR RGBCOLOR_HEX(0xE75873)
#define BUTTON_DISABLE_COLOR RGBCOLOR_HEX(0xD5D5D5) //目前和DISABLE_COLOR一样
//医生版色值,目前未支持
#elif IS_DOCTOR
//颜色规范
#define MAIN_VISUAL_COLOR RGBCOLOR_HEX(0x3ADBD2) //医生版主视觉颜色,暂时改为红色,用来区分
#define SECONDARY_VISUAL_COLOR RGBCOLOR_HEX(0xFF7690) //医生版辅助颜色
#define SEPARATOR_LINE_COLOR RGBCOLOR_HEX(0xE5E5E5) //医生版分割线颜色、边框颜色
#define DISABLE_COLOR RGBCOLOR_HEX(0xD5D5D5) //医生版失效颜色
#define BACKGROUND_COLOR RGBCOLOR_HEX(0xF5F5F5) //医生版背景颜色
#define BACKGROUND_TIP_COLOR RGBCOLOR_HEX(0xF8F4DD) //医生版提示背景颜色(黄)
#define TAG_BACKGROUND_COLOR RGBCOLOR_HEX(0xF0F0F0) //医生版tag背景颜色
#define TAG_SELECTED_COLOR RGBCOLOR_HEX(0x24DAE0) //tag标签选中颜色
//文字颜色
#define HEADLINE_TEXT_COLOR RGBCOLOR_HEX(0x282828) //一级标题字、主要内容
#define BODY_TEXT_COLOR RGBCOLOR_HEX(0x464646) //正文、普通文字内容
#define AUXILIARY_TEXT_GREEN RGBCOLOR_HEX(0x4ABAB4) //可点击状态的文字更美绿
#define AUXILIARY_TEXT_RED RGBCOLOR_HEX(0xFF7690) //文字的更美红
#define AUXILIARY_TEXT_YELLOW RGBCOLOR_HEX(0x9D704F) //文字的更美黄提示色
#define AUXILIARY_TEXT_COLOR_DARK RGBCOLOR_HEX(0x666666) //辅助文字色
#define AUXILIARY_TEXT_COLOR_LIGHT RGBCOLOR_HEX(0x999999) //辅助文字色
#define AUXILIARY_TEXT_COLOR_EXTRA_LIGHT RGBCOLOR_HEX(0xcccccc) //辅助文字色
//按钮颜色
#define BUTTON_NORMAL_GREEN_COLOR RGBCOLOR_HEX(0x3ADBD2) //目前和MAIN_VISUAL_COLOR一样
#define BUTTON_HIGHLIGHT_GREEN_COLOR RGBCOLOR_HEX(0x1FB2A7)
#define BUTTON_NORMAL_RED_COLOR RGBCOLOR_HEX(0xFF7690) //目前和SECONDARY_VISUAL_COLOR一样
#define BUTTON_HIGHLIGHT_RED_COLOR RGBCOLOR_HEX(0xE75873)
#define BUTTON_DISABLE_COLOR RGBCOLOR_HEX(0xD5D5D5) //目前和DISABLE_COLOR一样
#else //这里的默认色值可以随意,默认填的是用户板的色值
//颜色规范
#define MAIN_VISUAL_COLOR RGBCOLOR_HEX(0x3ADBD2) //主视觉颜色
#define SECONDARY_VISUAL_COLOR RGBCOLOR_HEX(0xFF7690) //辅助颜色
#define SEPARATOR_LINE_COLOR RGBCOLOR_HEX(0xE5E5E5) //分割线颜色、边框颜色
#define BACKGROUND_COLOR RGBCOLOR_HEX(0xF4F3F8) //背景颜色
#define DISABLE_COLOR RGBCOLOR_HEX(0xD5D5D5) //失效颜色
#define BACKGROUND_TIP_COLOR RGBCOLOR_HEX(0xFFFBE4) //提示背景颜色(黄)
#define TAG_BACKGROUND_COLOR RGBCOLOR_HEX(0xF0F0F0) //tag背景颜色
#define TAG_SELECTED_COLOR RGBCOLOR_HEX(0x24DAE0) //tag标签选中颜色
//文字颜色
#define HEADLINE_TEXT_COLOR RGBCOLOR_HEX(0x282828) //一级标题字、主要内容
#define BODY_TEXT_COLOR RGBCOLOR_HEX(0x464646) //正文、普通文字内容
#define AUXILIARY_TEXT_GREEN RGBCOLOR_HEX(0x4ABAB4) //可点击状态的文字更美绿
#define AUXILIARY_TEXT_RED RGBCOLOR_HEX(0xFF7690) //文字的更美红
#define AUXILIARY_TEXT_YELLOW RGBCOLOR_HEX(0x9D704F) //文字的更美黄提示色
#define AUXILIARY_TEXT_COLOR_DARK RGBCOLOR_HEX(0x666666) //辅助文字色
#define AUXILIARY_TEXT_COLOR_LIGHT RGBCOLOR_HEX(0x999999) //辅助文字色
#define AUXILIARY_TEXT_COLOR_EXTRA_LIGHT RGBCOLOR_HEX(0xcccccc) //辅助文字色
//按钮颜色
#define BUTTON_NORMAL_GREEN_COLOR RGBCOLOR_HEX(0x3ADBD2) //目前和MAIN_VISUAL_COLOR一样
#define BUTTON_HIGHLIGHT_GREEN_COLOR RGBCOLOR_HEX(0x1FB2A7)
#define BUTTON_NORMAL_RED_COLOR RGBCOLOR_HEX(0xFF7690) //目前和SECONDARY_VISUAL_COLOR一样
#define BUTTON_HIGHLIGHT_RED_COLOR RGBCOLOR_HEX(0xE75873)
#define BUTTON_DISABLE_COLOR RGBCOLOR_HEX(0xD5D5D5) //目前和DISABLE_COLOR一样
#endif
@implementation UIColor (GMTheme)
/**
用于色值是数字
*/
+ (UIColor *)colorWithHex:(NSInteger)hex{
return [UIColor colorWithHex:hex alpha:1.0];
}
+ (UIColor *)colorWithHex:(NSInteger)hex alpha:(CGFloat)alpha{
CGFloat r = ((hex & 0xFF0000) >> 16) / 255.0;
CGFloat g = ((hex & 0x00FF00) >> 8) / 255.0;
CGFloat b = ((hex & 0x0000FF) >> 0) / 255.0;
return [UIColor colorWithRed:r green:g blue:b alpha:alpha];
}
/**
用于色值字符串
*/
+ (UIColor *)colorWithHexString:(NSString *)hexString{
return [UIColor colorWithHexString:hexString alpha:1.0];
}
+ (UIColor *)colorWithHexString:(NSString *)hexString alpha:(CGFloat)alpha{
unsigned int hex = 0;
NSScanner * scanner = [NSScanner scannerWithString:hexString];
if([scanner scanHexInt:&hex]){
return [UIColor colorWithHex:(NSInteger)hex alpha:alpha];
}else{
return [[UIColor alloc]init];
}
}
/**
色值库里的各种色值
*/
+ (UIColor *)mainVisual{
return MAIN_VISUAL_COLOR;
}
+ (UIColor *)secondaryVisual{
return SECONDARY_VISUAL_COLOR;
}
+ (UIColor *)disable{
return DISABLE_COLOR;
}
+ (UIColor *)separatorLine{
return SEPARATOR_LINE_COLOR;
}
+ (UIColor *)background{
return BACKGROUND_COLOR;
}
+ (UIColor *)backgroundTip{
return BACKGROUND_TIP_COLOR;
}
+ (UIColor *)tagBackground{
return TAG_BACKGROUND_COLOR;
}
+ (UIColor *)headlineText{
return HEADLINE_TEXT_COLOR;
}
+ (UIColor *)bodyText{
return BODY_TEXT_COLOR;
}
+ (UIColor *)auxiliaryTextGreen{
return AUXILIARY_TEXT_GREEN;
}
+ (UIColor *)auxiliaryTextRed{
return AUXILIARY_TEXT_RED;
}
+ (UIColor *)auxiliaryTextYellow{
return AUXILIARY_TEXT_YELLOW;
}
+ (UIColor *)auxiliaryTextDark{
return AUXILIARY_TEXT_COLOR_DARK;
}
+ (UIColor *)auxiliaryTextLight{
return AUXILIARY_TEXT_COLOR_LIGHT;
}
+ (UIColor *)auxiliaryTextExtraLight{
return AUXILIARY_TEXT_COLOR_EXTRA_LIGHT;
}
+ (UIColor *)buttonNormalGreen{
return BUTTON_NORMAL_GREEN_COLOR;
}
+ (UIColor *)buttonHighlightGreen{
return BUTTON_HIGHLIGHT_GREEN_COLOR;
}
+ (UIColor *)buttonNormalRed{
return BUTTON_NORMAL_RED_COLOR;
}
+ (UIColor *)buttonHighlightRed{
return BUTTON_HIGHLIGHT_RED_COLOR;
}
+ (UIColor *)buttonDisable{
return BUTTON_DISABLE_COLOR;
}
+ (UIColor *)tagSelectedGreen {
return TAG_SELECTED_COLOR;
}
@end
//
// GMConstant.h
// GMKit
//
// Created by wangyang on 2017/11/8.
//
#import <Foundation/Foundation.h>
#define MAINSCREEN_FRAME [[UIScreen mainScreen] bounds]
#define MAINSCREEN_WIDTH MAINSCREEN_FRAME.size.width
#define MAINSCREEN_HEIGHT MAINSCREEN_FRAME.size.height
#define ONE_PIXEL (1/[UIScreen mainScreen].scale)
#define APP_VERSION [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]
#define APP_BUILD_VERSION [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]
@interface Constant: NSObject
@property (nonatomic, readonly, class) CGRect screenBounds;
@property (nonatomic, readonly, class) CGFloat screenWidth;
@property (nonatomic, readonly, class) CGFloat statusBarHeight;
@property (nonatomic, readonly, class) CGFloat screenHeight;
@property (nonatomic, readonly, class) CGFloat onePixel;
@property (nonatomic, readonly, class) CGFloat deviceScale;
@property (nonatomic, readonly, class) NSString* appName;
@property (nonatomic, readonly, class) NSString* appVersion;
@property (nonatomic, readonly, class) NSString* appBuildVersion;
/*
appHome下面有Document、Libray、tmp等目录。注意与appBundle区分
*/
@property (nonatomic, readonly, class) NSString* appHome;
@property (nonatomic, readonly, class) NSString* appTemp;
@property (nonatomic, readonly, class) NSString* appDocument;
// 主应用所在目录
@property (nonatomic, readonly, class) NSString* appBundle;
@end
//
// GMConstant.m
// GMKit
//
// Created by wangyang on 2017/11/8.
//
#import "Constant.h"
@implementation Constant
+ (CGRect)screenBounds {
return [[UIScreen mainScreen] bounds];
}
+ (CGFloat)screenWidth {
return [[UIScreen mainScreen] bounds].size.width;
}
+ (CGFloat)statusBarHeight{
return [UIApplication sharedApplication].statusBarFrame.size.height;
}
+ (CGFloat)screenHeight {
return [[UIScreen mainScreen] bounds].size.height;
}
+ (CGFloat)onePixel {
return 1/[UIScreen mainScreen].scale;
}
+ (CGFloat)deviceScale {
return [UIScreen mainScreen].scale;
}
+ (NSString *)appName {
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
}
+ (NSString *)appVersion {
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
}
+ (NSString *)appBuildVersion {
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
}
+ (NSString *)appHome {
return NSHomeDirectory();
}
+ (NSString *)appTemp {
return NSTemporaryDirectory();
}
+ (NSString *)appDocument {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
+ (NSString *)appBundle {
return [NSBundle mainBundle].resourcePath;
}
@end
//
// SystemVersion.h
// GMKit
//
// Created by wangyang on 2017/11/8.
//
#import <Foundation/Foundation.h>
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options: NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options: NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options: NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options: NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options: NSNumericSearch] != NSOrderedDescending)
@interface SystemVersion : NSObject
+ (BOOL)equalTo:(NSString *)version;
+ (BOOL)greaterThan:(NSString *)version;
+ (BOOL)greaterThanOrEqualTo:(NSString *)version;
+ (BOOL)lessThan:(NSString *)version;
+ (BOOL)lessThanOrEqualTo:(NSString *)version;
@end
//
// SystemVersion.m
// GMKit
//
// Created by wangyang on 2017/11/8.
//
#import "SystemVersion.h"
@implementation SystemVersion
+ (BOOL)equalTo:(NSString *)version {
return [[[UIDevice currentDevice] systemVersion] compare:version options: NSNumericSearch] == NSOrderedSame;
}
+ (BOOL)greaterThan:(NSString *)version {
return [[[UIDevice currentDevice] systemVersion] compare:version options: NSNumericSearch] == NSOrderedDescending;
}
+ (BOOL)greaterThanOrEqualTo:(NSString *)version {
return [[[UIDevice currentDevice] systemVersion] compare:version options: NSNumericSearch] != NSOrderedAscending;
}
+ (BOOL)lessThan:(NSString *)version {
return [[[UIDevice currentDevice] systemVersion] compare:version options: NSNumericSearch] == NSOrderedAscending;
}
+ (BOOL)lessThanOrEqualTo:(NSString *)version {
return [[[UIDevice currentDevice] systemVersion] compare:version options: NSNumericSearch] != NSOrderedDescending;
}
@end
// The MIT License (MIT)
//
// Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
//
// 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 <UIKit/UIKit.h>
/// "UINavigation+FDFullscreenPopGesture" extends UINavigationController's swipe-
/// to-pop behavior in iOS 7+ by supporting fullscreen pan gesture. Instead of
/// screen edge, you can now swipe from any place on the screen and the onboard
/// interactive pop transition works seamlessly.
///
/// Adding the implementation file of this category to your target will
/// automatically patch UINavigationController with this feature.
@interface UINavigationController (FDFullscreenPopGesture)
/// The gesture recognizer that actually handles interactive pop.
@property (nonatomic, strong, readonly) UIPanGestureRecognizer *fd_fullscreenPopGestureRecognizer;
/// A view controller is able to control navigation bar's appearance by itself,
/// rather than a global way, checking "fd_prefersNavigationBarHidden" property.
/// Default to YES, disable it if you don't want so.
@property (nonatomic, assign) BOOL fd_viewControllerBasedNavigationBarAppearanceEnabled;
@end
/// Allows any view controller to disable interactive pop gesture, which might
/// be necessary when the view controller itself handles pan gesture in some
/// cases.
@interface UIViewController (FDFullscreenPopGesture)
/// Whether the interactive pop gesture is disabled when contained in a navigation
/// stack.
@property (nonatomic, assign) BOOL fd_interactivePopDisabled;
/// Indicate this view controller prefers its navigation bar hidden or not,
/// checked when view controller based navigation bar's appearance is enabled.
/// Default to NO, bars are more likely to show.
@property (nonatomic, assign) BOOL fd_prefersNavigationBarHidden;
/// Max allowed initial distance to left edge when you begin the interactive pop
/// gesture. 0 by default, which means it will ignore this limit.
@property (nonatomic, assign) CGFloat fd_interactivePopMaxAllowedInitialDistanceToLeftEdge;
@end
//
// GMAnnotation.h
// Gengmei
//
// Created by Thierry on 4/25/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface GMAnnotation : NSObject<MKAnnotation>
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
-(id) initWithCoordinate:(CLLocationCoordinate2D) coords;
@end
//
// GMAnnotation.m
// Gengmei
//
// Created by Thierry on 4/25/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "GMAnnotation.h"
@implementation GMAnnotation
-(id) initWithCoordinate:(CLLocationCoordinate2D) coords
{
if (self = [super init]) {
self.coordinate = coords;
}
return self;
}
@end
//
// GMButton.h
// Gengmei
//
// Created by Thierry on 12/26/14.
// Copyright (c) 2014 Wanmeichuangyi. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
//渐变按钮渐变方向
typedef NS_ENUM(NSUInteger, GMGradientType) {
GMGradientTypeTopToBottom = 0, //从上到小
GMGradientTypeLeftToRight = 1, //从左到右
GMGradientTypeLeftUpToRightLow = 2, //左上到右下
GMGradientTypeRightUpToLeftLow = 3, //右上到左下
};
//见设计稿(UI组件化->组件_按钮.sketch)
typedef NS_ENUM(NSUInteger, GMButtonType) {
GMButtonTypeGreen, //绿色无边框直角矩形
GMButtonTypeGreenRoundCorner, //绿色带6px的圆角无边框矩形
GMButtonTypeGreenSemicircle, //绿色半圆无边框矩形
GMButtonTypeGreenRoundCornerBorder, //绿色、6px圆角、1px的有边框的矩形
GMButtonTypeGreenSemicircleBorder, //绿色、半圆、1px的有边框的矩形
GMButtonTypeGreenRoundCornerGradient, //绿色、6px圆角、无边框的渐变矩形
GMButtonTypeGreenSemicircleGradient, //绿色、半圆、无边框的渐变矩形
GMButtonTypeRed, //红色无边框直角矩形
GMButtonTypeRedRoundCorner, //红色带6px的圆角无边框矩形
GMButtonTypeRedSemicircle, //红色半圆无边框矩形
GMButtonTypeRedRoundCornerBorder, //红色、6px圆角、1px的有边框的的矩形
GMButtonTypeRedRoundCornerGradient, //红色、6px圆角、无边框的渐变矩形
GMButtonTypeRedSemicircleGradient, //红色、半圆、无边框的渐变矩形
GMButtonTypeGraySemicircleBorder, //灰色、半圆、1px的有边框的矩形
};
@interface GMButton : UIButton
/**
* @author licong, 16-12-30 17:12:55
*
* 是否支持Button自适应热区,Apple人机交互指南建议,可点击控件的热区最好是44*44,默认是NO,不支持
*
* @since 5.8
*/
@property (nonatomic, assign) BOOL enableAdaptive;
/**
* @author licong, 16-12-30 17:12:31
*
* 自适应热区宽,默认是 44
*
* @since 5.8
*/
@property (nonatomic, assign) float adaptiveHotAreaWidth;
/**
* @author licong, 16-12-30 17:12:09
*
* 自适应热区高,默认是 44
*
* @since 5.8
*/
@property (nonatomic, assign) float adaptiveHotAreaHeight;
/**
* @author licong, 16-12-30 17:12:30
*
* 初始化方法
*
* @since 5.8
*/
- (void)setup __attribute__((objc_requires_super));
/**
* @author licong, 16-12-30 17:12:46
*
* 创建一个button,并设置好它的title、backgroundColor、size、titleColor
*
* @param title title
* @param bgColor backgroundColor
* @param size 大小
* @param titleColor title标题
*
* @return 返回创建好的button
*
* @since 5.8
*/
+ (instancetype)buttonWithTitle:(nullable NSString *)title
backgroundColor:(nullable UIColor *)bgColor
titleFontSize:(CGFloat)size
titleColor:(nullable UIColor *)titleColor;
/**
* @author licong
*
* UI组件化后自定制Button
*
* @param customType 工厂模式下的button类型
*
* @return 返回创建好的button
*
* @since 6.2.0
*/
+ (instancetype)buttonWithCustomType:(GMButtonType)customType;
/**
* @author licong, 16-12-30 17:12:29
*
* 根据Button的状态设置对应的背景颜色
*
* @param backgroundColor button的背景颜色
* @param state button的controlState
*
* @since 5.8
*/
- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state;
@end
NS_ASSUME_NONNULL_END
This diff is collapsed.
//
// GMCollectionView
// Gengmei
//
// Created by Thierry on 1/9/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface GMCollectionView : UICollectionView
@end
@interface UICollectionView (Reuse)
- (void)registerHeader:(Class)headerClass NS_SWIFT_NAME(register(header:));
- (void)registerFooter:(Class)footerClass NS_SWIFT_NAME(register(footer:));
- (void)registerCell:(Class)cellClass NS_SWIFT_NAME(register(cell:));
- (__kindof UICollectionViewCell *)dequeueCell:(Class)cellClass forIndexPath:(NSIndexPath *)indexPath NS_SWIFT_NAME(dequeue(cell:for:));
- (__kindof UICollectionReusableView *)dequeueHeader:(Class)headerClass forIndexPath:(NSIndexPath *)indexPath NS_SWIFT_NAME(dequeue(header:for:));
- (__kindof UICollectionReusableView *)dequeueFooter:(Class)footerClass forIndexPath:(NSIndexPath *)indexPath NS_SWIFT_NAME(dequeue(footer:for:));
@end
//
// GMCollectionView
// Gengmei
//
// Created by Thierry on 1/9/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "GMCollectionView.h"
@implementation GMCollectionView
@end
@implementation UICollectionView (Reuse)
- (void)registerHeader:(Class)headerClass {
[self registerClass:headerClass forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass(headerClass)];
}
- (void)registerFooter:(Class)footerClass {
[self registerClass:footerClass forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass(footerClass)];
}
- (void)registerCell:(Class)cellClass {
[self registerClass:cellClass forCellWithReuseIdentifier:NSStringFromClass(cellClass)];
}
- (UICollectionViewCell *)dequeueCell:(Class)cellClass forIndexPath:(NSIndexPath *)indexPath {
return [self dequeueReusableCellWithReuseIdentifier:NSStringFromClass(cellClass) forIndexPath:indexPath];
}
- (UICollectionReusableView *)dequeueHeader:(Class)headerClass forIndexPath:(NSIndexPath *)indexPath {
return [self dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass(headerClass) forIndexPath:indexPath];
}
- (UICollectionReusableView *)dequeueFooter:(Class)footerClass forIndexPath:(NSIndexPath *)indexPath {
return [self dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass(footerClass) forIndexPath:indexPath];
}
@end
//
// GMSimpleCell.h
// Gengmei
// 简单的Collection Cell(图片+文字)
// Created by Thierry on 1/7/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "GMImageView.h"
#import "GMLabel.h"
#import "GMReuseIdentifier.h"
@interface GMCollectionViewCell : UICollectionViewCell <GMReuseIdentifier>
- (void)setup;
@end
@interface UICollectionReusableView (Reusable) <GMReuseIdentifier>
+ (NSString *)defaultReuseIdentifier;
@end
This diff is collapsed.
//
// GMControl.h
// Gengmei
//
// Created by wangyang on 9/14/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface GMControl : UIControl
/**
* @brief 不需要重写 init 方法,如果代码里调用了 init 方法,SDK 会自动调用 initWithFrame
*
*/
- (void)setup __attribute__((objc_requires_super));
@end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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