Przeglądaj źródła

1.从Apex Drivers中抽取工具类。

Pen Li 7 lat temu
rodzic
commit
43102665aa
47 zmienionych plików z 3021 dodań i 0 usunięć
  1. 25 0
      common/BadgeButton/RABadgeButton.h
  2. 60 0
      common/BadgeButton/RABadgeButton.m
  3. 54 0
      common/BadgeButton/badge_button.xib
  4. 16 0
      common/BadgeNumber/RABadgeNumberView.h
  5. 233 0
      common/BadgeNumber/RABadgeNumberView.m
  6. 171 0
      common/Camera/Camera.storyboard
  7. 19 0
      common/Camera/RACameraViewController.h
  8. 374 0
      common/Camera/RACameraViewController.m
  9. 23 0
      common/Camera/RATakePhotoPreviewController.h
  10. 116 0
      common/Camera/RATakePhotoPreviewController.m
  11. 6 0
      common/Camera/camera.xcassets/Contents.json
  12. 23 0
      common/Camera/camera.xcassets/btn_photo_assign.imageset/Contents.json
  13. BIN
      common/Camera/camera.xcassets/btn_photo_assign.imageset/btn_photo_assign.png
  14. BIN
      common/Camera/camera.xcassets/btn_photo_assign.imageset/btn_photo_assign@2x.png
  15. BIN
      common/Camera/camera.xcassets/btn_photo_assign.imageset/btn_photo_assign@3x.png
  16. 23 0
      common/Camera/camera.xcassets/btn_photo_retake.imageset/Contents.json
  17. BIN
      common/Camera/camera.xcassets/btn_photo_retake.imageset/btn_photo_retake.png
  18. BIN
      common/Camera/camera.xcassets/btn_photo_retake.imageset/btn_photo_retake@2x.png
  19. BIN
      common/Camera/camera.xcassets/btn_photo_retake.imageset/btn_photo_retake@3x.png
  20. 23 0
      common/Camera/camera.xcassets/btn_return.imageset/Contents.json
  21. BIN
      common/Camera/camera.xcassets/btn_return.imageset/btn_return.png
  22. BIN
      common/Camera/camera.xcassets/btn_return.imageset/btn_return@2x.png
  23. BIN
      common/Camera/camera.xcassets/btn_return.imageset/btn_return@3x.png
  24. 124 0
      common/DatePicker/Base.lproj/date.storyboard
  25. 17 0
      common/DatePicker/RADatePickerViewController.h
  26. 108 0
      common/DatePicker/RADatePickerViewController.m
  27. 9 0
      common/DatePicker/en.lproj/date.strings
  28. 9 0
      common/DatePicker/zh-Hans.lproj/date.strings
  29. 15 0
      common/EmptyView/RAEmptyView.h
  30. 65 0
      common/EmptyView/RAEmptyView.m
  31. 18 0
      common/ExceptionHandler/RAExceptionHandler.h
  32. 227 0
      common/ExceptionHandler/RAExceptionHandler.m
  33. 23 0
      common/HUD/RAProgressHUD.h
  34. 128 0
      common/HUD/RAProgressHUD.m
  35. 24 0
      common/NSData/NSData+RAImageType.h
  36. 43 0
      common/NSData/NSData+RAImageType.m
  37. 14 0
      common/PresentationController/RAPresentationController.h
  38. 93 0
      common/PresentationController/RAPresentationController.m
  39. 173 0
      common/QRCode/QRCode.storyboard
  40. 17 0
      common/QRCode/RAQRCodeScannerViewController.h
  41. 373 0
      common/QRCode/RAQRCodeScannerViewController.m
  42. 23 0
      common/UIImage/UIImage+RedAnt.h
  43. 135 0
      common/UIImage/UIImage+RedAnt.m
  44. 15 0
      common/UIScrollVIew+Empty/RAEmptyDataView.h
  45. 107 0
      common/UIScrollVIew+Empty/RAEmptyDataView.m
  46. 19 0
      common/UIScrollVIew+Empty/UIScrollView+Empty.h
  47. 76 0
      common/UIScrollVIew+Empty/UIScrollView+Empty.m

+ 25 - 0
common/BadgeButton/RABadgeButton.h

@@ -0,0 +1,25 @@
+//
+//  RABadgeButton.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/11/2.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@interface RABadgeButton : UIView
+
++ (instancetype)badgeButton;
+
+- (void)setImage:(UIImage *)image forState:(UIControlState)state;
+
+- (void)setNumber:(NSUInteger)number;
+
+- (void)setNumberColor:(UIColor *)color;
+
+- (void)setNumberBackgroundColor:(UIColor *)color;
+
+@end
+

+ 60 - 0
common/BadgeButton/RABadgeButton.m

@@ -0,0 +1,60 @@
+//
+//  RABadgeButton.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/11/2.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RABadgeButton.h"
+
+@interface RABadgeButton ()
+
+@property (nonatomic,strong) IBOutlet UILabel *numberLabel;
+@property (nonatomic,strong) IBOutlet UIButton *itemButton;
+
+@end
+
+@implementation RABadgeButton
+
++ (instancetype)badgeButton {
+    
+    RABadgeButton *btn = [[[NSBundle mainBundle] loadNibNamed:@"badge_button" owner:nil options:nil] objectAtIndex:0];
+    
+    return btn;
+}
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    
+    self.numberLabel.text = nil;
+    self.numberLabel.backgroundColor = UIColorFromRGB(0x299D4D);
+    self.numberLabel.layer.cornerRadius = 7.5f;
+    self.numberLabel.layer.masksToBounds = YES;
+}
+
+- (void)setImage:(UIImage *)image forState:(UIControlState)state {
+    [self.itemButton setImage:image forState:state];
+}
+
+- (void)setTintColor:(UIColor *)tintColor {
+    [self.itemButton setTintColor:tintColor];
+}
+
+- (void)setNumber:(NSUInteger)number {
+    self.numberLabel.text = [NSString stringWithFormat:@"%lu",(unsigned long)number];
+}
+
+- (void)setNumberColor:(UIColor *)color {
+    self.numberLabel.textColor = color;
+}
+
+- (void)setNumberBackgroundColor:(UIColor *)color {
+    self.numberLabel.backgroundColor = color;
+}
+
+- (IBAction)itemButtonClick:(id)sender {
+    
+}
+
+@end

+ 54 - 0
common/BadgeButton/badge_button.xib

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="Fia-ja-bkx" customClass="RABadgeButton">
+            <rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <subviews>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7ix-Zh-qWW">
+                    <rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
+                    <connections>
+                        <action selector="itemButtonClick:" destination="Fia-ja-bkx" eventType="touchUpInside" id="iAk-sT-lsf"/>
+                    </connections>
+                </button>
+                <label opaque="NO" clearsContextBeforeDrawing="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="8" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="W69-8t-pXI">
+                    <rect key="frame" x="30" y="-5" width="15" height="15"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="15" id="DqP-Q8-WsU"/>
+                        <constraint firstAttribute="width" constant="15" id="mds-rh-nUy"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                    <color key="textColor" red="0.098965144643472502" green="0.1902306239211119" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="W69-8t-pXI" firstAttribute="leading" secondItem="Fia-ja-bkx" secondAttribute="trailing" constant="-10" id="4QH-0u-ae4"/>
+                <constraint firstItem="7ix-Zh-qWW" firstAttribute="top" secondItem="dxr-7c-xmI" secondAttribute="top" id="7jJ-fH-13q"/>
+                <constraint firstItem="7ix-Zh-qWW" firstAttribute="trailing" secondItem="dxr-7c-xmI" secondAttribute="trailing" id="GR3-t8-lS8"/>
+                <constraint firstItem="7ix-Zh-qWW" firstAttribute="leading" secondItem="dxr-7c-xmI" secondAttribute="leading" id="NQS-Qk-Ty2"/>
+                <constraint firstItem="W69-8t-pXI" firstAttribute="bottom" secondItem="Fia-ja-bkx" secondAttribute="top" constant="10" id="QSV-sN-eUQ"/>
+                <constraint firstItem="dxr-7c-xmI" firstAttribute="bottom" secondItem="7ix-Zh-qWW" secondAttribute="bottom" id="hKm-SR-gcy"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <viewLayoutGuide key="safeArea" id="dxr-7c-xmI"/>
+            <connections>
+                <outlet property="itemButton" destination="7ix-Zh-qWW" id="hp5-Ry-nfy"/>
+                <outlet property="numberLabel" destination="W69-8t-pXI" id="mne-LE-MHW"/>
+            </connections>
+            <point key="canvasLocation" x="-49.600000000000001" y="-22.488755622188908"/>
+        </view>
+    </objects>
+</document>

+ 16 - 0
common/BadgeNumber/RABadgeNumberView.h

@@ -0,0 +1,16 @@
+//
+//  RABadgeNumberView.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/9/3.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RABadgeNumberView : UIView
+
+@property (nonatomic,assign) NSUInteger badgeNumber;///< Default is 0 ,while the value is 0,then it be hidden.the max value is 99
+@property (nonatomic,strong) UIColor *foregroundColor;///<textColor
+
+@end

+ 233 - 0
common/BadgeNumber/RABadgeNumberView.m

@@ -0,0 +1,233 @@
+//
+//  RABadgeNumberView.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/9/3.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RABadgeNumberView.h"
+
+#define Max_Width 30.0f
+#define Min_Width 16.0f
+#define Text_Size 12.0f
+
+@interface RABadgeNumberView ()
+{
+    UIColor *_backgroundColor;
+    UIColor *_foregroundColor;
+}
+@property (nonatomic,strong) CAShapeLayer *originLayer;
+@property (nonatomic,strong) CAShapeLayer *borderLayer;
+@property (nonatomic,strong) CATextLayer *valueLayer;
+
+@end
+
+
+@implementation RABadgeNumberView
+
+#pragma mark - Utils
+
++ (CGSize)sizeOfString:(NSString *)string font:(UIFont *)font{
+    
+    if (string == nil) {
+        return CGSizeZero;
+    }
+    
+    NSDictionary *attribute = @{NSFontAttributeName: font};
+    
+    CGSize resSize = [string boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT)
+                                          options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
+                                       attributes:attribute
+                                          context:nil].size;
+    
+    return resSize;
+}
+
+#pragma mark - Public
+
+- (void)setBadgeNumber:(NSUInteger)badgeNumber {
+    _badgeNumber = badgeNumber;
+    
+    self.hidden = _badgeNumber == 0;
+    
+    NSString *text = nil;
+    if (_badgeNumber > 99) {
+        text = @"99+";
+    } else {
+        text = [NSString stringWithFormat:@"%lu",badgeNumber];
+    }
+    
+    [self.valueLayer setString:text];
+    
+    [self updateUI];
+}
+
+- (void)setForegroundColor:(UIColor *)foregroundColor {
+    _foregroundColor = foregroundColor;
+    self.valueLayer.foregroundColor = _foregroundColor.CGColor;
+}
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor {
+    _backgroundColor = backgroundColor;
+    [self updateColor];
+}
+
+#pragma mark - Private
+
+- (UIColor *)foregroundColor {
+    if (_foregroundColor == nil) {
+        _foregroundColor = [UIColor whiteColor];
+    }
+    return _foregroundColor;
+}
+
+- (UIColor *)backgroundColor {
+    if (_backgroundColor == nil) {
+        _backgroundColor = [UIColor redColor];
+    }
+    return _backgroundColor;
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+    
+    [super willMoveToSuperview:newSuperview];
+    
+    [self.layer addSublayer:self.originLayer];
+    [self.layer addSublayer:self.borderLayer];
+    [self.layer addSublayer:self.valueLayer];
+    
+    [self updateUI];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    [self updateUI];
+}
+
+#pragma mark Frame
+
+- (void)setWidth:(CGFloat)width {
+    
+    NSLayoutConstraint *widthConstraint = nil;
+    for (NSLayoutConstraint *constraint in self.constraints) {
+        if (constraint.firstAttribute == NSLayoutAttributeWidth) {
+            widthConstraint = constraint;
+        }
+    }
+    
+    if (widthConstraint) {
+        widthConstraint.constant = width;
+    } else {
+        
+        CGRect bounds = self.bounds;
+        bounds.size.width = width;
+        self.bounds = bounds;
+    }
+}
+
+- (void)setHeight:(CGFloat)height {
+    
+    NSLayoutConstraint *heightConstraint = nil;
+    for (NSLayoutConstraint *constraint in self.constraints) {
+        if (constraint.firstAttribute == NSLayoutAttributeHeight) {
+            heightConstraint = constraint;
+        }
+    }
+    
+    if (heightConstraint) {
+        heightConstraint.constant = height;        
+    } else {
+        
+        CGRect bounds = self.bounds;
+        bounds.size.height = height;
+        self.bounds = bounds;
+    }
+}
+
+- (void)updateUI {
+    
+    CGSize size = [self.class sizeOfString:self.valueLayer.string font:[UIFont systemFontOfSize:Text_Size]];
+    CGSize textSize = size;
+    if (size.width < Min_Width) {
+        size.width = Min_Width;
+    }
+    
+    if (size.height < Min_Width) {
+        size.height = Min_Width;
+    }
+    
+    if (size.height > size.width) {
+        size.width = size.height;
+    }
+    
+    size.width += 5.0f;
+    size.height += 5.0f;
+    
+    CGFloat r = size.height * 0.5;
+    
+    // 更新自身Size
+    if (self.badgeNumber < 10) {
+        [self setWidth:size.width];
+    } else {
+        [self setWidth:size.width + 5];
+    }
+    [self setHeight:size.height];
+    
+    // drag layer
+    self.borderLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:r].CGPath;
+    
+    // 更新TextLayer Frame
+    CGFloat x = (CGRectGetWidth(self.bounds) - textSize.width) * 0.5,y = (CGRectGetHeight(self.bounds) - textSize.height) * 0.5;
+    self.valueLayer.frame = CGRectMake(x, y, textSize.width, textSize.height);
+}
+
+- (void)updateColor {
+    self.originLayer.fillColor = self.backgroundColor.CGColor;
+    self.originLayer.strokeColor = self.backgroundColor.CGColor;
+    self.borderLayer.fillColor = self.backgroundColor.CGColor;
+    self.borderLayer.strokeColor = self.backgroundColor.CGColor;
+}
+
+#pragma mark Layer
+
+- (CAShapeLayer *)originLayer {
+    if (!_originLayer) {
+        _originLayer = [CAShapeLayer layer];
+        _originLayer.fillColor = self.backgroundColor.CGColor;
+        _originLayer.strokeColor = self.backgroundColor.CGColor;
+        _originLayer.lineWidth = 0.1f;
+    }
+    return _originLayer;
+}
+
+- (CAShapeLayer *)borderLayer {
+    if (!_borderLayer) {
+        _borderLayer = [CAShapeLayer layer];
+        _borderLayer.fillColor = self.backgroundColor.CGColor;
+        _borderLayer.strokeColor = self.backgroundColor.CGColor;
+        _borderLayer.lineWidth = 0.1f;
+    }
+    return _borderLayer;
+}
+
+- (CATextLayer *)valueLayer {
+    if (!_valueLayer) {
+        _valueLayer = [CATextLayer layer];
+        _valueLayer.foregroundColor = self.foregroundColor.CGColor;
+        _valueLayer.contentsScale = [UIScreen mainScreen].scale;
+        _valueLayer.alignmentMode = kCAAlignmentCenter;
+        _valueLayer.contentsGravity = kCAGravityCenter;
+        
+        UIFont *font = [UIFont systemFontOfSize:Text_Size];
+        CGFontRef fontRef = CGFontCreateWithFontName((__bridge_retained CFStringRef)font.fontName);
+        _valueLayer.font = fontRef;
+        _valueLayer.fontSize = font.pointSize;
+        CGFontRelease(fontRef);
+    }
+    return _valueLayer;
+}
+
+
+@end

