- #代码下载
#直播喵播MGMiaoBo下载 - #自动旋转–横竖屏控制(Swift3.0)
- ###appDelegate代码
######## appDelegate ######## appDelegate ######## appDelegate ######## ######## ########
// MARK: - 是否横屏
extension AppDelegate {
@objc(application:supportedInterfaceOrientationsForWindow:) func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if isLandscape {
return .all
}else{
return .portrait
}
}
}
- ###控制器代码
######## 控制器 ######## 控制器 ######## 控制器 ######## ######## ########
override func viewWillAppear(_ animated: Bool) {
KAppDelegate.isLandscape = true
// 强制横屏
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//将试图还原为竖屏
KAppDelegate.isLandscape = false
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
}
// 视图是否自动旋转
override var shouldAutorotate : Bool {
return true
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return [UIInterfaceOrientationMask.portrait, UIInterfaceOrientationMask.landscapeLeft]
}
/// size : 屏幕翻转后的新的尺寸;
/// coordinator : 屏幕翻转过程中的一些信息,比如翻转时间等;
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { [unowned self] (context) in
let orient = UIApplication.shared.statusBarOrientation
switch orient {
case .portrait:
MGLog(message: "Portrait")
self.tableView.frame = CGRect(x: 0, y: navHeight, width: self.view.mg_width, height: self.view.mg_height - navHeight)
case .landscapeLeft, .landscapeRight:
MGLog(message: "LandscapeLeft")
self.tableView.frame = CGRect(x: 0, y: navHeight/2, width: self.view.mg_width, height: MGScreenH - navHeight/2)
default:
MGLog(message: "Anything But Portrait")
break
}
}) { (context) in
MGLog(message:"rotation completed")
}
super.viewWillTransition(to: size, with: coordinator)
}
- #补充1: iOS10 APP内跳转至系统设置(如WIFI,Bluetooth…)
- ###
app-Prefs:root=
+跳转名称
- eg: 1、WIFi:app-Prefs:root=WIFI
- e.g: 2、蜂窝网络:app-Prefs:root=MOBILE_DATA_SETTINGS_ID
- eg:** 3、蓝牙:app-Prefs:root=Bluetooth **
- eg:** 4、About:app-Prefs:root=General&path=About **
- eg:跳转到自己的应用下面的设置 app-Prefs:root=Appid
- ###
无线局域网 App-Prefs:root=WIFI
蓝牙 App-Prefs:root=Bluetooth
蜂窝移动网络 App-Prefs:root=MOBILE_DATA_SETTINGS_ID
个人热点 App-Prefs:root=INTERNET_TETHERING
运营商 App-Prefs:root=Carrier
通知 App-Prefs:root=NOTIFICATIONS_ID
通用 App-Prefs:root=General
通用-关于本机 App-Prefs:root=General&path=About
通用-键盘 App-Prefs:root=General&path=Keyboard
通用-辅助功能 App-Prefs:root=General&path=ACCESSIBILITY
通用-语言与地区 App-Prefs:root=General&path=INTERNATIONAL
通用-还原 App-Prefs:root=Reset
墙纸 App-Prefs:root=Wallpaper
Siri App-Prefs:root=SIRI
隐私 App-Prefs:root=Privacy
Safari App-Prefs:root=SAFARI
音乐 App-Prefs:root=MUSIC
音乐-均衡器 App-Prefs:root=MUSIC&path=com.apple.Music:EQ
照片与相机 App-Prefs:root=Photos
FaceTime App-Prefs:root=FACETIME
guard let url = URL(string: "app-Prefs:root=Bluetooth") else {
return
}
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.openURL(url)
}
- #补充2:导航栏和TabBar的appearance
- ###听说这个坑了好多人,分享一下
var tabBarItemAppear = UITabBarItem.appearance()
if #available(iOS 9.0, *) {
tabBarItemAppear = UITabBarItem.appearance(whenContainedInInstancesOf: [MainTabBarVC.classForCoder() as! UIAppearanceContainer.Type])
}
- #补充3:RunTime 扩展封装方法 只需调用
- ###获取所有的方法和属性
// MARK: - RunTime
extension NSObject {
/**
* 获取所有的方法和属性
* 参数: 当前类
*/
func mg_GetMethodAndPropertiesFromClass(cls: AnyClass) {
debugPrint("方法========================================================")
var methodNum: UInt32 = 0
let methods = class_copyMethodList(cls, &methodNum)
for index in 0..<numericCast(methodNum) {
let met: Method = methods![index]!
debugPrint("m_name: \(method_getName(met)!)")
// debugPrint("m_returnType: \(String(utf8String: method_copyReturnType(met))!)")
// debugPrint("m_type: \(String(utf8String: method_getTypeEncoding(met))!)")
}
debugPrint("属性=========================================================")
var propNum: UInt32 = 0
let properties = class_copyPropertyList(cls, &propNum)
for index in 0..<Int(propNum) {
let prop: objc_property_t = properties![index]!
debugPrint("p_name: \(String(utf8String: property_getName(prop))!)")
// debugPrint("p_Attr: \(String(utf8String: property_getAttributes(prop))!)")
}
debugPrint("成员变量======================================================")
var ivarNum: UInt32 = 0
let ivars = class_copyIvarList(cls, &ivarNum)
for index in 0..<numericCast(ivarNum) {
let ivar: objc_property_t = ivars![index]!
let name = ivar_getName(ivar)
debugPrint("ivar_name: \(String(cString: name!))")
}
}
- ###黑魔法(交换方法)
/**
* 交换方法
* 参数: 当前类 ,原方法 要交换的方法
*/
class func mg_SwitchMethod(cls: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
let originalMethod = class_getInstanceMethod(cls, originalSelector)
let swizzledMethod = class_getInstanceMethod(cls, swizzledSelector)
let didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
}
- #补充4:获取系统所有的UIFont文字名称
func getSystemAllFontName() {
for familyName in UIFont.familyNames {
print("Family name: \(familyName)")
for fontName in UIFont.fontNames(forFamilyName: familyName) {
print("Font name: \(fontName)")
}
}
}
- #补充5:swift3.0以上 tableviewcell分割线显示不全解决方案
- ###方案1:UITableViewCell.separatorInset和UIView.layoutMargins
- 在viewDidLoad()添加一下代码
if tableView.responds(to:#selector(setter: UITableViewCell.separatorInset)) {
tableView.separatorInset = UIEdgeInsets.zero
}
if tableView.responds(to:#selector(setter: UIView.layoutMargins)) {
tableView.layoutMargins = UIEdgeInsets.zero
}
- tableview实现多以下代理
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = UIEdgeInsets.zero
}
if cell.responds(to:#selector(setter: UIView.layoutMargins)) {
cell.layoutMargins = UIEdgeInsets.zero
}
}
- ###方案2:draw(_ rect: CGRect),通过在底部绘制颜色
// MARK: - 系统方法
override func awakeFromNib() {
super.awakeFromNib()
// 记得要设置contentView.backgroundColor为clear,否则颜色会被它挡住了
self.contentView.backgroundColor = UIColor.clear
}
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(UIColor.white.cgColor)
context.fill(rect)
context.setFillColor(UIColor(white: 0.9, alpha: 1.0).cgColor)
context.fill(CGRect(x: 0, y: rect.size.height - 3, width:rect.size.width, height: 3))
}
- ###方案3:朋友教的,重写frame,高度-x,露出背景色
override var frame: CGRect {
didSet {
var tmpFrame : CGRect = super.frame
tmpFrame.size.height -= 3
super.frame = tmpFrame
}
}
- #总结:方法一和方法二需要去掉系统的分割线
tb.separatorStyle = UITableViewCellSeparatorStyle.none
效果更佳
###OC方法改变Tableview分割线的边距
// tableView设置:
//1.调整(iOS7以上)表格分隔线边距
if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
self.tableView.separatorInset = UIEdgeInsetsZero;
}
// 2.调整(iOS8以上)view边距(或者在cell中设置preservesSuperviewLayoutMargins,二者等效)
if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
self.tableView.layoutMargins = UIEdgeInsetsZero;
}
// cell 设置:
cell.preservesSuperviewLayoutMargins = NO;
[cell setLayoutMargins:UIEdgeInsetsZero];
- #补充6:Swift3.0纯代码添加约束 可供参考
-
禁用autoresizing(重要)
- 给需要设置约束的视图禁用autoresizing,禁用父视图autoresizing对子控件无效
- #方法1:代码添加autolayout约束
-
// 说明
/*
constraintWithItem:需要设置约束的view
attribute:需要设置约束的位置
relatedBy:约束的条件
toItem:约束依赖目标
attribute:依赖目标约束位置
multiplier:配置系数
constant:额外需要添加的长度
*/
/*
计算公式:redView.attribute = self.view.attribute * multiplier + constant;
其中:=符号取决于relatedBy:参数
typedef NS_ENUM(NSInteger, NSLayoutRelation) {
NSLayoutRelationLessThanOrEqual = -1, 小于等于
NSLayoutRelationEqual = 0, 等于
NSLayoutRelationGreaterThanOrEqual = 1, 大于等于
};
*/
tableView.translatesAutoresizingMaskIntoConstraints = false
let leftCon = NSLayoutConstraint(item: tableView, attribute: NSLayoutAttribute.left, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.left, multiplier: 1.0, constant: 0)
let rightCon = NSLayoutConstraint(item: tableView, attribute: .right, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: .right, multiplier: 1.0, constant: 0)
let topCon = NSLayoutConstraint(item: tableView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1.0, constant: 0)
let bottomCon = NSLayoutConstraint(item: tableView, attribute: .bottom, relatedBy: .equal
, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0)
self.view.addConstraints([leftCon,rightCon,topCon,bottomCon])
- #方法2:添加约束 VFL格式
// 说明
/VFL格式说明
功能 表达式
水平方向 H:
垂直方向 V:
Views [view]
SuperView |
关系 >=,==,<=
空间,间隙 -
优先级 @value
-----------------------------------------------------
/ VisualFormat: VFL语句
options: 对齐方式等,可以选择居中等
metrics: VFL语句中使用到的一些变量
views: VFL语句中使用到的一些控件*/
// 代码
tableView.translatesAutoresizingMaskIntoConstraints = false
var cons = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[tableView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["tableView": tableView])
cons += NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[tableView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["tableView": tableView])
view.addConstraints(cons)
- ####eg1:
"V:|-20-[redView(==50)]"
- 解释:redView(==50)是什么意思?V是代表垂直方向,垂直方向也就是高度,说明redView他的高度是50,同理如果是H开头呢,就是代表宽度 。-20-又是什么意思呢?距离父控件上边为20。
- ####eg2:
"V:[redView]-20-[blueView(==50)]"
- 解释:同理blueView他的高度是50,V是代表垂直方向,而且blueView距离redView垂直距离为20
- ####eg3:
let layout_frameView = ["frameView":frameView,"superView":self.view]
var frameView_constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:[frameView(300.)]-(<=1)-[superView]", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: layout_frameView)
frameView_constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[frameView(200.0)]-(<=1)-[superView]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: layout_frameView)
view.addConstraints(frameView_constraints)
- 解释:frameView宽度300和高度为200并且居中显示
- #补充7:Swift3.0控件存在屏幕底部,当键盘出现,控件出现在键盘上方
// MARK:- 系统方法
override func viewDidLoad() {
super.viewDidLoad()
// 1.添加并且布局
view.addSubview(toolBar)
toolBar.snp_makeConstraints { (make) -> Void in
make.bottom.left.right.equalTo(view)
make.height.equalTo(44)
}
// 2.监听键盘尺寸的改变的通知
MGNotificationCenter.addObserver(self, selector: #selector(self.keyboardFrameChange(noti:)), name: NSNotification.Name.UIKeyboardDidChangeFrame, object: nil)
}
/// 监听键盘尺寸的改变的方法
@objc fileprivate func keyboardFrameChange(noti: NSNotification) {
/*
userInfo = {
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.4";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 365}, {375, 302}}";
}
*/
let duration = (noti.userInfo![UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue
let offsetY = (noti.userInfo![UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.origin.y - MGScreenH
// toolBar: 是要挨着键盘的控件
toolBar.snp.updateConstraints { (make) -> Void in
make.bottom.equalTo(view.snp.bottom).offset(offsetY)
}
let CurveValue = noti.userInfo![UIKeyboardAnimationCurveUserInfoKey]! as! Int
UIView.animate(withDuration: duration!, delay: 0, options: UIViewAnimationOptions(rawValue: 0), animations: { () -> Void in
UIView.setAnimationCurve(UIViewAnimationCurve.init(rawValue: CurveValue)!)
self.view.layoutIfNeeded()
}, completion: nil)
}
- ###补充8:Swift3.0tableView右边标题按钮兰的研究,通过KVC和Runtime可以改变颜色,系统API默认有提供接口
sectionIndexColor
和sectionIndexBackgroundColor
。其他功能还没有研究到,要做这个其他功能自定义比较合适。(比如选中文字有颜色…等)
func test() {
let indexView = tableView.value(forKeyPath: "_index")
as? UIView
indexView?.setValue(UIColor.darkGray, forKey: "_indexColor")
indexView?.setValue(UIColor.randomColor(), forKey: "_indexTrackingBackgroundColor")
indexView?.setValue(UIColor.randomColor(), forKey: "_indexBackgroundColor")
let sel = NSSelectorFromString("endTrackingWithTouch:withEvent:")
let _ = indexView?.perform(sel)
self.mg_GetMethodAndPropertiesFromClass(cls: NSClassFromString("UITableViewIndex")!)
(NSClassFromString("UITableViewIndex") as! UIView.Type).init()
}
- #后续:自定义索引,详情请戳
- #补充9:Swift3.0 URL的encode和decode
extension String {
// MARK: - encoding 系统API
/*
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?@[\]^`
*/
/** 这个方法没有多大用,系统API已经提供了很多方法给我们如上
* URL 编码
* return 编码字符串
*/
func encodeEscapesURL(value: String) -> String {
let str:String = value
let originalString = str as CFString
let charactersToBeEscaped = "!*'();:@&=+$,/?%#[]" as CFString //":/?&=;+!@#$()',*" //转意符号
//let charactersToLeaveUnescaped = "[]." as CFStringRef //保留的符号
let result =
CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
originalString,
nil, //charactersToLeaveUnescaped,
charactersToBeEscaped,
CFStringConvertNSStringEncodingToEncoding(String.Encoding.utf8.rawValue)) as NSString
return result as String
}
/**
* URL 解码
* return 解码字符串
*/
func stringByURLDecode() -> String {
if self.removingPercentEncoding != nil {
return self.removingPercentEncoding!
} else {
let en: CFStringEncoding = CFStringConvertNSStringEncodingToEncoding(String.Encoding.utf8.rawValue)
var decoded: String = self.replacingOccurrences(of: "+", with: " ")
decoded = (CFURLCreateStringByReplacingPercentEscapesUsingEncoding(nil, (decoded as CFString),nil, en) as String)
return decoded
}
}
}
"http://baidu.com".encodeEscapesURL(value: "http://你好baidu.com")
let urlCode = "http://你好baidu.com".addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPasswordAllowed)
urlCode?.stringByURLDecode()
#补充10:In-Call Status Bar的监听及视图位置改变调整
- ###监听通知方法
//监听状态栏的改变
MGNotificationCenter.addObserver(self, selector: #selector(self.statusBarChange(noti:)), name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
- ###通知方法,执行一些相应的的操作(感觉主要对frame布局的UI影响较大)
@objc fileprivate func statusBarChange(noti: Notification) {
// 获取变化参数
let rectValue: NSValue? = (noti.userInfo?[UIApplicationStatusBarFrameUserInfoKey] as? NSValue)
let statusRect: CGRect? = rectValue?.cgRectValue
let statusFrame: CGRect = view.convert(statusRect!, from: MGKeyWindow)
let statusHeight: CGFloat = statusFrame.size.height - 20
// 需要修改的控件,举个:比如下面这个
if statusHeight == 0 {
settingBtn.frame = CGRect(x: 15, y: MGScreenH-64-44, width: 60, height: 44)
} else {
settingBtn.frame = CGRect(x: 15, y: MGScreenH-64-44-20, width: 60, height: 44)
}
}
- #补充11:Swift3.0 自定义UIButton替换导航返回按钮,仍然保持系统边缘返回手势
class BaseNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// 1.保留局部返回手势
self.interactivePopGestureRecognizer?.delegate = nil
self.popDelegate = self.interactivePopGestureRecognizer?.delegate
self.delegate = self
}
}
// MARK: - UINavigationControllerDelegate
extension BaseNavigationController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// 实现滑动返回功能
// 清空滑动返回手势的代理就能实现
if viewController == self.viewControllers[0] || viewController is ProdProgressItemListVC { // 可以控制那个控制器不需要局部返回手势
self.interactivePopGestureRecognizer!.delegate = self.popDelegate
} else {
self.interactivePopGestureRecognizer!.delegate = nil
}
}
}
- #补充12:解决Swift3.0 自定义全局返回手势和TableView左滑手势的冲突
class BaseNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// 1.全局拖拽手势
setUpGlobalPan()
}
}
// MARK: - 全局拖拽手势
extension BaseNavigationController: UIGestureRecognizerDelegate {
/// 全局拖拽手势
fileprivate func setUpGlobalPan() {
// 1.创建Pan手势
let target = interactivePopGestureRecognizer?.delegate
let globalPan = UIPanGestureRecognizer(target: target, action: Selector(("handleNavigationTransition:")))
globalPan.delegate = self
self.view.addGestureRecognizer(globalPan)
// 2.禁止系统的手势
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
/// 什么时候支持全屏手势
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if self.childViewControllers.count != 1 {
if (gestureRecognizer is UIPanGestureRecognizer) {
if (self.topViewController != nil) && (self.view.gestureRecognizers!.contains(gestureRecognizer)) {
let tPoint: CGPoint = ((gestureRecognizer as? UIPanGestureRecognizer)?.translation(in: gestureRecognizer.view))!
if tPoint.x >= 0 {
let y: CGFloat = fabs(tPoint.y)
let x: CGFloat = fabs(tPoint.x)
let af: CGFloat = 30.0 / 180.0 * .pi // tanf(Float(af))
let tf: CGFloat = tan(af)
return (y / x) <= tf
} else {
return false
}
}
}
return true
} else {
return false
}
}
}
- #补充13:判断是模拟器还是真机
- ###Swift3.x 运行在模拟器还是真机的判断
struct Platform {
static let isSimulator: Bool = {
var isSim = false
#if arch(i386) || arch(x86_64)
isSim = true
#endif
return isSim
}()
}
-
iOS Objective-C判断是模拟器还是真机
#if TARGET_IPHONE_SIMULATOR//模拟器
#elseif TARGET_OS_IPHONE//真机
#endif
- #补充14:运行在后台继续执行任务,比如定时器计时
//后台任务
var backgroundTask:UIBackgroundTaskIdentifier! = nil
func applicationDidEnterBackground(_ application: UIApplication) {
//如果已存在后台任务,先将其设为完成
if self.backgroundTask != nil {
application.endBackgroundTask(self.backgroundTask)
self.backgroundTask = UIBackgroundTaskInvalid
}
//如果要后台运行
//注册后台任务
self.backgroundTask = application.beginBackgroundTask(expirationHandler: {
() -> Void in
//如果没有调用endBackgroundTask,时间耗尽时应用程序将被终止
application.endBackgroundTask(self.backgroundTask)
self.backgroundTask = UIBackgroundTaskInvalid
})
}
- #补充15:钟摆效果
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.brown
setUpInit()
}
func setUpInit() {
self.view.layoutIfNeeded()
imageView = UIImageView(image: #imageLiteral(resourceName: "user_img_qd.png"))
view.addSubview(imageView)
imageView.frame.origin = CGPoint(x: 240, y: -5)
imageView.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
startAnimation()
}
func startAnimation() {
imageView.layer.removeAllAnimations()
// 旋转动画
let anim = CABasicAnimation(keyPath: "transform.rotation.z")
anim.fromValue = 7.5/4 * M_PI
anim.toValue = 8.5/4 * M_PI
// 悬浮
let pathAnimation = CAKeyframeAnimation(keyPath: "position")
pathAnimation.calculationMode = kCAAnimationPaced
pathAnimation.fillMode = kCAFillModeBoth
// pathAnimation.repeatCount = MAXFLOAT
// pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
let path = UIBezierPath(ovalIn: imageView.frame.insetBy(dx: 10, dy: imageView.frame.size.height - 2))
pathAnimation.path = path.cgPath
pathAnimation.duration = Double(arc4random_uniform(UInt32(8))) + 2.0
// 放大动画
let scaleX = CAKeyframeAnimation(keyPath: "transform.scale")
scaleX.values = [1.0, 1.1, 1.0];
scaleX.keyTimes = [0.0, 0.5, 1.0];
// 组动画
let group = CAAnimationGroup()
group.animations = [anim,pathAnimation,scaleX]
group.duration = 2.0
group.repeatCount = HUGE
group.autoreverses = true
imageView.layer.add(group, forKey: "group")
}
- #补充16:iOS判断过期或者想要延时x天后才执行某方法(Swift3.x和Objective-c)
- ###登录是否过期(连续5天未登录App,就重新登录)Objective-c(iOS判断过期)
/** 判断用户登录的tocken是否过期 */
+(BOOL)checkTockenIsExpire {
// 获取tocken日期
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSString *date = [userDefault valueForKeyPath:TockenIsExpireDateKey];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyyMMdd";
NSString *snow = [formatter stringFromDate:[NSDate date]];
if (date == nil) { // tocken设置为连续超过5天不打开App就重新登录
date = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow: 24 * 60 * 60 * 5]];
[userDefault setValue: date forKeyPath: TockenIsExpireDateKey];
}
if ([snow compare:date] == NSOrderedDescending) { // 当前日期大于之前保存的日期 // 降序
// 设置下一次过期的时间(5天有效)
date = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow: 24 * 60 * 60 * 5]];
[userDefault setValue: date forKeyPath: TockenIsExpireDateKey];
return YES; // 过期
}
// 刷新过期的时间(5天有效)
date = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow: 24 * 60 * 60 * 5]];
[userDefault setValue: date forKeyPath: TockenIsExpireDateKey];
return NO; // 没有过期
}
- ###某方法审核的时候不要去执行,审核通过后才去执行该方法,Swift(想要延时x天后才执行某方法)
// 判断今天是否执行某方法
let defaultst = UserDefaults.standard
var date = defaultst.object(forKey: kCurrentVersionDateKey) as? String
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let snow = formatter.string(from: Date())
if date == nil { // 第一次使用三天后才会有执行这个方法(跳过审核)
date = formatter.string(from: Date(timeIntervalSinceNow: 24 * 60 * 60 * 3))
}
if snow.compare(date!) == .orderedAscending {
return
}
// 设置这个是为了以后每天都会执行方法
defaultst.set(snow, forKey: kCurrentVersionDateKey)
// 要执行的方法
test()
- #github
| 项目 | 简介 |
| :-------------:| :-------------: |
| MGDS_Swif | 逗视视频直播 |
| MGMiaoBo | 喵播视频直播 |
| MGDYZB | 斗鱼视频直播 |
| MGDemo | n多小功能合集 |
| MGBaisi | 高度仿写百思 |
| MGSinaWeibo | 高度仿写Sina |
| MGLoveFreshBeen | 一款电商App |
| MGWeChat | 小部分实现微信功能 |
| MGTrasitionPractice | 自定义转场练习 |
| DBFMDemo | 豆瓣电台 |
| MGPlayer | 一个播放视频的Demo |
| MGCollectionView | 环形图片排布以及花瓣形排布 |
| MGPuBuLiuDemo | 瀑布流–商品展 |
| MGSlideViewDemo | 一个简单点的侧滑效果,仿QQ侧滑 |
| MyResume | 一个展示自己个人简历的Demo |
| GoodBookDemo | 好书 |
- #1、直播喵播MGMiaoBo下载
- #2、逗视:逗你玩的直播App,可下载试玩
-
#看下效果