소스 검색

1.从Apex Drivers中抽取工具类图像预览。

Pen Li 7 년 전
부모
커밋
ee697b0129

+ 16 - 0
common/InfinitePhoto/Controller/RAPhotoPreviewController.h

@@ -0,0 +1,16 @@
+//
+//  NewPhotoPreviewController.h
+//  RA Image
+//
+//  Created by Jack on 2017/6/14.
+//  Copyright © 2017年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "RAPhotoDelegate.h"
+
+@interface RAPhotoPreviewController : UIViewController
+
++ (instancetype)ra_photoPreviewControllerWithPhotoItems:(NSArray<id<RAPhotoItemDelegate>> *)items offset:(NSUInteger)offset;
+
+@end

+ 231 - 0
common/InfinitePhoto/Controller/RAPhotoPreviewController.m

@@ -0,0 +1,231 @@
+//
+//  NewPhotoPreviewController.m
+//  RA Image
+//
+//  Created by Jack on 2017/6/14.
+//  Copyright © 2017年 USAI. All rights reserved.
+//
+
+#import "RAPhotoPreviewController.h"
+#import "PhotoPreviewCell.h"
+
+@interface RAPhotoPreviewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
+
+@property (nonatomic,assign) NSUInteger currentIndex;
+@property (strong, nonatomic) IBOutlet UILabel *indicator;
+@property (strong, nonatomic) IBOutlet UICollectionView *previewContainer;
+
+
+@property (nonatomic,strong) NSArray<id<RAPhotoItemDelegate>> *photos;
+@property (nonatomic,assign) NSUInteger offset;
+
+@property (nonatomic,assign) BOOL hideNavigationBar;
+
+@end
+
+@implementation RAPhotoPreviewController
+
++ (instancetype)ra_photoPreviewControllerWithPhotoItems:(NSArray<id<RAPhotoItemDelegate>> *)items offset:(NSUInteger)offset {
+    
+    RAPhotoPreviewController *vc = [[UIStoryboard storyboardWithName:@"PhotoList" bundle:nil] instantiateViewControllerWithIdentifier:@"RAPhotoPreviewController"];
+    if (offset == 0 || offset >= items.count) {
+        vc.photos = items;
+    } else {
+        NSMutableArray<id<RAPhotoItemDelegate>> *tmpArr = [NSMutableArray array];
+        [tmpArr addObjectsFromArray:[items subarrayWithRange:NSMakeRange(offset, items.count - offset)]];
+        for (int i = 0; i < offset; i++) {
+            id<RAPhotoItemDelegate> model = [items objectAtIndex:i];
+            [tmpArr addObject:model];
+        }
+        items = [tmpArr copy];
+        vc.photos = items;
+    }
+    vc.offset = 0;
+    
+    return vc;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    if (@available(iOS 11, *)) {
+        self.previewContainer.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+    } else {
+        self.automaticallyAdjustsScrollViewInsets = NO;
+    }
+    
+    self.indicator.layer.cornerRadius = 20;
+    self.indicator.layer.masksToBounds = YES;
+    
+    self.previewContainer.pagingEnabled = YES;
+    NSString *offset = [NSString stringWithFormat:@"%lu / %lu",(unsigned long)self.currentIndex + 1,(unsigned long)self.photos.count];
+    self.indicator.text = offset;
+   
+    self.hideNavigationBar = self.navigationController.isNavigationBarHidden;
+    
+    self.navigationController.navigationBarHidden = YES;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+}
+
+- (void)viewDidLayoutSubviews {
+    [super viewDidLayoutSubviews];
+
+   [self.previewContainer setContentOffset:CGPointMake((self.currentIndex + 1) * CGRectGetWidth(self.previewContainer.frame), 0) animated:NO];
+
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+}
+
+- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
+    
+    // 重新布局 Item 大小
+    [self.previewContainer.collectionViewLayout invalidateLayout];
+}
+
+- (BOOL)prefersStatusBarHidden {
+    return YES;
+}
+
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+    // Dispose of any resources that can be recreated.
+}
+
+#pragma mark - Setter
+
+- (void)setOffset:(NSUInteger)offset {
+    [self setCurrentIndex:offset];
+}
+
+#pragma mark - FlowLayout Delegate
+
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
+    return collectionView.bounds.size;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
+    return 0;
+}
+
+- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
+    return 0;
+}
+
+- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
+    return UIEdgeInsetsZero;
+}
+
+#pragma mark - CollectionView Delegate
+
+- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
+
+    NSUInteger idx = [self contentOffsetForIndexPath:indexPath];
+    
+    PhotoPreviewCell *preCell = (PhotoPreviewCell *)cell;
+    
+    id<RAPhotoItemDelegate> model = [self.photos objectAtIndex:idx];
+    preCell.model = model;
+}
+
+#pragma mark - CollectionView DataSource
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    if ([self.photos count] == 0) {
+        return 0;
+    }
+    return self.photos.count + 2;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    
+    PhotoPreviewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PhotoPreviewCell" forIndexPath:indexPath];
+    cell.scrollView.delegate = self;
+    return cell;
+}
+
+#pragma mark - ScrollView Delegate
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+    CGFloat offsetX = scrollView.contentOffset.x;
+    float idxf = offsetX / CGRectGetWidth(scrollView.frame);
+    int idxi = (int)(offsetX / CGRectGetWidth(scrollView.frame));
+    
+    if (idxf == idxi) {
+        if (idxi == 0) {
+            self.currentIndex = self.photos.count - 1;
+        } else if (idxi == self.photos.count + 1) {
+            self.currentIndex = 0;
+        } else {
+            self.currentIndex = idxi - 1;
+        }
+
+        [self updateIndicator];
+    } else {
+
+    }
+    
+    if (idxi == 0) {
+        [self scrollToIndex:self.photos.count];
+    }
+    
+    if (idxi == self.photos.count + 1) {
+        [self scrollToIndex:1];
+    }
+    
+}
+
+- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
+    if (scrollView != self.previewContainer) {
+        return scrollView.subviews.firstObject;
+    }
+    return nil;
+}
+
+- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
+    
+    if (self.previewContainer != scrollView) {
+        
+    }
+}
+
+#pragma mark - Private
+
+- (void)updateIndicator {
+    NSString *offset = [NSString stringWithFormat:@"%lu / %lu",(unsigned long)self.currentIndex + 1,(unsigned long)self.photos.count];
+    self.indicator.text = offset;
+}
+
+- (NSUInteger)contentOffsetForIndexPath:(NSIndexPath *)indexPath {
+    NSUInteger idx = indexPath.row;
+    if (idx == 0) {
+        idx = self.photos.count - 1;
+    }else if (idx == self.photos.count + 1) {
+        idx = 0;
+    } else {
+        idx = idx - 1;
+    }
+    return idx;
+}
+
+- (void)scrollToIndex:(NSUInteger)index { // 不会出现肉眼可见的滚动效果
+    self.previewContainer.contentOffset = CGPointMake(index * CGRectGetWidth(self.previewContainer.frame), 0);
+}
+
+- (IBAction)closeBtnClick:(UIButton *)sender {
+    
+    if (self.navigationController) {
+        self.navigationController.navigationBarHidden = self.hideNavigationBar;
+        [self.navigationController popViewControllerAnimated:YES];
+    } else {
+        [self dismissViewControllerAnimated:YES completion:nil];
+    }
+    
+}
+
+
+@end