+ 171 - 0
common/Camera/Camera.storyboard

@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Camera View Controller-->
+        <scene sceneID="4sG-sz-uXW">
+            <objects>
+                <viewController storyboardIdentifier="RACameraViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="u3G-8E-Sj8" customClass="RACameraViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="ZFi-1H-xB4">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aIR-II-sqh">
+                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            </view>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2cM-nE-ueF">
+                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
+                                <subviews>
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Zmb-bI-WjK">
+                                        <rect key="frame" x="157.5" y="527" width="60" height="60"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" constant="60" id="Jgr-Dk-QIx"/>
+                                            <constraint firstAttribute="width" secondItem="Zmb-bI-WjK" secondAttribute="height" multiplier="1:1" id="MQN-fF-lQY"/>
+                                        </constraints>
+                                        <connections>
+                                            <action selector="takePictureBtnClick:" destination="u3G-8E-Sj8" eventType="touchUpInside" id="1LX-1e-klr"/>
+                                        </connections>
+                                    </button>
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mbh-f5-Pjk">
+                                        <rect key="frame" x="10" y="20" width="30" height="30"/>
+                                        <state key="normal" image="btn_return"/>
+                                        <connections>
+                                            <action selector="returnButtonClick:" destination="u3G-8E-Sj8" eventType="touchUpInside" id="HSh-Rt-lSF"/>
+                                        </connections>
+                                    </button>
+                                </subviews>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <constraints>
+                                    <constraint firstAttribute="bottom" secondItem="Zmb-bI-WjK" secondAttribute="bottom" constant="60" id="f8Y-IT-5Vo"/>
+                                    <constraint firstItem="Zmb-bI-WjK" firstAttribute="centerX" secondItem="2cM-nE-ueF" secondAttribute="centerX" id="wR7-zz-eVK"/>
+                                </constraints>
+                            </view>
+                        </subviews>
+                        <color key="backgroundColor" red="0.76354031735751293" green="0.76354031735751293" blue="0.76354031735751293" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="fLT-zm-dh6" firstAttribute="bottom" secondItem="2cM-nE-ueF" secondAttribute="bottom" id="9Y0-7J-sXY"/>
+                            <constraint firstItem="fLT-zm-dh6" firstAttribute="trailing" secondItem="aIR-II-sqh" secondAttribute="trailing" id="CZh-X5-9Zr"/>
+                            <constraint firstItem="2cM-nE-ueF" firstAttribute="leading" secondItem="fLT-zm-dh6" secondAttribute="leading" id="Igd-YW-xgj"/>
+                            <constraint firstItem="fLT-zm-dh6" firstAttribute="bottom" secondItem="aIR-II-sqh" secondAttribute="bottom" id="bSC-7H-ATA"/>
+                            <constraint firstItem="mbh-f5-Pjk" firstAttribute="leading" secondItem="fLT-zm-dh6" secondAttribute="leading" constant="10" id="d8B-Ug-GS1"/>
+                            <constraint firstItem="2cM-nE-ueF" firstAttribute="top" secondItem="fLT-zm-dh6" secondAttribute="top" id="fox-Pf-jXw"/>
+                            <constraint firstItem="aIR-II-sqh" firstAttribute="top" secondItem="fLT-zm-dh6" secondAttribute="top" id="iNS-Ag-rc8"/>
+                            <constraint firstItem="fLT-zm-dh6" firstAttribute="trailing" secondItem="2cM-nE-ueF" secondAttribute="trailing" id="plK-cA-ZV1"/>
+                            <constraint firstItem="mbh-f5-Pjk" firstAttribute="top" secondItem="fLT-zm-dh6" secondAttribute="top" constant="20" id="vud-1w-6K9"/>
+                            <constraint firstItem="aIR-II-sqh" firstAttribute="leading" secondItem="fLT-zm-dh6" secondAttribute="leading" id="yWd-lg-8xz"/>
+                        </constraints>
+                        <viewLayoutGuide key="safeArea" id="fLT-zm-dh6"/>
+                    </view>
+                    <connections>
+                        <outlet property="controlContanier" destination="2cM-nE-ueF" id="8g4-KY-DMK"/>
+                        <outlet property="previewContainer" destination="aIR-II-sqh" id="Xhl-yB-wfI"/>
+                        <outlet property="takePhotoBtn" destination="Zmb-bI-WjK" id="4ND-ng-dvs"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="65S-tr-YKy" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-23" y="161"/>
+        </scene>
+        <!--Take Photo Preview Controller-->
+        <scene sceneID="Y0T-nH-52O">
+            <objects>
+                <viewController storyboardIdentifier="RATakePhotoPreviewController" automaticallyAdjustsScrollViewInsets="NO" useStoryboardIdentifierAsRestorationIdentifier="YES" id="hfm-f2-DNT" customClass="RATakePhotoPreviewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="JtE-cJ-OW0"/>
+                        <viewControllerLayoutGuide type="bottom" id="1aO-Vd-AQh"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="khP-jm-wId">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleAspectFit" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" maximumZoomScale="4" translatesAutoresizingMaskIntoConstraints="NO" id="w4v-z1-b7B">
+                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
+                                <subviews>
+                                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Z0q-fB-hKK">
+                                        <rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
+                                    </imageView>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstAttribute="trailing" secondItem="Z0q-fB-hKK" secondAttribute="trailing" id="1DV-S9-kNZ"/>
+                                    <constraint firstItem="Z0q-fB-hKK" firstAttribute="leading" secondItem="w4v-z1-b7B" secondAttribute="leading" id="3vl-RG-C7S"/>
+                                    <constraint firstItem="Z0q-fB-hKK" firstAttribute="top" secondItem="w4v-z1-b7B" secondAttribute="top" id="U6T-ty-Pya"/>
+                                    <constraint firstItem="Z0q-fB-hKK" firstAttribute="height" secondItem="w4v-z1-b7B" secondAttribute="height" id="Vy1-Qy-KOG"/>
+                                    <constraint firstAttribute="bottom" secondItem="Z0q-fB-hKK" secondAttribute="bottom" id="iA1-6c-bee"/>
+                                    <constraint firstItem="Z0q-fB-hKK" firstAttribute="width" secondItem="w4v-z1-b7B" secondAttribute="width" id="mYI-88-f5w"/>
+                                </constraints>
+                                <connections>
+                                    <outlet property="delegate" destination="hfm-f2-DNT" id="0Kg-98-liP"/>
+                                </connections>
+                            </scrollView>
+                            <view hidden="YES" alpha="0.44999998807907099" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WfP-Fk-mo9">
+                                <rect key="frame" x="0.0" y="605" width="375" height="62"/>
+                                <color key="backgroundColor" white="0.33333333329999998" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="62" id="cnn-ba-VJB"/>
+                                </constraints>
+                            </view>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XlI-8n-qRu">
+                                <rect key="frame" x="50" y="532" width="60" height="60"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                <state key="normal" image="btn_photo_retake"/>
+                                <connections>
+                                    <action selector="retakeBtnClick:" destination="hfm-f2-DNT" eventType="touchUpInside" id="7eA-Kj-Zq8"/>
+                                </connections>
+                            </button>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZBU-jX-GTo">
+                                <rect key="frame" x="265" y="532" width="60" height="60"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                <state key="normal" image="btn_photo_assign"/>
+                                <connections>
+                                    <action selector="usePhotoClick:" destination="hfm-f2-DNT" eventType="touchUpInside" id="3JY-Vk-Gu3"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstItem="1aO-Vd-AQh" firstAttribute="top" secondItem="WfP-Fk-mo9" secondAttribute="bottom" id="18i-Al-Ypd"/>
+                            <constraint firstItem="BrA-yF-F9H" firstAttribute="trailing" secondItem="ZBU-jX-GTo" secondAttribute="trailing" constant="50" id="1MK-Io-C0h"/>
+                            <constraint firstItem="1aO-Vd-AQh" firstAttribute="top" secondItem="XlI-8n-qRu" secondAttribute="bottom" constant="75" id="I6O-uF-hVL"/>
+                            <constraint firstItem="XlI-8n-qRu" firstAttribute="leading" secondItem="BrA-yF-F9H" secondAttribute="leading" constant="50" id="M5Y-yj-q9i"/>
+                            <constraint firstItem="WfP-Fk-mo9" firstAttribute="leading" secondItem="khP-jm-wId" secondAttribute="leading" id="MSv-jh-Kws"/>
+                            <constraint firstItem="1aO-Vd-AQh" firstAttribute="top" secondItem="w4v-z1-b7B" secondAttribute="bottom" id="ZV0-ao-dGH"/>
+                            <constraint firstItem="w4v-z1-b7B" firstAttribute="leading" secondItem="khP-jm-wId" secondAttribute="leading" id="eWS-j0-eyB"/>
+                            <constraint firstAttribute="trailing" secondItem="w4v-z1-b7B" secondAttribute="trailing" id="qYR-pg-xfY"/>
+                            <constraint firstItem="ZBU-jX-GTo" firstAttribute="centerY" secondItem="XlI-8n-qRu" secondAttribute="centerY" id="uMc-9T-hZd"/>
+                            <constraint firstItem="w4v-z1-b7B" firstAttribute="top" secondItem="JtE-cJ-OW0" secondAttribute="bottom" id="vBb-3e-ld9"/>
+                            <constraint firstAttribute="trailing" secondItem="WfP-Fk-mo9" secondAttribute="trailing" id="wKB-RK-2W0"/>
+                        </constraints>
+                        <viewLayoutGuide key="safeArea" id="BrA-yF-F9H"/>
+                    </view>
+                    <nil key="simulatedStatusBarMetrics"/>
+                    <nil key="simulatedTopBarMetrics"/>
+                    <nil key="simulatedBottomBarMetrics"/>
+                    <connections>
+                        <outlet property="previewPhotoView" destination="Z0q-fB-hKK" id="CuC-M7-vFP"/>
+                        <outlet property="previewScroll" destination="w4v-z1-b7B" id="mvQ-nK-wZW"/>
+                        <outlet property="retakeBtn" destination="XlI-8n-qRu" id="Og5-TY-dJU"/>
+                        <outlet property="toolBarView" destination="WfP-Fk-mo9" id="sdI-yW-TCC"/>
+                        <outlet property="usePhotoBtn" destination="ZBU-jX-GTo" id="c0Y-4b-GQ9"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ex0-03-0bJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2557.5999999999999" y="243.32833583208398"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="btn_photo_assign" width="60" height="60"/>
+        <image name="btn_photo_retake" width="60" height="60"/>
+        <image name="btn_return" width="30" height="30"/>
+    </resources>
+</document>

+ 19 - 0
common/Camera/RACameraViewController.h

@@ -0,0 +1,19 @@
+//
+//  RACameraViewController.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/6/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RACameraViewController : UIViewController
+
+@property (nonatomic,copy) void (^completion)(UIImage *image);
+
+@property (nonatomic,weak) UIViewController *fromVC;
+
++ (instancetype)viewControllerFromStoryboard;
+
+@end

+ 374 - 0
common/Camera/RACameraViewController.m

@@ -0,0 +1,374 @@
+//
+//  RACameraViewController.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/6/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RACameraViewController.h"
+#import <AVFoundation/AVFoundation.h>
+#import "RATakePhotoPreviewController.h"
+
+@interface RACameraViewController ()
+
+@property (nonatomic,strong) IBOutlet UIView *previewContainer;
+@property (nonatomic,strong) IBOutlet UIView *controlContanier;
+@property (strong, nonatomic) IBOutlet UIButton *takePhotoBtn;
+
+@property (nonatomic,assign) BOOL barHidden;
+
+#pragma mark - Camera
+
+@property (nonatomic,strong) AVCaptureDevice *captureDevice;
+@property (nonatomic,strong) AVCaptureSession *captureSession;
+@property (nonatomic,strong) AVCaptureDeviceInput *captureInput;
+@property (nonatomic,strong) AVCaptureStillImageOutput *captureOutput;
+@property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewLayer;
+
+@property (nonatomic,assign) BOOL cameraInitial;
+
+@end
+
+@implementation RACameraViewController
+
++ (NSString *)storyboardID {
+    return NSStringFromClass([self class]);
+}
+
++ (instancetype)viewControllerFromStoryboard {
+    RACameraViewController *cameraVC = [[UIStoryboard storyboardWithName:@"Camera" bundle:nil] instantiateViewControllerWithIdentifier:[self storyboardID]];
+    return cameraVC;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    
+    UIImage *normal_img = [self.class imageWithColor:[UIColor redColor] Size:CGSizeMake(60, 60)];
+    UIImage *highlight_img = [self.class imageWithColor:[UIColor whiteColor] Size:CGSizeMake(60, 60)];
+    
+    [self.takePhotoBtn setImage:normal_img forState:UIControlStateNormal];
+    [self.takePhotoBtn setImage:highlight_img forState:UIControlStateHighlighted];
+    
+//    [self initCapture];
+//    [self initTakePicture];
+    
+    if ([self camerAuthorization]) {
+        
+        [self initCapture];
+        [self initTakePicture];
+        
+    } else {
+        // fix:第一次打开相机的时候授权成功后,未初始化相机
+        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
+            
+            dispatch_async(dispatch_get_main_queue(), ^{
+                if (granted) {
+                    [self initCapture];
+                    [self initTakePicture];
+                    
+                    CGRect frame = self.previewContainer.bounds;
+                    [self resetPreview:CGRectOffset(frame, CGRectGetWidth(frame), 0)];
+                    
+                    [UIView animateWithDuration:0.3 animations:^{
+                        self.previewLayer.frame = frame;
+                    }];
+                    
+                    if (self.cameraInitial && !self.captureSession.isRunning) {
+                        [self.captureSession startRunning];
+                    }
+                    
+                } else {
+                    
+                    NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
+                    NSString *appName = [infoDict objectForKey:@"CFBundleDisplayName"];
+                    __weak typeof(self) weakSelf = self;
+                    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert];
+                    UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+                        [weakSelf dismissViewControllerAnimated:YES completion:nil];
+                    }];
+                    [alert addAction:action];
+                    [self presentViewController:alert animated:YES completion:nil];
+                    
+                }
+            });
+            
+        }];
+    }
+    /**
+     * 管理导航条
+     * 在viewDidload的时候隐藏导航条
+     * 恢复导航条的显示/隐藏有两个地方:1.退出的时候;2.确认使用照片的时候
+     */
+    if (self.navigationController) {
+        BOOL navBarHidden = self.navigationController.navigationBar.hidden;
+        self.barHidden = navBarHidden;
+        if (!navBarHidden) {
+            [self.navigationController setNavigationBarHidden:YES animated:YES];
+        }
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    if (self.cameraInitial && !self.captureSession.isRunning) {
+        [self.captureSession startRunning];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    if ([self.captureSession isRunning]) {
+        [self.captureSession stopRunning];
+    }
+}
+
+- (BOOL)prefersStatusBarHidden {
+    return YES;
+}
+
+- (void)viewDidLayoutSubviews {
+    [super viewDidLayoutSubviews];
+    
+    if ([self camerAuthorization] && self.cameraInitial) {
+        
+        [self resetPreview:self.previewContainer.bounds];
+    }
+}
+
+#pragma mark - Capture
+
+- (void)resetPreview:(CGRect)frame {
+    
+    self.previewLayer.frame = frame;
+    
+    if (self.previewLayer.connection.isVideoOrientationSupported) {
+        self.previewLayer.connection.videoOrientation = [self captureVideoOrientation];
+    }
+    
+    if ([self.captureOutput connectionWithMediaType:AVMediaTypeVideo].isVideoOrientationSupported) {
+        [self.captureOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation = [self captureVideoOrientation];
+    }
+    
+}
+
+- (BOOL)camerAuthorization {
+    
+    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
+    if (status == AVAuthorizationStatusRestricted || status == AVAuthorizationStatusDenied) {
+        return NO;
+    }
+    return YES;
+}
+
+
+- (void)initCapture {
+    
+    self.cameraInitial = NO;
+    
+    if (![self camerAuthorization]) {
+        
+        NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
+        NSString *appName = [infoDict objectForKey:@"CFBundleDisplayName"];
+        __weak typeof(self) weakSelf = self;
+        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert];
+        UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+            [weakSelf dismissViewControllerAnimated:YES completion:nil];
+        }];
+        [alert addAction:action];
+        [self presentViewController:alert animated:YES completion:nil];
+        
+        return;
+    }
+    
+    self.captureSession = [[AVCaptureSession alloc] init];
+    
+    self.captureDevice = [self videoDevicePosition:AVCaptureDevicePositionBack];
+    if (!self.captureDevice) {
+        NSLog(@"there is no capture device while init camera");
+        return;
+    }
+    
+    NSError *error;
+    self.captureInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.captureDevice error:&error];
+    
+    if (error) {
+        NSLog(@"init camera error: %@",error);
+        return;
+    }
+    
+    [self.captureSession beginConfiguration];
+    
+    if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {
+        _captureSession.sessionPreset = AVCaptureSessionPresetHigh;
+    }
+    
+    if ([self.captureDevice isFlashAvailable] && [_captureDevice isFlashModeSupported:AVCaptureFlashModeAuto]) {
+        NSError *configErr;
+        [self.captureDevice lockForConfiguration:&configErr];
+        [self.captureDevice setFlashMode:AVCaptureFlashModeAuto];
+        [self.captureDevice unlockForConfiguration];
+    }
+    
+    if ([self.captureSession canAddInput:self.captureInput]) {
+        
+        
+        [self.captureSession addInput:self.captureInput];
+        
+//        if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080]) {
+//            self.captureSession.sessionPreset = AVCaptureSessionPreset1920x1080;
+//        } else {
+//            if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {
+//                self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
+//            }
+//        }
+        
+    } else {
+        NSLog(@"init camera can't add input");
+        return;
+    }
+    
+    [self.captureSession commitConfiguration];
+    
+    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
+    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
+    [self.previewContainer.layer addSublayer:self.previewLayer];
+    
+    self.cameraInitial = YES;
+}
+
+- (void)initTakePicture {
+    if (!self.cameraInitial) {
+        return;
+    }
+    self.captureOutput = [[AVCaptureStillImageOutput alloc] init];
+    
+    NSDictionary *setting = @{AVVideoCodecKey:AVVideoCodecJPEG};
+    [self.captureOutput setOutputSettings:setting];
+    
+    if ([self.captureSession canAddOutput:self.captureOutput]) {
+        [self.captureSession addOutput:self.captureOutput];
+    }
+    
+    AVCaptureConnection *connection = [self.captureOutput connectionWithMediaType:AVMediaTypeVideo];
+    if (connection.isVideoOrientationSupported) { // addOutput之后判断,否则一直都是false
+        connection.videoOrientation = [self captureVideoOrientation];
+    }
+    
+}
+
+- (AVCaptureDevice *) videoDevicePosition:(AVCaptureDevicePosition)position {
+
+    NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
+    for (AVCaptureDevice *device in videoDevices) {
+        if ([device position] == position) {
+            return device;
+        }
+    }
+    
+    return nil;
+}
+
+- (AVCaptureVideoOrientation)captureVideoOrientation {
+    AVCaptureVideoOrientation result;
+    
+    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
+    switch (deviceOrientation) {
+        case UIDeviceOrientationPortrait:
+        case UIDeviceOrientationFaceUp:
+        case UIDeviceOrientationFaceDown:
+            result = AVCaptureVideoOrientationPortrait;
+            break;
+        case UIDeviceOrientationPortraitUpsideDown:
+            //如果这里设置成AVCaptureVideoOrientationPortraitUpsideDown,则视频方向和拍摄时的方向是相反的。
+            result = AVCaptureVideoOrientationPortrait;
+            break;
+        case UIDeviceOrientationLandscapeLeft:
+            result = AVCaptureVideoOrientationLandscapeRight;
+            break;
+        case UIDeviceOrientationLandscapeRight:
+            result = AVCaptureVideoOrientationLandscapeLeft;
+            break;
+        default:
+            result = AVCaptureVideoOrientationPortrait;
+            break;
+    }
+    
+    return result;
+}
+
+#pragma mark - Action
+
+- (IBAction)takePictureBtnClick:(UIButton *)sender {
+    
+    if (!self.cameraInitial) {
+        return;
+    }
+    
+    AVCaptureConnection *connection = [self.captureOutput connectionWithMediaType:AVMediaTypeVideo];
+    __weak typeof(self) weakSelf = self;
+    [self.captureOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error) {
+        
+        if (imageDataSampleBuffer) {
+            NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
+            UIImage *image=[UIImage imageWithData:imageData];
+            
+            RATakePhotoPreviewController *preVC = [RATakePhotoPreviewController viewControllerFromStoryboard];
+            preVC.photoHandler = ^(UIImage *img){
+                if (weakSelf) {
+                    __strong typeof(weakSelf) strongSelf = weakSelf;
+                    if (strongSelf.completion) {
+                        strongSelf.completion(img);
+                    }
+                }
+            };
+            preVC.preImage = image;
+            preVC.popTo = weakSelf.fromVC;
+            preVC.barHidden = weakSelf.barHidden;
+            [weakSelf.navigationController pushViewController:preVC animated:YES];
+            
+        } else {
+            NSLog(@"take picture failed: %@",error);
+        }
+        
+    }];
+}
+
+- (IBAction)returnButtonClick:(UIButton *)sender {
+    if (self.navigationController) {
+        [self.navigationController popViewControllerAnimated:YES];
+    } else {
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+    
+    if (self.navigationController) {
+        [self.navigationController setNavigationBarHidden:self.barHidden animated:YES];
+    }
+}
+
+#pragma mark - Utils
+
++ (UIImage *)imageWithColor:(UIColor *)color Size:(CGSize)size {
+    
+    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
+    CGContextRef ctx = UIGraphicsGetCurrentContext();
+    CGContextAddEllipseInRect(ctx, CGRectMake(5, 5, size.width - 10, size.height - 10));
+    CGContextSetFillColorWithColor(ctx, color.CGColor);
+    CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
+    CGContextSetLineWidth(ctx, 3.0f);
+    CGContextDrawPath(ctx, kCGPathFillStroke);
+    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    
+    return img;
+}
+
+@end

+ 23 - 0
common/Camera/RATakePhotoPreviewController.h

@@ -0,0 +1,23 @@
+//
+//  TakePhotoPreviewController.h
+//  RA Image
+//
+//  Created by Jack on 2017/5/15.
+//  Copyright © 2017年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RATakePhotoPreviewController : UIViewController
+
+@property (nonatomic,strong) UIImage *preImage;
+
+@property (nonatomic,copy) void(^photoHandler) (UIImage *);
+
+@property (nonatomic,weak) UIViewController *popTo;
+
+@property (nonatomic,assign) BOOL barHidden;
+
++ (instancetype)viewControllerFromStoryboard;
+
+@end

+ 116 - 0
common/Camera/RATakePhotoPreviewController.m

@@ -0,0 +1,116 @@
+//
+//  TakePhotoPreviewController.m
+//  RA Image
+//
+//  Created by Jack on 2017/5/15.
+//  Copyright © 2017年 USAI. All rights reserved.
+//
+
+#import "RATakePhotoPreviewController.h"
+#import "const.h"
+
+@interface RATakePhotoPreviewController ()<UIScrollViewDelegate>
+
+@property (strong, nonatomic) IBOutlet UIScrollView *previewScroll;
+@property (strong, nonatomic) IBOutlet UIImageView *previewPhotoView;
+@property (strong, nonatomic) IBOutlet UIButton *retakeBtn;
+@property (strong, nonatomic) IBOutlet UIButton *usePhotoBtn;
+@property (strong, nonatomic) IBOutlet UIView *toolBarView;
+
+@end
+
+@implementation RATakePhotoPreviewController
+
++ (NSString *)storyboardID {
+    return NSStringFromClass([self class]);
+}
+
++ (instancetype)viewControllerFromStoryboard {
+    RATakePhotoPreviewController *previewVC = [[UIStoryboard storyboardWithName:@"Camera" bundle:nil] instantiateViewControllerWithIdentifier:[self storyboardID]];
+    return previewVC;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    
+    if (@available(iOS 11.0, *)) {
+        self.previewScroll.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+    } else {
+        self.automaticallyAdjustsScrollViewInsets = NO;
+    }
+    
+    [self.view insertSubview:[UIView new] atIndex:0];
+    self.previewPhotoView.image = self.preImage;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+//    if (self.navigationController) {
+//        BOOL navBarHidden = self.navigationController.navigationBar.hidden;
+//        self.barHidden = navBarHidden;
+//        if (!navBarHidden) {
+//            [self.navigationController setNavigationBarHidden:YES animated:animated];
+//        }
+//    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+//    if (self.navigationController) {
+//        [self.navigationController setNavigationBarHidden:self.barHidden animated:animated];
+//    }
+}
+
+- (BOOL)prefersStatusBarHidden {
+    return YES;
+}
+
+- (void)setPreImage:(UIImage *)preImage {
+    _preImage = preImage;
+}
+
+//- (BOOL)prefersStatusBarHidden {
+//    return YES;
+//}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)retakeBtnClick:(UIButton *)sender {
+//    if (self.photoHandler) {
+//        self.photoHandler(nil);
+//    }
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (IBAction)usePhotoClick:(UIButton *)sender {
+    
+    if (self.photoHandler) {
+        self.photoHandler(self.preImage);
+    }
+    
+    if (self.popTo) {
+        [self.navigationController setNavigationBarHidden:self.barHidden animated:NO];
+        [self.navigationController popToViewController:self.popTo animated:YES];
+    } else {
+        [self.navigationController popViewControllerAnimated:YES];
+    }
+    
+}
+
+#pragma mark - UIScrollViewDelegate
+
+- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
+    return self.previewPhotoView;
+}
+
+
+
+
+
+@end

+ 6 - 0
common/Camera/camera.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 23 - 0
common/Camera/camera.xcassets/btn_photo_assign.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "btn_photo_assign.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "btn_photo_assign@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "btn_photo_assign@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
common/Camera/camera.xcassets/btn_photo_assign.imageset/btn_photo_assign.png