+ 30 - 0
common/InfinitePhoto/Delegate/RAPhotoDelegate.h

@@ -0,0 +1,30 @@
+//
+//  RAPhotoDelegate.h
+//  APEX CRM
+//
+//  Created by Jack on 2018/11/28.
+//  Copyright © 2018年 USAI. All rights reserved.
+//
+
+#ifndef RAPhotoDelegate_h
+#define RAPhotoDelegate_h
+
+#import <UIKit/UIKit.h>
+
+@protocol RAPhotoItemUIDelegate <NSObject>
+
+@required
+- (void)refreshUI;
+- (void)unbind;
+
+@end
+
+@protocol RAPhotoItemDelegate <NSObject>
+
+@required
+@property (nonatomic,weak) id<RAPhotoItemUIDelegate> delegate;
+- (UIImage *)image;
+
+@end
+
+#endif /* RAPhotoDelegate_h */

+ 6 - 0
common/InfinitePhoto/RAPhotoPreview.xcassets/Contents.json

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

+ 23 - 0
common/InfinitePhoto/RAPhotoPreview.xcassets/btn_close.imageset/Contents.json

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

BIN
common/InfinitePhoto/RAPhotoPreview.xcassets/btn_close.imageset/ca1.png


BIN
common/InfinitePhoto/RAPhotoPreview.xcassets/btn_close.imageset/ca1@2x.png


BIN
common/InfinitePhoto/RAPhotoPreview.xcassets/btn_close.imageset/ca1@3x.png


+ 136 - 0
common/InfinitePhoto/Storyboard/PhotoList.storyboard