BIN
common/Camera/camera.xcassets/btn_photo_assign.imageset/btn_photo_assign@2x.png


BIN
common/Camera/camera.xcassets/btn_photo_assign.imageset/btn_photo_assign@3x.png


+ 23 - 0
common/Camera/camera.xcassets/btn_photo_retake.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "btn_photo_retake.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "btn_photo_retake@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "btn_photo_retake@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
common/Camera/camera.xcassets/btn_photo_retake.imageset/btn_photo_retake.png


BIN
common/Camera/camera.xcassets/btn_photo_retake.imageset/btn_photo_retake@2x.png


BIN
common/Camera/camera.xcassets/btn_photo_retake.imageset/btn_photo_retake@3x.png


+ 23 - 0
common/Camera/camera.xcassets/btn_return.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "btn_return.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "btn_return@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "btn_return@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

BIN
common/Camera/camera.xcassets/btn_return.imageset/btn_return.png


BIN
common/Camera/camera.xcassets/btn_return.imageset/btn_return@2x.png


BIN
common/Camera/camera.xcassets/btn_return.imageset/btn_return@3x.png


+ 124 - 0
common/DatePicker/Base.lproj/date.storyboard

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Date Picker View Controller-->
+        <scene sceneID="Zyp-gu-v0h">
+            <objects>
+                <viewController storyboardIdentifier="RADatePickerViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="UZ8-Ru-lSY" customClass="RADatePickerViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="3G4-y1-fay">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fbi-R0-4N2">
+                                <rect key="frame" x="5" y="25" width="365" height="40"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="40" id="Ly9-61-pLF"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O9N-iu-Ek5">
+                                <rect key="frame" x="0.0" y="64" width="375" height="0.5"/>
+                                <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="0.5" id="0H3-fw-1wB"/>
+                                </constraints>
+                            </view>
+                            <datePicker contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" datePickerMode="date" minuteInterval="1" translatesAutoresizingMaskIntoConstraints="NO" id="p97-x3-1d5">
+                                <rect key="frame" x="0.0" y="65" width="375" height="238"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="238" id="r3b-tc-qku"/>
+                                </constraints>
+                                <date key="date" timeIntervalSinceReferenceDate="557120579.94449699">
+                                    <!--2018-08-28 03:42:59 +0000-->
+                                </date>
+                            </datePicker>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cBT-vV-Li8">
+                                <rect key="frame" x="0.0" y="303" width="375" height="41"/>
+                                <subviews>
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LjX-WA-ZSH">
+                                        <rect key="frame" x="188" y="1" width="187" height="40"/>
+                                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="40" id="Tli-gy-iyX"/>
+                                        </constraints>
+                                        <state key="normal" title="Set">
+                                            <color key="titleColor" red="1" green="0.1047433005" blue="0.075207091899999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        </state>
+                                        <connections>
+                                            <action selector="setBtnClick:" destination="UZ8-Ru-lSY" eventType="touchUpInside" id="U7T-k0-wnb"/>
+                                        </connections>
+                                    </button>
+                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7Bd-bE-hfF">
+                                        <rect key="frame" x="0.0" y="1" width="187" height="40"/>
+                                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        <constraints>
+                                            <constraint firstAttribute="height" constant="40" id="Ug3-7k-Rpy"/>
+                                        </constraints>
+                                        <state key="normal" title="Cancel"/>
+                                        <connections>
+                                            <action selector="cancelBtnClick:" destination="UZ8-Ru-lSY" eventType="touchUpInside" id="yh6-LK-cR2"/>
+                                        </connections>
+                                    </button>
+                                </subviews>
+                                <color key="backgroundColor" red="0.9322579339" green="0.9322579339" blue="0.9322579339" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="41" id="0ED-vX-XfU"/>
+                                    <constraint firstItem="LjX-WA-ZSH" firstAttribute="leading" secondItem="7Bd-bE-hfF" secondAttribute="trailing" constant="1" id="39B-8l-8He"/>
+                                    <constraint firstItem="LjX-WA-ZSH" firstAttribute="top" secondItem="cBT-vV-Li8" secondAttribute="top" constant="1" id="CUE-qo-Ed6"/>
+                                    <constraint firstItem="LjX-WA-ZSH" firstAttribute="width" secondItem="7Bd-bE-hfF" secondAttribute="width" id="d7B-qa-xgc"/>
+                                    <constraint firstAttribute="trailing" secondItem="LjX-WA-ZSH" secondAttribute="trailing" id="dTk-fs-BGS"/>
+                                    <constraint firstItem="7Bd-bE-hfF" firstAttribute="top" secondItem="cBT-vV-Li8" secondAttribute="top" constant="1" id="ifC-kU-vkx"/>
+                                    <constraint firstItem="7Bd-bE-hfF" firstAttribute="leading" secondItem="cBT-vV-Li8" secondAttribute="leading" id="uHP-vF-oUL"/>
+                                </constraints>
+                            </view>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ei2-z6-v8t">
+                                <rect key="frame" x="0.0" y="303" width="375" height="0.5"/>
+                                <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="0.5" id="ShW-cR-veE"/>
+                                </constraints>
+                            </view>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <gestureRecognizers/>
+                        <constraints>
+                            <constraint firstItem="p97-x3-1d5" firstAttribute="top" secondItem="Fbi-R0-4N2" secondAttribute="bottom" id="2XR-9y-ej4"/>
+                            <constraint firstItem="O9N-iu-Ek5" firstAttribute="leading" secondItem="xiG-YA-3Yu" secondAttribute="leading" id="2lx-uQ-mdE"/>
+                            <constraint firstItem="xiG-YA-3Yu" firstAttribute="trailing" secondItem="cBT-vV-Li8" secondAttribute="trailing" id="6E2-Nw-A2p"/>
+                            <constraint firstItem="cBT-vV-Li8" firstAttribute="leading" secondItem="xiG-YA-3Yu" secondAttribute="leading" id="6J3-31-uJT"/>
+                            <constraint firstItem="Fbi-R0-4N2" firstAttribute="top" secondItem="xiG-YA-3Yu" secondAttribute="top" constant="5" id="Nkn-02-9dp"/>
+                            <constraint firstItem="xiG-YA-3Yu" firstAttribute="trailing" secondItem="Fbi-R0-4N2" secondAttribute="trailing" constant="5" id="Xk4-1K-DGL"/>
+                            <constraint firstItem="xiG-YA-3Yu" firstAttribute="trailing" secondItem="O9N-iu-Ek5" secondAttribute="trailing" id="Z5t-sR-OiV"/>
+                            <constraint firstItem="O9N-iu-Ek5" firstAttribute="top" secondItem="Fbi-R0-4N2" secondAttribute="bottom" constant="-1" id="dKu-nW-qid"/>
+                            <constraint firstItem="p97-x3-1d5" firstAttribute="trailing" secondItem="xiG-YA-3Yu" secondAttribute="trailing" id="il2-tV-eIZ"/>
+                            <constraint firstItem="cBT-vV-Li8" firstAttribute="top" secondItem="p97-x3-1d5" secondAttribute="bottom" id="pLe-ib-Aey"/>
+                            <constraint firstItem="Ei2-z6-v8t" firstAttribute="leading" secondItem="xiG-YA-3Yu" secondAttribute="leading" id="pqS-vs-71I"/>
+                            <constraint firstItem="Fbi-R0-4N2" firstAttribute="leading" secondItem="xiG-YA-3Yu" secondAttribute="leading" constant="5" id="prt-yY-H7F"/>
+                            <constraint firstItem="xiG-YA-3Yu" firstAttribute="trailing" secondItem="Ei2-z6-v8t" secondAttribute="trailing" id="qNA-vg-KJz"/>
+                            <constraint firstItem="Ei2-z6-v8t" firstAttribute="top" secondItem="cBT-vV-Li8" secondAttribute="top" id="sY1-6d-EqB"/>
+                            <constraint firstItem="p97-x3-1d5" firstAttribute="leading" secondItem="xiG-YA-3Yu" secondAttribute="leading" id="tbN-9P-LLx"/>
+                        </constraints>
+                        <viewLayoutGuide key="safeArea" id="xiG-YA-3Yu"/>
+                    </view>
+                    <connections>
+                        <outlet property="datePicker" destination="p97-x3-1d5" id="Ca6-aZ-Jl3"/>
+                        <outlet property="titleLabel" destination="Fbi-R0-4N2" id="qvH-GX-0Kx"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ggs-ni-j3T" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="549.60000000000002" y="45.42728635682159"/>
+        </scene>
+    </scenes>
+</document>

+ 17 - 0
common/DatePicker/RADatePickerViewController.h

@@ -0,0 +1,17 @@
+//
+//  RADatePickerViewController.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/8/28.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RABaseViewController.h"
+
+@interface RADatePickerViewController : RABaseViewController
+
++ (void)presentDatePicker:(UIViewController *)viewController title:(NSString *)title withSetBlk:(void(^)(NSDate *date))blk;
+
++ (void)presentDatePicker:(UIViewController *)viewController title:(NSString *)title dateMode:(UIDatePickerMode)mode withSetBlk:(void(^)(NSDate *date))blk;
+
+@end

+ 108 - 0
common/DatePicker/RADatePickerViewController.m

@@ -0,0 +1,108 @@
+//
+//  RADatePickerViewController.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/8/28.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RADatePickerViewController.h"
+#import "RAPresentationController.h"
+
+@interface RADatePickerViewController () <UIViewControllerTransitioningDelegate>
+
+@property (strong, nonatomic) IBOutlet UILabel *titleLabel;
+@property (strong, nonatomic) IBOutlet UIDatePicker *datePicker;
+
+@property (nonatomic,copy) void(^blk)(NSDate *);
+@property (nonatomic,assign) UIDatePickerMode datePickerMode;
+
+@end
+
+@implementation RADatePickerViewController
+
++ (instancetype)viewControllerFromStoryboard {
+    RADatePickerViewController *datePickerVC = [[UIStoryboard storyboardWithName:@"date" bundle:nil] instantiateViewControllerWithIdentifier:[self storyboardID]];
+    
+    
+    return datePickerVC;
+}
+
++ (void)presentDatePicker:(UIViewController *)viewController title:(NSString *)title dateMode:(UIDatePickerMode)mode withSetBlk:(void(^)(NSDate *date))blk {
+    
+    if (!viewController) {
+        return;
+    }
+    
+    RADatePickerViewController *datePickerVC = [self viewControllerFromStoryboard];
+    
+    datePickerVC.title = title;
+    datePickerVC.blk = blk;
+    datePickerVC.datePickerMode = mode;
+    
+    datePickerVC.transitioningDelegate = datePickerVC;
+    datePickerVC.modalPresentationStyle = UIModalPresentationCustom;
+    
+//    CGFloat width = [UIScreen mainScreen].bounds.size.width - 40;
+    datePickerVC.preferredContentSize = CGSizeMake(300, 325);
+    
+    [viewController presentViewController:datePickerVC animated:YES completion:nil];
+}
+
++ (void)presentDatePicker:(UIViewController *)viewController title:(NSString *)title withSetBlk:(void(^)(NSDate *date))blk {
+    
+    [self presentDatePicker:viewController title:title dateMode:UIDatePickerModeDate withSetBlk:blk];
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    
+    self.view.layer.cornerRadius = 10.0f;
+    self.view.layer.masksToBounds = YES;
+    
+    self.datePicker.datePickerMode = self.datePickerMode;
+    self.titleLabel.text = self.title;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - UIViewControllerTransitioningDelegate
+
+- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented
+                                                      presentingViewController:(UIViewController *)presenting
+                                                          sourceViewController:(UIViewController *)source {
+    
+    return [[RAPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
+    
+}
+
+#pragma mark - Action
+
+- (IBAction)cancelBtnClick:(id)sender {
+    
+    [self dismissViewControllerAnimated:YES completion:nil];
+    
+}
+
+- (IBAction)setBtnClick:(id)sender {
+    
+    __weak typeof(self) weakSelf = self;
+    NSDate *date = self.datePicker.date;
+    [self dismissViewControllerAnimated:YES completion:^{
+       
+        if (weakSelf) {
+            __strong typeof(weakSelf) strongSelf = weakSelf;
+            if (strongSelf.blk) {
+                strongSelf.blk(date);
+            }
+        }
+        
+    }];
+}
+
+
+@end

+ 9 - 0
common/DatePicker/en.lproj/date.strings

@@ -0,0 +1,9 @@
+
+/* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "7Bd-bE-hfF"; */
+"7Bd-bE-hfF.normalTitle" = "Cancel";
+
+/* Class = "UILabel"; text = "Title"; ObjectID = "Fbi-R0-4N2"; */
+"Fbi-R0-4N2.text" = "Title";
+
+/* Class = "UIButton"; normalTitle = "Set"; ObjectID = "LjX-WA-ZSH"; */
+"LjX-WA-ZSH.normalTitle" = "Set";

+ 9 - 0
common/DatePicker/zh-Hans.lproj/date.strings

@@ -0,0 +1,9 @@
+
+/* Class = "UIButton"; normalTitle = "Cancel"; ObjectID = "7Bd-bE-hfF"; */
+"7Bd-bE-hfF.normalTitle" = "取消";
+
+/* Class = "UILabel"; text = "Title"; ObjectID = "Fbi-R0-4N2"; */
+"Fbi-R0-4N2.text" = "Title";
+
+/* Class = "UIButton"; normalTitle = "Set"; ObjectID = "LjX-WA-ZSH"; */
+"LjX-WA-ZSH.normalTitle" = "确定";

+ 15 - 0
common/EmptyView/RAEmptyView.h

@@ -0,0 +1,15 @@
+//
+//  RAEmptyView.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/9/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RAEmptyView : UIView
+
++ (instancetype)emptyViewWithTapBlk:(void(^)(id sender))tapEmptyBlk;
+
+@end

+ 65 - 0
common/EmptyView/RAEmptyView.m

@@ -0,0 +1,65 @@
+//
+//  RAEmptyView.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/9/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RAEmptyView.h"
+
+@interface RAEmptyView ()
+
+@property (nonatomic,copy) void(^tapEmptyBlk)(id sender);
+@property (nonatomic,strong) UILabel *tipLabel;
+
+@end
+
+@implementation RAEmptyView
+
++ (instancetype)emptyViewWithTapBlk:(void(^)(id sender))tapEmptyBlk {
+    RAEmptyView *emptyView = [RAEmptyView new];
+    emptyView.frame = CGRectMake(0, 0, 200, 80);
+    emptyView.tapEmptyBlk = tapEmptyBlk;
+    
+    return emptyView;
+}
+
+- (instancetype)init {
+    
+    if (self = [super init]) {
+        self.layer.borderColor = [UIColor grayColor].CGColor;
+        self.layer.borderWidth = 0.5f;
+        self.layer.cornerRadius = 5.0f;
+        self.layer.masksToBounds = YES;
+        [self addSubview:self.tipLabel];
+        
+        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapEmpty:)];
+        [self addGestureRecognizer:tap];
+    }
+    return self;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    self.tipLabel.frame = self.bounds;
+}
+
+- (UILabel *)tipLabel {
+    if (!_tipLabel) {
+        _tipLabel = [[UILabel alloc] init];
+        _tipLabel.text = NSLocalizedString(@"empty_tips", nil);
+        _tipLabel.numberOfLines = 0;
+        _tipLabel.textAlignment = NSTextAlignmentCenter;
+    }
+    return _tipLabel;
+}
+
+- (void)tapEmpty:(UITapGestureRecognizer *)tap {
+    if (self.tapEmptyBlk) {
+        self.tapEmptyBlk(tap);
+    }
+}
+
+@end

+ 18 - 0
common/ExceptionHandler/RAExceptionHandler.h

@@ -0,0 +1,18 @@
+//
+//  LPExceptionHandler.h
+//  Mach-O UUID
+//
+//  Created by Jack on 2018/8/1.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ * @brief 收集Crash信息,分析参考https://github.com/answer-huang/dSYMTools
+ */
+@interface RAExceptionHandler : NSObject
+
++ (void)registHandler:(void (^)(NSString *exceptionStr)) handler;
+
+@end

+ 227 - 0
common/ExceptionHandler/RAExceptionHandler.m

@@ -0,0 +1,227 @@
+//
+//  LPExceptionHandler.m
+//  Mach-O UUID
+//
+//  Created by Jack on 2018/8/1.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RAExceptionHandler.h"
+#import <UIKit/UIDevice.h>
+#import <sys/utsname.h>
+
+// Mach-O UUID
+#import <mach-o/ldsyms.h>
+
+// CPU arch
+#import <mach-o/arch.h>
+
+// Slide Address
+#include <mach-o/dyld.h>
+
+@interface RAExceptionHandler ()
+
+@property (nonatomic,copy) void (^handler)(NSString *);
+
++ (instancetype)sharedHanlder;
+
+@end
+
+#pragma mark - dSYM UUID
+
+// 获取主执行Image UUID,此UUID要和dSYM文件UUID相同
+NSString *mach_oUUID() {
+    const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1);
+    for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) {
+        if (((const struct load_command *)command)->cmd == LC_UUID) {
+            command += sizeof(struct load_command);
+//            return [NSString stringWithFormat:@"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+//                    command[0], command[1], command[2], command[3],
+//                    command[4], command[5],
+//                    command[6], command[7],
+//                    command[8], command[9],
+//                    command[10], command[11], command[12], command[13], command[14], command[15]];
+            
+            CFUUIDRef uuidRef = CFUUIDCreateFromUUIDBytes(NULL, *((CFUUIDBytes*)command));
+            NSString* uuidStr = (__bridge_transfer NSString*)CFUUIDCreateString(NULL, uuidRef);
+            
+            return uuidStr;
+            
+        } else {
+            command += ((const struct load_command *)command)->cmdsize;
+        }
+    }
+    return nil;
+}
+
+#pragma mark - CPU Type
+
+const char *byteOrder(enum NXByteOrder BO) {
+    switch (BO) {
+        case NX_LittleEndian: return ("Little-Endian");
+        case NX_BigEndian: return ("Big-Endian");
+        case NX_UnknownByteOrder: return "Unknow";
+        default: return ("!?!");
+    }
+}
+
+void testGetAllArch () {
+    
+    const NXArchInfo *known = NXGetAllArchInfos();
+    
+    while (known && known->description) {
+        printf("known: %s\t%x/%x\t%s\n", known->description,
+               known->cputype,
+               known->cpusubtype,
+               byteOrder(known->byteorder));
+        known++;
+    }
+}
+
+// 获取CPU架构类型
+NSString *localCPUType() {
+    const NXArchInfo *local = NXGetLocalArchInfo();
+    
+    
+    if (local) {
+        printf("Local - %s\t%x/%x\t%s\n", local->description,
+               local->cputype,
+               local->cpusubtype,
+               byteOrder(local->byteorder));
+        
+        return [NSString stringWithUTF8String:local->description];
+    }
+    return @"unknown";
+}
+
+#pragma mark - Slide Address
+
+//获取基地址
+uintptr_t loadAddress() {
+    const struct mach_header *exe_header = NULL;
+    for (uint32_t i = 0; i < _dyld_image_count(); i++) {
+        const struct mach_header *header = _dyld_get_image_header(i);
+        if (header->filetype == MH_EXECUTE) {
+            exe_header = header;
+            break;
+        }
+    }
+    
+    //返回值即为加载地址
+    return (uintptr_t)exe_header;
+}
+
+// 获取偏移地址
+uintptr_t slideAddress() {
+    
+    uintptr_t vmaddr_slide = 0;
+    for (uint32_t i = 0; i < _dyld_image_count(); i++) {
+        const struct mach_header *header = _dyld_get_image_header(i);
+        if (header->filetype == MH_EXECUTE) {
+            vmaddr_slide = _dyld_get_image_vmaddr_slide(i);
+            break;
+        }
+    }
+    
+    return (uintptr_t)vmaddr_slide;
+}
+
+#pragma mark - Binary Image
+
+NSString *binaryImageName() {
+    
+    for (uint32_t i = 0; i < _dyld_image_count(); i++) {
+        const struct mach_header *header = _dyld_get_image_header(i);
+        if (header->filetype == MH_EXECUTE) {
+            
+            const char *path = _dyld_get_image_name((unsigned)i);
+            NSString *imagePath = [NSString stringWithUTF8String:path];
+            NSArray *array = [imagePath componentsSeparatedByString:@"/"];
+            NSString *imageName = array[array.count - 1];
+            return imageName;
+            
+            break;
+        }
+    }
+    
+    return nil;
+}
+
+#pragma mark - Caught Exception
+
+void UncaughtExceptionHandler(NSException *exception) {
+    
+    NSMutableString *exceptionStr = [NSMutableString string];
+    
+    UIDevice *device = [UIDevice currentDevice];
+    NSString *modle = device.model;
+    NSString *os = device.systemName;
+    NSString *ver = device.systemVersion;
+    
+    struct utsname systeminfo;
+    uname(&systeminfo);
+    NSString *deviceString = [NSString stringWithCString:systeminfo.machine encoding:NSUTF8StringEncoding];
+    
+    [exceptionStr appendFormat:@"Device: %@\n",modle];
+    [exceptionStr appendFormat:@"OS: %@ %@\n",os,ver];
+    [exceptionStr appendFormat:@"Hardware: %@\n",deviceString];
+    
+    NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
+    NSString* build =[infoDict objectForKey:@"CFBundleVersion"];
+    NSString* version =[infoDict objectForKey:@"CFBundleShortVersionString"];
+    NSString *bundleID = [infoDict objectForKey:@"CFBundleIdentifier"];
+    NSString *bundleName = [infoDict objectForKey:@"CFBundleName"];
+    
+    [exceptionStr appendFormat:@"Bundle Name: %@\n",bundleName];
+    [exceptionStr appendFormat:@"build: %@\n",build];
+    [exceptionStr appendFormat:@"version: %@\n",version];
+    [exceptionStr appendFormat:@"identifier: %@\n",bundleID];
+    
+    NSDate *date = [NSDate date];
+    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss Z"];
+    NSString *dateStr = [formatter stringFromDate:date];
+    
+    [exceptionStr appendFormat:@"Date/Time: %@\n\n",dateStr];
+    
+    NSArray *callStack = [exception callStackSymbols];
+    NSString *reason = [exception reason];
+    NSString *name = [exception name];
+    
+    [exceptionStr appendFormat:@"%@\n%@\n\n%@\n\n",name,reason,callStack];
+    [exceptionStr appendFormat:@"dSYM UUID: %@\n",mach_oUUID()];
+    [exceptionStr appendFormat:@"CPU Type: %@\n",localCPUType()];
+    [exceptionStr appendFormat:@"Slide Address: 0x%lx\n",slideAddress()];
+    [exceptionStr appendFormat:@"Binary Image: %@\n",binaryImageName()];
+    [exceptionStr appendFormat:@"Base Address: 0x%lx\n",loadAddress()];
+    
+    NSLog(@"exception:\n%@",exceptionStr);
+    
+    if ([RAExceptionHandler sharedHanlder].handler) {
+        [RAExceptionHandler sharedHanlder].handler(exceptionStr);
+    }
+}
+
+#pragma mark - Handler
+
+@implementation RAExceptionHandler
+
++ (instancetype)sharedHanlder {
+    static RAExceptionHandler *handler = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        handler = [[RAExceptionHandler alloc] init];
+    });
+    return handler;
+}
+
++ (void)registHandler:(void (^)(NSString *))handler {
+    [[RAExceptionHandler sharedHanlder] registExceptionHandler:handler];
+}
+
+- (void)registExceptionHandler:(void (^)(NSString *))handler {
+    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
+    self.handler = handler;
+}
+
+@end

+ 23 - 0
common/HUD/RAProgressHUD.h

@@ -0,0 +1,23 @@
+//
+//  RAProgressHUD.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/6/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RAProgressHUD : UIView
+
+@property (nonatomic,copy) NSString *title;
+
++ (instancetype)showHUDOnView:(UIView *)view;
+
++ (instancetype)showHUDOnView:(UIView *)view withTitle:(NSString *)title;
+
+- (void)dismiss;
+
+- (void)dismiss:(void(^)(void))completion;
+
+@end

+ 128 - 0
common/HUD/RAProgressHUD.m

@@ -0,0 +1,128 @@
+//
+//  RAProgressHUD.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/6/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RAProgressHUD.h"
+
+static const CGFloat HUDSIZE = 100.0f;
+
+@interface RAProgressHUD ()
+
+@property (nonatomic,strong) CAGradientLayer *gradientLayer;
+@property (nonatomic,strong) CAShapeLayer *progressLayer;
+
+@property (nonatomic,strong) UIActivityIndicatorView *activityIndicator;
+@property (nonatomic,strong) UILabel *indicatorLabel;
+
+@end
+
+@implementation RAProgressHUD
+
++ (instancetype)showHUDOnView:(UIView *)view {
+    
+    return [self showHUDOnView:view withTitle:NSLocalizedString(@"loading...", @"loading...")];
+}
+
++ (instancetype)showHUDOnView:(UIView *)view withTitle:(NSString *)title {
+    
+    if (!view) {
+        return nil;
+    }
+    
+    RAProgressHUD *hud = [[RAProgressHUD alloc] init];
+    hud.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.8];
+    hud.layer.cornerRadius = 5.0f;
+    hud.layer.masksToBounds = YES;
+    [view addSubview:hud];
+    
+    hud.translatesAutoresizingMaskIntoConstraints = NO;
+    
+    NSLayoutConstraint *h_center = [NSLayoutConstraint constraintWithItem:hud
+                                                                attribute:NSLayoutAttributeCenterX
+                                                                relatedBy:NSLayoutRelationEqual
+                                                                   toItem:view
+                                                                attribute:NSLayoutAttributeCenterX
+                                                               multiplier:1
+                                                                 constant:0];
+    
+    NSLayoutConstraint *v_center = [NSLayoutConstraint constraintWithItem:hud
+                                                                attribute:NSLayoutAttributeCenterY
+                                                                relatedBy:NSLayoutRelationEqual
+                                                                   toItem:view
+                                                                attribute:NSLayoutAttributeCenterY
+                                                               multiplier:1
+                                                                 constant:0];
+    NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:hud
+                                                             attribute:NSLayoutAttributeWidth
+                                                             relatedBy:NSLayoutRelationEqual
+                                                                toItem:nil
+                                                             attribute:NSLayoutAttributeNotAnAttribute
+                                                            multiplier:0
+                                                              constant:HUDSIZE];
+    NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:hud
+                                                              attribute:NSLayoutAttributeHeight
+                                                              relatedBy:NSLayoutRelationEqual
+                                                                 toItem:nil
+                                                              attribute:NSLayoutAttributeNotAnAttribute
+                                                             multiplier:0
+                                                               constant:HUDSIZE];
+    [view addConstraints:@[h_center,v_center,width,height]];
+    
+    hud.title = title;
+    
+    hud.indicatorLabel.frame = CGRectMake(0, 70, HUDSIZE, 20);
+    [hud addSubview:hud.indicatorLabel];
+    
+    hud.activityIndicator.frame = CGRectMake(20, 5, 60, 60);
+    [hud addSubview:hud.activityIndicator];
+    
+//    hud.window.userInteractionEnabled = NO;
+    
+    return hud;
+}
+
+- (UIActivityIndicatorView *)activityIndicator {
+    if (!_activityIndicator) {
+        _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+        [_activityIndicator startAnimating];
+    }
+    return _activityIndicator;
+}
+
+- (UILabel *)indicatorLabel {
+    if (!_indicatorLabel) {
+        _indicatorLabel = [[UILabel alloc] init];
+        _indicatorLabel.textColor = [UIColor whiteColor];
+        _indicatorLabel.textAlignment = NSTextAlignmentCenter;
+        _indicatorLabel.font = [UIFont systemFontOfSize:14.0f];
+    }
+    return _indicatorLabel;
+}
+
+- (void)dismiss {
+    [self dismiss:nil];
+}
+
+- (void)dismiss:(void(^)(void))completion {
+    
+//    self.window.userInteractionEnabled = YES;
+    [UIView animateWithDuration:0.25 animations:^{
+        self.alpha = 0.3;
+    } completion:^(BOOL finished) {
+        [self removeFromSuperview];
+        if (completion) {
+            completion();
+        }
+    }];
+}
+
+- (void)setTitle:(NSString *)title {
+    _title = title;
+    self.indicatorLabel.text = title;
+}
+
+@end