@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina5_5" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Photo Preview Controller-->
+        <scene sceneID="U3N-xr-7Rz">
+            <objects>
+                <viewController storyboardIdentifier="RAPhotoPreviewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="qZK-Vy-gaw" customClass="RAPhotoPreviewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="mc4-Qg-2g3"/>
+                        <viewControllerLayoutGuide type="bottom" id="0pB-uU-kJr"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="qtX-co-R7G">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="eUk-3I-LIa">
+                                <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                                <collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="AhJ-66-sid">
+                                    <size key="itemSize" width="414" height="735"/>
+                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
+                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
+                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                </collectionViewFlowLayout>
+                                <cells>
+                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="PhotoPreviewCell" id="eAR-El-bRn" customClass="PhotoPreviewCell">
+                                        <rect key="frame" x="0.0" y="0.66666666666666663" width="414" height="735"/>
+                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="735"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <subviews>
+                                                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" maximumZoomScale="3" translatesAutoresizingMaskIntoConstraints="NO" id="5Dl-d3-MLq">
+                                                    <rect key="frame" x="0.0" y="0.0" width="414" height="735"/>
+                                                    <subviews>
+                                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sni-z4-WnW">
+                                                            <rect key="frame" x="0.0" y="0.0" width="414" height="735"/>
+                                                            <subviews>
+                                                                <imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="0p1-c6-dGo">
+                                                                    <rect key="frame" x="0.0" y="0.0" width="414" height="735"/>
+                                                                </imageView>
+                                                            </subviews>
+                                                            <constraints>
+                                                                <constraint firstItem="0p1-c6-dGo" firstAttribute="centerY" secondItem="sni-z4-WnW" secondAttribute="centerY" id="8UX-6e-CRi"/>
+                                                                <constraint firstItem="0p1-c6-dGo" firstAttribute="centerX" secondItem="sni-z4-WnW" secondAttribute="centerX" id="Cw9-JE-ar8"/>
+                                                                <constraint firstItem="0p1-c6-dGo" firstAttribute="width" secondItem="sni-z4-WnW" secondAttribute="width" id="d0G-UK-DXO"/>
+                                                                <constraint firstItem="0p1-c6-dGo" firstAttribute="height" secondItem="sni-z4-WnW" secondAttribute="height" id="pjY-2k-kdy"/>
+                                                            </constraints>
+                                                        </view>
+                                                    </subviews>
+                                                    <constraints>
+                                                        <constraint firstItem="sni-z4-WnW" firstAttribute="top" secondItem="5Dl-d3-MLq" secondAttribute="top" id="3mP-Sy-8ZJ"/>
+                                                        <constraint firstItem="sni-z4-WnW" firstAttribute="centerX" secondItem="5Dl-d3-MLq" secondAttribute="centerX" id="4c9-Zy-NsD"/>
+                                                        <constraint firstItem="sni-z4-WnW" firstAttribute="centerY" secondItem="5Dl-d3-MLq" secondAttribute="centerY" id="GGY-7p-nOf"/>
+                                                        <constraint firstAttribute="trailing" secondItem="sni-z4-WnW" secondAttribute="trailing" id="PVO-l2-aPm"/>
+                                                        <constraint firstAttribute="bottom" secondItem="sni-z4-WnW" secondAttribute="bottom" id="WIV-ve-oT1"/>
+                                                        <constraint firstItem="sni-z4-WnW" firstAttribute="leading" secondItem="5Dl-d3-MLq" secondAttribute="leading" id="rd8-QD-VTS"/>
+                                                    </constraints>
+                                                </scrollView>
+                                            </subviews>
+                                        </view>
+                                        <constraints>
+                                            <constraint firstItem="5Dl-d3-MLq" firstAttribute="width" secondItem="eAR-El-bRn" secondAttribute="width" id="OwB-eR-E1R"/>
+                                            <constraint firstItem="5Dl-d3-MLq" firstAttribute="centerY" secondItem="eAR-El-bRn" secondAttribute="centerY" id="hQv-Uz-CBO"/>
+                                            <constraint firstItem="5Dl-d3-MLq" firstAttribute="centerX" secondItem="eAR-El-bRn" secondAttribute="centerX" id="nsu-Oh-hQQ"/>
+                                            <constraint firstItem="5Dl-d3-MLq" firstAttribute="height" secondItem="eAR-El-bRn" secondAttribute="height" id="wst-oN-7pA"/>
+                                        </constraints>
+                                        <size key="customSize" width="414" height="735"/>
+                                        <connections>
+                                            <outlet property="photoView" destination="0p1-c6-dGo" id="FII-Mz-9Qt"/>
+                                            <outlet property="scrollContentView" destination="sni-z4-WnW" id="hob-7H-hG5"/>
+                                            <outlet property="scrollView" destination="5Dl-d3-MLq" id="2Gj-Oc-6rO"/>
+                                        </connections>
+                                    </collectionViewCell>
+                                </cells>
+                                <connections>
+                                    <outlet property="dataSource" destination="qZK-Vy-gaw" id="2qY-wX-LI0"/>
+                                    <outlet property="delegate" destination="qZK-Vy-gaw" id="Fnz-nQ-4PE"/>
+                                </connections>
+                            </collectionView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1 / 8" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="x3F-Hb-jne">
+                                <rect key="frame" x="167" y="30" width="80" height="40"/>
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="80" id="4nS-MH-dz0"/>
+                                    <constraint firstAttribute="height" constant="40" id="jTZ-mK-h0Z"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0RT-6b-F9T">
+                                <rect key="frame" x="360" y="25" width="44" height="44"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="44" id="EfS-6B-vnU"/>
+                                    <constraint firstAttribute="width" constant="44" id="Usq-qx-7G1"/>
+                                </constraints>
+                                <state key="normal" image="btn_close"/>
+                                <connections>
+                                    <action selector="closeBtnClick:" destination="qZK-Vy-gaw" eventType="touchUpInside" id="JTL-8z-Gma"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="0RT-6b-F9T" secondAttribute="trailing" constant="10" id="1bv-tN-nCS"/>
+                            <constraint firstItem="0RT-6b-F9T" firstAttribute="top" secondItem="mc4-Qg-2g3" secondAttribute="bottom" constant="5" id="7h0-ww-k6I"/>
+                            <constraint firstItem="eUk-3I-LIa" firstAttribute="centerX" secondItem="qtX-co-R7G" secondAttribute="centerX" id="Occ-gY-Cbn"/>
+                            <constraint firstItem="x3F-Hb-jne" firstAttribute="top" secondItem="mc4-Qg-2g3" secondAttribute="bottom" constant="10" id="PCn-1c-2Pu"/>
+                            <constraint firstItem="x3F-Hb-jne" firstAttribute="centerX" secondItem="qtX-co-R7G" secondAttribute="centerX" id="Vpc-xd-gDa"/>
+                            <constraint firstItem="eUk-3I-LIa" firstAttribute="height" secondItem="qtX-co-R7G" secondAttribute="height" id="dad-0B-yAf"/>
+                            <constraint firstItem="eUk-3I-LIa" firstAttribute="width" secondItem="qtX-co-R7G" secondAttribute="width" id="nY6-mM-Sjc"/>
+                            <constraint firstItem="eUk-3I-LIa" firstAttribute="centerY" secondItem="qtX-co-R7G" secondAttribute="centerY" id="ygr-Ka-rvN"/>
+                        </constraints>
+                    </view>
+                    <connections>
+                        <outlet property="indicator" destination="x3F-Hb-jne" id="JGA-vq-BPK"/>
+                        <outlet property="previewContainer" destination="eUk-3I-LIa" id="TYz-ym-JNG"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="sWf-Id-XaR" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1871.0144927536232" y="50.54347826086957"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="btn_close" width="32" height="32"/>
+    </resources>
+</document>