+ 24 - 0
common/NSData/NSData+RAImageType.h

@@ -0,0 +1,24 @@
+//
+//  NSData+RAImageType.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/10/15.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef NS_ENUM(NSInteger,RAIMAGETYPE) {
+    RAIMAGETYPEPNG,
+    RAIMAGETYPEJPG,
+    RAIMAGETYPEBMP,
+    RAIMAGETYPEGIF,
+    RAIMAGETYPEUNKNOW
+};
+
+@interface NSData (RAImageType)
+
+-(RAIMAGETYPE)imageType;
+
+@end
+

+ 43 - 0
common/NSData/NSData+RAImageType.m

@@ -0,0 +1,43 @@
+//
+//  NSData+RAImageType.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/10/15.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "NSData+RAImageType.h"
+
+@implementation NSData (RAImageType)
+
+-(RAIMAGETYPE)imageType {
+    if (self.length > 4) {
+        const unsigned char *byte = self.bytes;
+        // jpeg/jpg
+        // ff d8
+        if (byte[0] == 0xff && byte[1] == 0xd8 && byte[2] == 0xff) {
+            return RAIMAGETYPEJPG;
+        }
+        // png
+        // 89 50 4e 47
+        if (byte[0] == 0x89 && byte[1] == 0x50 && byte[2] == 0x4e && byte[3] == 0x47) {
+            return RAIMAGETYPEPNG;
+        }
+        // bmp
+        // 42 4D
+        if (byte[0] == 0x42 && byte[1] == 0x4d) {
+            return RAIMAGETYPEBMP;
+        }
+        
+        // gif
+        // GIF比对[47][49][46]与第五个字符39(37)
+        if (byte[0] == 0x47 && byte[1] == 0x49 && byte[2] == 0x46 && (byte[4] == 0x39 || byte[4] == 0x37)) {
+            return RAIMAGETYPEGIF;
+        }
+        
+        return RAIMAGETYPEUNKNOW;
+    }
+    return RAIMAGETYPEUNKNOW;
+}
+
+@end

+ 14 - 0
common/PresentationController/RAPresentationController.h

@@ -0,0 +1,14 @@
+//
+//  RAPresentationController.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/8/28.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RAPresentationController : UIPresentationController
+
+@end
+

+ 93 - 0
common/PresentationController/RAPresentationController.m

@@ -0,0 +1,93 @@
+//
+//  RApresentationController.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/8/28.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RAPresentationController.h"
+
+@interface RAPresentationController ()
+
+@property (nonatomic,strong) UIView *dimmingView;
+
+@end
+
+@implementation RAPresentationController
+
+- (UIView *)dimmingView {
+    if (!_dimmingView) {
+        _dimmingView = [UIView new];
+        _dimmingView.backgroundColor = [UIColor grayColor];
+    }
+    return _dimmingView;
+}
+
+- (void)presentationTransitionWillBegin {
+    self.dimmingView.frame = self.containerView.bounds;
+    self.dimmingView.alpha = 0.f;
+    
+    [self.containerView addSubview:self.dimmingView];
+    [self.containerView addSubview:self.presentedView];
+    
+    // 确保我们的动画与其他动画一道儿播放。
+    id<UIViewControllerTransitionCoordinator> transitionCoordiantor = self.presentedViewController.transitionCoordinator;
+    [transitionCoordiantor animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
+        self.dimmingView.alpha = .4f;
+    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
+        
+    }];
+}
+
+- (void)presentationTransitionDidEnd:(BOOL)completed {
+    if (completed) {
+        //        [self.dimmingView removeFromSuperview];
+    }
+}
+
+- (CGRect)frameOfPresentedViewInContainerView {
+    CGSize size = self.containerView.bounds.size;
+    
+    UIViewController *presentedVC = self.presentedViewController;
+    size = presentedVC.preferredContentSize;
+    if (size.width <= 0 || size.height <= 0) {
+        size = self.containerView.bounds.size;
+    }
+    
+    CGFloat w = CGRectGetWidth(self.containerView.bounds);
+    CGFloat h = CGRectGetHeight(self.containerView.bounds);
+    
+    return CGRectMake((w - size.width) * 0.5, (h - size.height) * 0.5, size.width, size.height);
+}
+
+- (void)dismissalTransitionWillBegin {
+    // 确保我们的动画与其他动画一道儿播放。
+    id<UIViewControllerTransitionCoordinator> transitionCoordiantor = self.presentedViewController.transitionCoordinator;
+    [transitionCoordiantor animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
+        self.dimmingView.alpha = 0.f;
+    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
+        
+    }];
+}
+
+- (void)dismissalTransitionDidEnd:(BOOL)completed {
+    if (completed) {
+        //        [self.dimmingView removeFromSuperview];
+    }
+}
+
+// 屏幕旋转调用此方法
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    
+    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
+        self.dimmingView.frame = self.containerView.bounds;
+        self.presentedView.frame = [self frameOfPresentedViewInContainerView];
+    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
+        
+    }];
+}
+
+
+@end

+ 173 - 0
common/QRCode/QRCode.storyboard

@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina5_5" orientation="landscape">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+        <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Code Scanner View Controller-->
+        <scene sceneID="SCd-VM-Uux">
+            <objects>
+                <viewController storyboardIdentifier="RAQRCodeScannerViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="41J-NQ-wiU" customClass="RAQRCodeScannerViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="aiT-qZ-M5f">
+                        <rect key="frame" x="0.0" y="0.0" width="736" height="414"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D8z-rA-Qpf">
+                                <rect key="frame" x="0.0" y="0.0" width="736" height="414"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            </view>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4DJ-GK-9l9">
+                                <rect key="frame" x="0.0" y="0.0" width="736" height="414"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            </view>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vCI-Zm-N7X">
+                                <rect key="frame" x="121" y="60" width="294" height="294"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" secondItem="vCI-Zm-N7X" secondAttribute="height" multiplier="1:1" id="8cj-iq-wvr"/>
+                                    <constraint firstAttribute="height" constant="300" id="tXF-V5-qbK"/>
+                                </constraints>
+                                <variation key="default">
+                                    <mask key="constraints">
+                                        <exclude reference="tXF-V5-qbK"/>
+                                    </mask>
+                                </variation>
+                                <variation key="heightClass=regular-widthClass=regular">
+                                    <mask key="constraints">
+                                        <include reference="tXF-V5-qbK"/>
+                                    </mask>
+                                </variation>
+                            </view>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0ig-dn-iSa">
+                                <rect key="frame" x="596" y="177" width="60" height="60"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="60" id="OkG-xs-m3c"/>
+                                    <constraint firstAttribute="width" secondItem="0ig-dn-iSa" secondAttribute="height" multiplier="1:1" id="ZrC-2n-5ix"/>
+                                </constraints>
+                                <connections>
+                                    <action selector="scannerBtnTouchCancel:" destination="41J-NQ-wiU" eventType="touchCancel" id="z40-QN-qDW"/>
+                                    <action selector="scannerBtnTouchDown:" destination="41J-NQ-wiU" eventType="touchDown" id="5TK-sG-LzS"/>
+                                    <action selector="scannerBtnTouchUp:" destination="41J-NQ-wiU" eventType="touchUpInside" id="Nco-1e-gQv"/>
+                                    <action selector="scannerBtnTouchUpOutSide:" destination="41J-NQ-wiU" eventType="touchUpOutside" id="O42-nG-qkE"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="0ig-dn-iSa" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="vCI-Zm-N7X" secondAttribute="trailing" priority="999" constant="10" id="29i-AW-HSH"/>
+                            <constraint firstItem="0ig-dn-iSa" firstAttribute="top" relation="greaterThanOrEqual" secondItem="vCI-Zm-N7X" secondAttribute="bottom" priority="999" constant="10" id="3gR-v0-uuY"/>
+                            <constraint firstItem="4DJ-GK-9l9" firstAttribute="height" secondItem="D8z-rA-Qpf" secondAttribute="height" id="4QJ-Tu-9cj"/>
+                            <constraint firstAttribute="bottom" secondItem="vCI-Zm-N7X" secondAttribute="bottom" constant="81" id="7a1-vL-ZwM"/>
+                            <constraint firstAttribute="trailing" secondItem="0ig-dn-iSa" secondAttribute="trailing" constant="104" id="7eW-A7-Nkb"/>
+                            <constraint firstItem="0ig-dn-iSa" firstAttribute="centerX" secondItem="vCI-Zm-N7X" secondAttribute="centerX" id="7qf-eL-rnv"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="centerX" secondItem="aiT-qZ-M5f" secondAttribute="centerX" id="8dy-2H-2iw"/>
+                            <constraint firstItem="D8z-rA-Qpf" firstAttribute="width" secondItem="aiT-qZ-M5f" secondAttribute="width" id="BuV-2a-gda"/>
+                            <constraint firstItem="0ig-dn-iSa" firstAttribute="centerY" secondItem="vCI-Zm-N7X" secondAttribute="centerY" id="DcB-0a-gGt"/>
+                            <constraint firstItem="4DJ-GK-9l9" firstAttribute="leading" secondItem="D8z-rA-Qpf" secondAttribute="leading" id="OtU-1g-dHc"/>
+                            <constraint firstItem="0ig-dn-iSa" firstAttribute="centerY" secondItem="vCI-Zm-N7X" secondAttribute="centerY" id="R8a-93-kVx"/>
+                            <constraint firstItem="D8z-rA-Qpf" firstAttribute="leading" secondItem="aiT-qZ-M5f" secondAttribute="leading" id="RYY-iZ-sc1"/>
+                            <constraint firstItem="4DJ-GK-9l9" firstAttribute="width" secondItem="D8z-rA-Qpf" secondAttribute="width" id="S8U-sb-mvg"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="centerX" secondItem="aiT-qZ-M5f" secondAttribute="centerX" constant="-100" id="V3j-Mb-G9g"/>
+                            <constraint firstItem="0ig-dn-iSa" firstAttribute="centerX" secondItem="vCI-Zm-N7X" secondAttribute="centerX" id="Vi4-ET-WmZ"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="centerX" secondItem="aiT-qZ-M5f" secondAttribute="centerX" constant="-80" id="Z6F-qY-EEv"/>
+                            <constraint firstAttribute="trailing" secondItem="vCI-Zm-N7X" secondAttribute="trailing" constant="70" id="cSr-ne-Xxd"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="centerY" secondItem="aiT-qZ-M5f" secondAttribute="centerY" constant="-110" id="e2p-ZK-jAC"/>
+                            <constraint firstAttribute="trailing" secondItem="0ig-dn-iSa" secondAttribute="trailing" constant="80" id="eCS-j2-u7d"/>
+                            <constraint firstAttribute="bottom" secondItem="0ig-dn-iSa" secondAttribute="bottom" constant="100" id="exY-By-XcQ"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="centerY" secondItem="aiT-qZ-M5f" secondAttribute="centerY" constant="-70" id="fNO-9Q-eMD"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="top" secondItem="aiT-qZ-M5f" secondAttribute="top" constant="60" id="gDV-MG-Lxf"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="top" secondItem="aiT-qZ-M5f" secondAttribute="top" constant="60" id="mwH-jr-Ixq"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="leading" secondItem="aiT-qZ-M5f" secondAttribute="leading" constant="70" id="ncF-ii-QJ5"/>
+                            <constraint firstAttribute="bottom" secondItem="0ig-dn-iSa" secondAttribute="bottom" constant="70" id="qin-xY-VOb"/>
+                            <constraint firstItem="D8z-rA-Qpf" firstAttribute="top" secondItem="aiT-qZ-M5f" secondAttribute="top" id="rVq-z9-u0f"/>
+                            <constraint firstItem="vCI-Zm-N7X" firstAttribute="centerX" secondItem="aiT-qZ-M5f" secondAttribute="centerX" id="s29-TR-Yol"/>
+                            <constraint firstItem="4DJ-GK-9l9" firstAttribute="top" secondItem="D8z-rA-Qpf" secondAttribute="top" id="sbV-jE-FcH"/>
+                            <constraint firstItem="D8z-rA-Qpf" firstAttribute="height" secondItem="aiT-qZ-M5f" secondAttribute="height" id="swA-T5-xSR"/>
+                            <constraint firstAttribute="bottom" secondItem="vCI-Zm-N7X" secondAttribute="bottom" constant="60" id="uOO-Nq-OMU"/>
+                        </constraints>
+                        <viewLayoutGuide key="safeArea" id="TEW-wV-M4S"/>
+                        <variation key="default">
+                            <mask key="constraints">
+                                <exclude reference="7a1-vL-ZwM"/>
+                                <exclude reference="8dy-2H-2iw"/>
+                                <exclude reference="V3j-Mb-G9g"/>
+                                <exclude reference="Z6F-qY-EEv"/>
+                                <exclude reference="cSr-ne-Xxd"/>
+                                <exclude reference="e2p-ZK-jAC"/>
+                                <exclude reference="fNO-9Q-eMD"/>
+                                <exclude reference="gDV-MG-Lxf"/>
+                                <exclude reference="mwH-jr-Ixq"/>
+                                <exclude reference="ncF-ii-QJ5"/>
+                                <exclude reference="s29-TR-Yol"/>
+                                <exclude reference="uOO-Nq-OMU"/>
+                                <exclude reference="29i-AW-HSH"/>
+                                <exclude reference="3gR-v0-uuY"/>
+                                <exclude reference="7eW-A7-Nkb"/>
+                                <exclude reference="7qf-eL-rnv"/>
+                                <exclude reference="DcB-0a-gGt"/>
+                                <exclude reference="R8a-93-kVx"/>
+                                <exclude reference="Vi4-ET-WmZ"/>
+                                <exclude reference="eCS-j2-u7d"/>
+                                <exclude reference="exY-By-XcQ"/>
+                                <exclude reference="qin-xY-VOb"/>
+                            </mask>
+                        </variation>
+                        <variation key="heightClass=compact-widthClass=compact">
+                            <mask key="constraints">
+                                <include reference="7a1-vL-ZwM"/>
+                                <include reference="Z6F-qY-EEv"/>
+                                <include reference="gDV-MG-Lxf"/>
+                                <include reference="29i-AW-HSH"/>
+                                <include reference="7eW-A7-Nkb"/>
+                                <include reference="DcB-0a-gGt"/>
+                            </mask>
+                        </variation>
+                        <variation key="heightClass=compact-widthClass=regular">
+                            <mask key="constraints">
+                                <include reference="V3j-Mb-G9g"/>
+                                <include reference="mwH-jr-Ixq"/>
+                                <include reference="uOO-Nq-OMU"/>
+                                <include reference="R8a-93-kVx"/>
+                                <include reference="eCS-j2-u7d"/>
+                            </mask>
+                        </variation>
+                        <variation key="heightClass=regular-widthClass=compact">
+                            <mask key="constraints">
+                                <include reference="8dy-2H-2iw"/>
+                                <include reference="cSr-ne-Xxd"/>
+                                <include reference="fNO-9Q-eMD"/>
+                                <include reference="ncF-ii-QJ5"/>
+                                <include reference="3gR-v0-uuY"/>
+                                <include reference="Vi4-ET-WmZ"/>
+                                <include reference="qin-xY-VOb"/>
+                            </mask>
+                        </variation>
+                        <variation key="heightClass=regular-widthClass=regular">
+                            <mask key="constraints">
+                                <include reference="e2p-ZK-jAC"/>
+                                <include reference="s29-TR-Yol"/>
+                                <include reference="7qf-eL-rnv"/>
+                                <include reference="exY-By-XcQ"/>
+                            </mask>
+                        </variation>
+                    </view>
+                    <connections>
+                        <outlet property="maskView" destination="4DJ-GK-9l9" id="naM-uL-H99"/>
+                        <outlet property="previewContainer" destination="D8z-rA-Qpf" id="XCg-1T-zSa"/>
+                        <outlet property="scanBtn" destination="0ig-dn-iSa" id="JUa-KJ-cvr"/>
+                        <outlet property="scanerView" destination="vCI-Zm-N7X" id="09n-Fn-vIF"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="3tF-Yn-TdS" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-155.70652173913044" y="160.86956521739131"/>
+        </scene>
+    </scenes>
+</document>