+ 20 - 0
common/InfinitePhoto/View/PhotoPreviewCell.h

@@ -0,0 +1,20 @@
+//
+//  PhotoPreviewCell.h
+//  RA Image
+//
+//  Created by Jack on 2017/6/14.
+//  Copyright © 2017年 USAI. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "RAPhotoDelegate.h"
+
+@interface PhotoPreviewCell : UICollectionViewCell <RAPhotoItemUIDelegate>
+
+@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
+@property (strong, nonatomic) IBOutlet UIView *scrollContentView;
+@property (nonatomic,strong) IBOutlet UIImageView *photoView;
+
+@property (nonatomic,strong) id<RAPhotoItemDelegate> model;
+
+@end

+ 60 - 0
common/InfinitePhoto/View/PhotoPreviewCell.m

@@ -0,0 +1,60 @@
+//
+//  PhotoPreviewCell.m
+//  RA Image
+//
+//  Created by Jack on 2017/6/14.
+//  Copyright © 2017年 USAI. All rights reserved.
+//
+
+#import "PhotoPreviewCell.h"
+
+@implementation PhotoPreviewCell
+
+- (void)setModel:(id<RAPhotoItemDelegate>)model {
+    if (_model) {
+        _model.delegate = nil;
+    }
+    _model = model;
+    [_model.delegate unbind];
+    _model.delegate = self;
+    
+    [self refreshUI];
+}
+
+- (void)setPhoto:(UIImage *)image {
+    if (self.photoView) {
+        self.photoView.image = image;
+    }
+}
+
+- (void)prepareForReuse {
+    [super prepareForReuse];
+
+    
+    UIScrollView *sc = self.scrollView;
+    sc.zoomScale = 1;
+    sc.contentSize = CGSizeZero;
+    sc.contentOffset = CGPointZero;
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+}
+
+#pragma mark - UIDelegate
+
+- (void)refreshUI {
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self setPhoto:self.model.image];
+    });
+}
+
+- (void)unbind {
+    _model.delegate = nil;
+    _model = nil;
+    [self refreshUI];
+}
+
+
+@end