+ 17 - 0
common/QRCode/RAQRCodeScannerViewController.h

@@ -0,0 +1,17 @@
+//
+//  RAQRCodeScannerViewController.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/6/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RAQRCodeScannerViewController : UIViewController
+
+@property (nonatomic,copy) void (^completion)(NSString *value);
+
++ (instancetype)viewControllerFromStoryboard;
+
+@end

+ 373 - 0
common/QRCode/RAQRCodeScannerViewController.m

@@ -0,0 +1,373 @@
+//
+//  RAQRCodeScannerViewController.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/6/5.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "RAQRCodeScannerViewController.h"
+#import <AVKit/AVKit.h>
+
+@interface RAQRCodeScannerViewController () <AVCaptureMetadataOutputObjectsDelegate>
+
+@property (strong, nonatomic) IBOutlet UIView *scanerView;
+@property (nonatomic,strong) IBOutlet UIView *previewContainer;
+@property (strong, nonatomic) IBOutlet UIView *maskView;
+@property (strong, nonatomic) IBOutlet UIButton *scanBtn;
+
+@property (nonatomic,strong) AVCaptureDevice *device;
+@property (nonatomic,strong) AVCaptureDeviceInput *input;
+@property (nonatomic,strong) AVCaptureMetadataOutput *output;
+@property (nonatomic,strong) AVCaptureSession *session;
+@property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewLayer;
+
+@property (nonatomic,assign) BOOL scannerEnable;
+@property (nonatomic,assign) BOOL scannerInitial;
+
+@property (nonatomic,strong) CAGradientLayer *scanLineLayer;
+@property (nonatomic,strong) CAShapeLayer *maskLayer;
+@property (nonatomic,strong) CAShapeLayer *rectLayer;
+
+@end
+
+@implementation RAQRCodeScannerViewController
+
++ (NSString *)storyboardID {
+    return NSStringFromClass([self class]);
+}
+
++ (instancetype)viewControllerFromStoryboard {
+    RAQRCodeScannerViewController *scannerVC = [[UIStoryboard storyboardWithName:@"QRCode" bundle:nil] instantiateViewControllerWithIdentifier:[self storyboardID]];
+    return scannerVC;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    
+    self.scanerView.layer.borderColor = [UIColor blackColor].CGColor;
+    self.scanerView.layer.borderWidth = 0.5f;
+    
+    UIImage *normal_img = [self.class imageWithColor:[UIColor redColor] Size:CGSizeMake(60, 60)];
+    UIImage *highlight_img = [self.class imageWithColor:[UIColor greenColor] Size:CGSizeMake(60, 60)];
+    
+    [self.scanBtn setImage:normal_img forState:UIControlStateNormal];
+    [self.scanBtn setImage:highlight_img forState:UIControlStateHighlighted];
+    
+    if ([self camerAuthorization]) {
+        
+        [self initCapture];
+        
+    } else {
+        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
+            
+            dispatch_async(dispatch_get_main_queue(), ^{
+                
+                if (granted) {
+                    
+                    [self initCapture];
+                    [self resetPreview];
+                    
+                    if (![self.session isRunning]) {
+                        [self.session startRunning];
+                    }
+                    
+                } else {
+                    
+                    NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
+                    NSString *appName = [infoDict objectForKey:@"CFBundleDisplayName"];
+                    __weak typeof(self) weakSelf = self;
+                    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert];
+                    UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+                        [weakSelf dismissViewControllerAnimated:YES completion:nil];
+                    }];
+                    [alert addAction:action];
+                    [self presentViewController:alert animated:YES completion:nil];
+                    
+                }
+                
+            });
+            
+        }];
+    }
+}
+
+//- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
+//    return UIInterfaceOrientationPortrait;
+//}
+
+- (AVCaptureVideoOrientation)captureVideoOrientation {
+    AVCaptureVideoOrientation result;
+    
+    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
+    switch (deviceOrientation) {
+        case UIDeviceOrientationPortrait:
+        case UIDeviceOrientationFaceUp:
+        case UIDeviceOrientationFaceDown:
+            result = AVCaptureVideoOrientationPortrait;
+            break;
+        case UIDeviceOrientationPortraitUpsideDown:
+            //如果这里设置成AVCaptureVideoOrientationPortraitUpsideDown,则视频方向和拍摄时的方向是相反的。
+            result = AVCaptureVideoOrientationPortrait;
+            break;
+        case UIDeviceOrientationLandscapeLeft:
+            result = AVCaptureVideoOrientationLandscapeRight;
+            break;
+        case UIDeviceOrientationLandscapeRight:
+            result = AVCaptureVideoOrientationLandscapeLeft;
+            break;
+        default:
+            result = AVCaptureVideoOrientationPortrait;
+            break;
+    }
+    
+    return result;
+}
+
+- (void)viewDidLayoutSubviews {
+    [super viewDidLayoutSubviews];
+    
+    [self resetPreview];
+}
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    
+//    NSLog(@"device orientation: %ld & statusbar orientaion: %ld",[UIDevice currentDevice].orientation,[UIApplication sharedApplication].statusBarOrientation);
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+    
+    if (self.scannerInitial) {
+        [self.session startRunning];
+    }
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    
+    if ([self.session isRunning]) {
+        [self.session stopRunning];
+    }
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+- (void)resetPreview {
+    
+    self.previewLayer.frame = self.previewContainer.bounds;
+    AVCaptureVideoOrientation orientation = [self captureVideoOrientation];
+    if (self.previewLayer.connection.isVideoOrientationSupported) {
+        self.previewLayer.connection.videoOrientation = orientation;
+    }
+    
+    CGFloat w = CGRectGetWidth(self.previewContainer.bounds);
+    CGFloat h = CGRectGetHeight(self.previewContainer.bounds);
+    
+    /**
+     rectOfInterest
+     竖屏 x轴和y轴要交换一下
+     Left、Right:Home键反方向X为0
+     */
+    CGRect rect = CGRectMake(CGRectGetMinY(self.scanerView.frame) / h, CGRectGetMinX(self.scanerView.frame) / w, CGRectGetHeight(self.scanerView.frame) / h, CGRectGetWidth(self.scanerView.frame) / w);
+    if (orientation == AVCaptureVideoOrientationLandscapeRight) {
+        
+        rect = CGRectMake(CGRectGetMinX(self.scanerView.frame) / w, CGRectGetMinY(self.scanerView.frame) / h, CGRectGetWidth(self.scanerView.frame) / w,CGRectGetHeight(self.scanerView.frame) / h);
+        
+    } else if (orientation == AVCaptureVideoOrientationLandscapeLeft){
+        
+        rect = CGRectMake(1 - CGRectGetMaxX(self.scanerView.frame) / w, 1 - CGRectGetMaxY(self.scanerView.frame) / h, CGRectGetWidth(self.scanerView.frame) / w,CGRectGetHeight(self.scanerView.frame) / h);
+        
+    } else {
+        
+        rect = CGRectMake(CGRectGetMinY(self.scanerView.frame) / h, CGRectGetMinX(self.scanerView.frame) / w, CGRectGetHeight(self.scanerView.frame) / h, CGRectGetWidth(self.scanerView.frame) / w);
+    }
+    
+    [self.output setRectOfInterest:rect];
+    
+    [self.view bringSubviewToFront:self.scanerView];
+    
+    CGRect scanlineFrame = CGRectMake(0, CGRectGetMidY(self.scanerView.bounds) - 0.5, CGRectGetWidth(self.scanerView.bounds), 1);
+    self.scanLineLayer.frame = scanlineFrame;
+    [self.scanerView.layer insertSublayer:self.scanLineLayer atIndex:0];
+    
+    
+    UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.maskView.bounds];
+    UIBezierPath *subPath = [UIBezierPath bezierPathWithRect:self.scanerView.frame];
+    [path appendPath:subPath];
+    
+    if (!self.maskLayer) {
+        self.maskLayer = [CAShapeLayer layer];
+        self.maskLayer.fillColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.5].CGColor;
+        self.maskLayer.fillRule = kCAFillRuleEvenOdd;
+    }
+    self.maskLayer.path = path.CGPath;
+    
+    if (!self.rectLayer) {
+        self.rectLayer = [CAShapeLayer layer];
+        self.rectLayer.fillColor = [UIColor clearColor].CGColor;
+        self.rectLayer.strokeColor = [UIColor whiteColor].CGColor;
+        self.rectLayer.lineWidth = 0.5f;
+    }
+    self.rectLayer.path = subPath.CGPath;
+    
+    [self.maskLayer addSublayer:self.rectLayer];
+    [self.maskView.layer addSublayer:self.maskLayer];
+}
+
+- (CAGradientLayer *)scanLineLayer {
+    if (!_scanLineLayer) {
+        CAGradientLayer *gradientLayer = [CAGradientLayer layer];
+        //set gradient colors
+        // 数组成员接受 CGColorRef 类型的值
+        gradientLayer.colors = @[(__bridge id)[UIColor colorWithRed:1 green:0 blue:0 alpha:0.2].CGColor,(__bridge id)[UIColor redColor].CGColor,(__bridge id)[UIColor colorWithRed:1 green:0 blue:0 alpha:0.2].CGColor];
+        
+        gradientLayer.locations = @[@2.5,@0.5,@0.75];
+
+        gradientLayer.startPoint = CGPointMake(0, 0);
+        gradientLayer.endPoint = CGPointMake(1, 0);
+        _scanLineLayer = gradientLayer;
+    }
+    return _scanLineLayer;
+}
+
+#pragma mark - Init
+
+- (void)initCapture {
+    
+    self.scannerInitial = NO;
+    
+    if (![self camerAuthorization]) {
+        
+        NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
+        NSString *appName = [infoDict objectForKey:@"CFBundleDisplayName"];
+        __weak typeof(self) weakSelf = self;
+        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert];
+        UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+            [weakSelf dismissViewControllerAnimated:YES completion:nil];
+        }];
+        [alert addAction:action];
+        [self presentViewController:alert animated:YES completion:nil];
+        
+        return;
+    }
+    
+    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
+    
+    NSError *inputError;
+    self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&inputError];
+    
+    if (inputError) {
+        NSLog(@"init scanner input error: %@",inputError);
+        return;
+    }
+    
+    self.session = [[AVCaptureSession alloc] init];
+    [self.session setSessionPreset:AVCaptureSessionPresetHigh];
+    if ([self.session canAddInput:self.input]) {
+        [self.session addInput:self.input];
+    } else {
+        NSLog(@"init scanner can't add input");
+        return;
+    }
+    
+    self.output = [[AVCaptureMetadataOutput alloc] init];
+    [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
+    
+    if ([self.session canAddOutput:self.output]) {
+        [self.session addOutput:self.output];
+    } else {
+        NSLog(@"init scanner can't add output");
+        return;
+    }
+    self.output.metadataObjectTypes = @[
+                                        AVMetadataObjectTypeQRCode,
+                                        AVMetadataObjectTypeEAN13Code,
+                                        AVMetadataObjectTypeEAN8Code,
+                                        AVMetadataObjectTypeUPCECode,
+                                        AVMetadataObjectTypeCode39Code,
+                                        AVMetadataObjectTypeCode39Mod43Code,
+                                        AVMetadataObjectTypeCode93Code,
+                                        AVMetadataObjectTypeCode128Code,
+                                        AVMetadataObjectTypePDF417Code
+                                        ];
+    
+    self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
+    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
+    [self.previewContainer.layer addSublayer:self.previewLayer];
+    
+    self.scannerInitial = YES;
+}
+
+- (BOOL)camerAuthorization {
+    
+    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
+    if (status == AVAuthorizationStatusRestricted || status == AVAuthorizationStatusDenied) {
+        return NO;
+    }
+    return YES;
+}
+
+#pragma mark - AVCaptureMetadataOutputObjectsDelegate
+
+- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
+    
+    if (!self.scannerEnable) {
+        return;
+    }
+    
+    if ([metadataObjects count] > 0) {
+        [self.session stopRunning];
+        
+        AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];
+        NSString *codeValue = metadataObject.stringValue;
+        if (self.completion) {
+            self.completion(codeValue);
+        }
+        [self.navigationController popViewControllerAnimated:YES];
+    }
+    
+}
+
+#pragma mark - Action
+
+- (IBAction)scannerBtnTouchDown:(UIButton *)sender {
+    self.scannerEnable = YES;
+}
+
+- (IBAction)scannerBtnTouchUp:(UIButton *)sender {
+    self.scannerEnable = NO;
+}
+
+- (IBAction)scannerBtnTouchUpOutSide:(UIButton *)sender {
+    self.scannerEnable = NO;
+}
+
+- (IBAction)scannerBtnTouchCancel:(UIButton *)sender {
+    self.scannerEnable = NO;
+}
+
+#pragma mark - Utils
+
++ (UIImage *)imageWithColor:(UIColor *)color Size:(CGSize)size {
+    
+    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
+    CGContextRef ctx = UIGraphicsGetCurrentContext();
+    CGContextAddEllipseInRect(ctx, CGRectMake(5, 5, size.width - 10, size.height - 10));
+    CGContextSetFillColorWithColor(ctx, color.CGColor);
+    CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
+    CGContextSetLineWidth(ctx, 3.0f);
+    CGContextDrawPath(ctx, kCGPathFillStroke);
+    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    
+    return img;
+}
+
+
+@end

+ 23 - 0
common/UIImage/UIImage+RedAnt.h

@@ -0,0 +1,23 @@
+//
+//  UIImage+RedAnt.h
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/8/29.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIImage (RedAnt)
+
++ (instancetype)ra_imageWithURL:(NSURL *)url;
+
++ (NSString *)imageCacheDir;
+
++ (NSString *)imageCachePath:(NSString *)url;
+
++ (UIImage *)img_compress:(UIImage*)image kbsize:(float) size;
+
++ (UIImage *)scaleImageToSize:(UIImage *)img size:(CGSize)size;
+
+@end

+ 135 - 0
common/UIImage/UIImage+RedAnt.m

@@ -0,0 +1,135 @@
+//
+//  UIImage+RedAnt.m
+//  Apex And Drivers
+//
+//  Created by Jack on 2018/8/29.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#import "UIImage+RedAnt.h"
+#import <CommonCrypto/CommonCrypto.h>
+
+static dispatch_semaphore_t _lock;
+
+#define Lock() dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER)
+#define Unlock() dispatch_semaphore_signal(_lock)
+
+@implementation UIImage (RedAnt)
+
++ (void)load {
+    _lock = dispatch_semaphore_create(1);
+}
+
++ (instancetype)ra_imageWithURL:(NSURL *)url {
+    
+    if (url == nil) {
+        return nil;
+    }
+    
+    if ([url.scheme isEqualToString:@"file"]) {
+        return [UIImage imageWithContentsOfFile:url.absoluteString];
+    }
+    
+    NSString *md5 = [self md5:url.absoluteString];
+    
+    NSString *imgDir = [self imageCacheDir];
+    NSString *imgPath = [imgDir stringByAppendingPathComponent:md5];
+    
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    
+    BOOL isDir = NO;
+    BOOL exist = [fileManager fileExistsAtPath:imgPath isDirectory:&isDir];
+    
+    if (exist && !isDir) {
+        return [UIImage imageWithContentsOfFile:imgPath];
+    } else {
+        
+        NSData *imgData = [NSData dataWithContentsOfURL:url];
+        
+        exist = [fileManager fileExistsAtPath:imgDir isDirectory:&isDir];
+        if ((exist && isDir) || !exist) {
+            [fileManager createDirectoryAtPath:imgDir withIntermediateDirectories:YES attributes:nil error:nil];
+        }
+        
+        UIImage *img = [UIImage imageWithData:imgData];
+        if (img) { // 解析图片成功
+            Lock();
+            if (![fileManager fileExistsAtPath:imgPath]) {
+                [imgData writeToFile:imgPath atomically:NO];
+            }
+            Unlock();
+            
+            return img;
+        } else {
+            return nil;
+        }
+    }
+}
+
++ (NSString *)imageCacheDir {
+    return [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"ImageCache"];
+}
+
++ (NSString *)imageCachePath:(NSString *)url {
+    
+    NSString *md5 = [self md5:url];
+    
+    NSString *imgDir = [self imageCacheDir];
+    NSString *imgPath = [imgDir stringByAppendingPathComponent:md5];
+    
+    return imgPath;
+}
+
++ (nullable NSString *)md5:(nullable NSString *)str {
+    if (!str) return nil;
+    
+    const char *cStr = str.UTF8String;
+    unsigned char result[CC_MD5_DIGEST_LENGTH];
+    CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
+    
+    NSMutableString *md5Str = [NSMutableString string];
+    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) {
+        [md5Str appendFormat:@"%02x", result[i]];
+    }
+    return md5Str;
+}
+
++ (UIImage *)img_compress:(UIImage*)image kbsize:(float) size {
+    
+    
+    
+    //UIImage *image=[UIImage imageNamed:@"xxoo.jpeg"];
+    NSData  *imageData=UIImageJPEGRepresentation(image, 1.f);
+    
+    if(size>imageData.length/1024)
+        return image;
+    
+    //   CGFloat size=40.f;// kb
+    CGFloat scale=size/(imageData.length/1024);
+    
+    scale = sqrt (scale);
+    
+    CGSize newsize=image.size;
+    newsize.height = newsize.height*scale;
+    newsize.width = newsize.width*scale;
+    
+    return [self scaleImageToSize:image size:newsize];
+}
+
++ (UIImage *)scaleImageToSize:(UIImage *)img size:(CGSize)size {
+    // 创建一个bitmap的context
+    // 并把它设置成为当前正在使用的context
+    UIGraphicsBeginImageContext(size);
+    // 绘制改变大小的图片
+    [img drawInRect:CGRectMake(0, 0, size.width, size.height)];
+    // 从当前context中创建一个改变大小后的图片
+    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
+    // 使当前的context出堆栈
+    UIGraphicsEndImageContext();
+    // 返回新的改变大小后的图片
+    
+    //   NSData  *imageData=UIImageJPEGRepresentation(scaledImage, 1.f);
+    return scaledImage;
+}
+
+@end

+ 15 - 0
common/UIScrollVIew+Empty/RAEmptyDataView.h

@@ -0,0 +1,15 @@
+//
+//  RAEmptyDataView.h
+//  UIScrollViewEmpty
+//
+//  Created by Jack on 2018/9/5.
+//  Copyright © 2018年 United Software Applications. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface RAEmptyDataView : UIView
+
+@property (nonatomic,strong) UIView *emptyView;
+
+@end

+ 107 - 0
common/UIScrollVIew+Empty/RAEmptyDataView.m

@@ -0,0 +1,107 @@
+//
+//  RAEmptyDataView.m
+//  UIScrollViewEmpty
+//
+//  Created by Jack on 2018/9/5.
+//  Copyright © 2018年 United Software Applications. All rights reserved.
+//
+
+#import "RAEmptyDataView.h"
+
+@implementation RAEmptyDataView
+
+#pragma mark - Initial
+
+- (instancetype)init {
+    if (self = [super init]) {
+        self.backgroundColor = [UIColor clearColor];
+//        self.translatesAutoresizingMaskIntoConstraints = NO;
+    }
+    return self;
+}
+
+- (void)setFrame:(CGRect)frame {
+    [super setFrame:frame];
+}
+
+- (void)didMoveToSuperview {
+    [super didMoveToSuperview];
+    self.frame = self.superview.bounds;
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+    [super willMoveToSuperview:newSuperview];
+}
+
+- (void)setHidden:(BOOL)hidden {
+    [super setHidden:hidden];
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    if (self.emptyView) {
+        
+        CGFloat w = self.bounds.size.width;
+        CGFloat h = self.bounds.size.height;
+        CGFloat emptyW = self.emptyView.bounds.size.width;
+        CGFloat emptyH = self.emptyView.bounds.size.height;
+        
+        CGFloat x = (w - emptyW) * 0.5;
+        CGFloat y = (h - emptyH) * 0.5;
+        self.emptyView.frame = CGRectMake(x, y, emptyW, emptyH);
+    }
+}
+
+- (void)clear {
+    NSArray *subviews = self.subviews;
+    if (subviews && subviews.count > 0) {
+        for (UIView *subview in subviews) {
+            [subview removeFromSuperview];
+        }
+    }
+}
+
+- (void)setEmptyView:(UIView *)emptyView {
+    _emptyView = emptyView;
+    
+    [self clear];
+    [self addSubview:_emptyView];
+
+//    NSLayoutConstraint *enterX = [NSLayoutConstraint constraintWithItem:_emptyView
+//                                                             attribute:NSLayoutAttributeCenterX
+//                                                             relatedBy:NSLayoutRelationEqual
+//                                                                toItem:self
+//                                                             attribute:NSLayoutAttributeCenterX
+//                                                            multiplier:1
+//                                                              constant:0];
+//
+//    NSLayoutConstraint *enterY = [NSLayoutConstraint constraintWithItem:_emptyView
+//                                                              attribute:NSLayoutAttributeCenterY
+//                                                              relatedBy:NSLayoutRelationEqual
+//                                                                 toItem:self
+//                                                              attribute:NSLayoutAttributeCenterY
+//                                                             multiplier:1
+//                                                               constant:0];
+//
+//    NSLayoutConstraint *w = [NSLayoutConstraint constraintWithItem:_emptyView
+//                                                              attribute:NSLayoutAttributeWidth
+//                                                              relatedBy:NSLayoutRelationEqual
+//                                                                 toItem:nil
+//                                                              attribute:NSLayoutAttributeNotAnAttribute
+//                                                             multiplier:1
+//                                                               constant:100];
+//
+//    NSLayoutConstraint *h = [NSLayoutConstraint constraintWithItem:_emptyView
+//                                                              attribute:NSLayoutAttributeHeight
+//                                                              relatedBy:NSLayoutRelationEqual
+//                                                                 toItem:nil
+//                                                              attribute:NSLayoutAttributeNotAnAttribute
+//                                                             multiplier:1
+//                                                               constant:70];
+//
+//
+//    [self addConstraints:@[enterX,enterY,w,h]];
+}
+
+@end

+ 19 - 0
common/UIScrollVIew+Empty/UIScrollView+Empty.h

@@ -0,0 +1,19 @@
+//
+//  UIScrollView+Empty.h
+//  UIScrollViewEmpty
+//
+//  Created by Jack on 2018/9/5.
+//  Copyright © 2018年 United Software Applications. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface UIScrollView (Empty)
+
+@property (nonatomic,strong) UIView *emptyView;
+
+- (void)showEmpty;
+
+- (void)hideEmpty;
+
+@end

+ 76 - 0
common/UIScrollVIew+Empty/UIScrollView+Empty.m

@@ -0,0 +1,76 @@
+//
+//  UIScrollView+Empty.m
+//  UIScrollViewEmpty
+//
+//  Created by Jack on 2018/9/5.
+//  Copyright © 2018年 United Software Applications. All rights reserved.
+//
+
+#import "UIScrollView+Empty.h"
+#import "RAEmptyDataView.h"
+#import <objc/runtime.h>
+
+static const char *emptyKey = "emptyKey";
+
+static const float duration = 0.25;
+
+@implementation UIScrollView (Empty)
+
+- (void)setEmptyContentView:(RAEmptyDataView *)contentView {
+    if (contentView) {
+        UIView *view = objc_getAssociatedObject(self, emptyKey);
+        if (view) {
+            [view removeFromSuperview];
+        }
+        
+        [self insertSubview:contentView atIndex:0];
+        
+        [self willChangeValueForKey:@"emptyView"];
+        objc_setAssociatedObject(self, emptyKey, contentView, OBJC_ASSOCIATION_RETAIN);
+        [self didChangeValueForKey:@"emptyView"];
+    }
+}
+
+- (RAEmptyDataView *)emptyContentView {
+    
+    RAEmptyDataView *contentView = objc_getAssociatedObject(self, emptyKey);
+    
+    if (!contentView) {
+        contentView = [RAEmptyDataView new];
+        contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
+        contentView.hidden = YES;
+        
+        [self setEmptyContentView:contentView];
+    }
+    
+    return contentView;
+}
+
+- (void)setEmptyView:(UIView *)emptyView {
+    [self emptyContentView].emptyView = emptyView;
+}
+
+- (UIView *)emptyView {
+    return [self emptyContentView].emptyView;
+}
+
+- (void)showEmpty {
+    UIView *view = [self emptyContentView];
+//    view.alpha = 0.0f;
+    view.hidden = NO;
+    
+//    [UIView animateWithDuration:duration animations:^{
+//        view.alpha = 1.0f;
+//    }];
+}
+
+- (void)hideEmpty {
+    UIView *view = [self emptyContentView];
+//    [UIView animateWithDuration:duration animations:^{
+//        view.alpha = 0.0f;
+//    } completion:^(BOOL finished) {
+        view.hidden = YES;
+//    }];
+}
+
+@end