├── .gitignore ├── 1.png ├── 2.png ├── 3.png ├── LICENSE.md ├── README.md ├── RSArticle.h ├── RSArticle.m ├── RSImageFitness ├── UIImage+Fitness.h └── UIImage+Fitness.m ├── RSReadingBoard.h ├── RSReadingBoard.m ├── RSReadingBoardSample ├── RSReadingBoardSample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── RSReadingBoardSample.xccheckout │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── RSReadingBoardSample.xcscheme └── RSReadingBoardSample │ ├── Body.txt │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ ├── clip0.imageset │ │ ├── Contents.json │ │ └── clip0@2x.png │ ├── clip1.imageset │ │ ├── Contents.json │ │ └── clip1@2x.png │ ├── clip2.imageset │ │ ├── Contents.json │ │ └── clip2@2x.png │ └── image.imageset │ │ ├── Contents.json │ │ └── image@2x.png │ ├── RSAppDelegate.h │ ├── RSAppDelegate.m │ ├── RSReadingBoardSample-Info.plist │ ├── RSReadingBoardSample-Prefix.pch │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── RSReadingBoard_iPad.xib ├── RSReadingBoard_iPhone.xib └── iPad_landscape.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | RSReadingBoardSample/RSReadingBoardSample.xcodeproj/xcuserdata/* 3 | 4 | RSReadingBoardSample/RSReadingBoardSample.xcodeproj/project.xcworkspace/xcuserdata/* 5 | 6 | RSReadingBoardSample/Podfile.lock 7 | 8 | RSReadingBoardSample/Pods/* 9 | 10 | RSReadingBoardSample/RSReadingBoardSample.xcworkspace/* 11 | -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/1.png -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/2.png -------------------------------------------------------------------------------- /3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/3.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2014 P.D.Q. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RSReadingBoard 2 | ============== 3 | 4 | [![Total views](https://sourcegraph.com/api/repos/github.com/yeahdongcn/RSReadingBoard/counters/views.png)](https://sourcegraph.com/github.com/yeahdongcn/RSReadingBoard) 5 | [![Views in the last 24 hours](https://sourcegraph.com/api/repos/github.com/yeahdongcn/RSReadingBoard/counters/views-24h.png)](https://sourcegraph.com/github.com/yeahdongcn/RSReadingBoard) 6 | 7 | RSReadingBoard is a ZAKER alike news/article reading board for iOS7 and demonstrates how to use Auto Layout. For iPhone only UIInterfaceOrientationMaskPortrait is supported and for iPad UIInterfaceOrientationMaskAllButUpsideDown is supported. 8 | 9 | Screen shots 10 | ------------ 11 | 12 | ####iPhone 13 | 14 | ![ScreenShot](https://github.com/yeahdongcn/RSReadingBoard/blob/master/1.png?raw=true)![ScreenShot](https://github.com/yeahdongcn/RSReadingBoard/blob/master/2.png?raw=true)![ScreenShot](https://github.com/yeahdongcn/RSReadingBoard/blob/master/3.png?raw=true) 15 | 16 | ####iPad 17 | 18 | ![ScreenShot](https://github.com/yeahdongcn/RSReadingBoard/blob/master/iPad_landscape.png?raw=true) 19 | 20 | Usage 21 | ------------ 22 | 1. Import `RSReadingBoard.h` `RSReadingBoard.m` and xib files into your project. 23 | 2. If you need custom layout go directly modify the xib file but do `NOT` change the relationships between the default controls. For example, you do not want the colour line view, set its width to `0`. 24 | 3. Import `RSReadingBoard.h` into your code, this header file has been well commented, try change these public properties to achieve your goal. 25 | 26 | License 27 | ------------ 28 | The MIT License (MIT) 29 | 30 | Copyright (c) 2012-2014 P.D.Q. 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy of 33 | this software and associated documentation files (the "Software"), to deal in 34 | the Software without restriction, including without limitation the rights to 35 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 36 | the Software, and to permit persons to whom the Software is furnished to do so, 37 | subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in all 40 | copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 44 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 45 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 46 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 47 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | 49 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/yeahdongcn/rsreadingboard/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 50 | 51 | -------------------------------------------------------------------------------- /RSArticle.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSArticle.h 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RSArticle : NSObject 12 | 13 | @property (nonatomic, strong) UIColor *color; 14 | 15 | @property (nonatomic, strong) UIImage *image; 16 | 17 | @property (nonatomic, strong) NSString *title; 18 | 19 | @property (nonatomic, strong) NSString *source; 20 | 21 | @property (nonatomic, strong) NSString *date; 22 | 23 | @property (nonatomic, strong) NSString *body; 24 | 25 | @property (nonatomic, strong) NSArray *clips; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /RSArticle.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSArticle.m 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSArticle.h" 10 | 11 | @implementation RSArticle 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /RSImageFitness/UIImage+Fitness.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Fitness.h 3 | // RSImageFitnessSample 4 | // 5 | // Created by R0CKSTAR on 3/28/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, RSHorizontalAlignment) { 12 | /** 13 | * H: Center align 14 | */ 15 | RSHorizontalAlignmentCenter = 0, 16 | /** 17 | * H: Left align 18 | */ 19 | RSHorizontalAlignmentLeft, 20 | /** 21 | * H: Right align 22 | */ 23 | RSHorizontalAlignmentRight, 24 | }; 25 | 26 | typedef NS_ENUM(NSUInteger, RSVerticalAlignment) { 27 | /** 28 | * V: Center align 29 | */ 30 | RSVerticalAlignmentCenter = 0, 31 | /** 32 | * 33 | */ 34 | RSVerticalAlignmentTop, 35 | /** 36 | * V: Bottom align 37 | */ 38 | RSVerticalAlignmentBottom, 39 | }; 40 | 41 | @interface UIImage (Fitness) 42 | 43 | /** 44 | * Create a new UIImage instance if its size NOT equals to the give size, 45 | * otherwise retrun the unchanged self. 46 | * 47 | * @param newSize Size of the new image 48 | * @param horizontalAlignment Horizontal alignment 49 | * @param verticalAlignment Vertical alignment 50 | * @param scale Scale of the new image 51 | * 52 | * @return UIImage instace 53 | */ 54 | - (UIImage *)imageWithNewSize:(CGSize)newSize 55 | horizontalAlignment:(RSHorizontalAlignment)horizontalAlignment 56 | verticalAlignment:(RSVerticalAlignment)verticalAlignment 57 | scale:(CGFloat)scale; 58 | 59 | /** 60 | * @NOTE: this function use RSHorizontalAlignmentCenter, RSVerticalAlignmentTop 61 | * and current screen scale. 62 | */ 63 | - (UIImage *)imageWithNewSize:(CGSize)newSize; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /RSImageFitness/UIImage+Fitness.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Fitness.m 3 | // RSImageFitnessSample 4 | // 5 | // Created by R0CKSTAR on 3/28/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "UIImage+Fitness.h" 10 | 11 | @implementation UIImage (Fitness) 12 | 13 | - (UIImage *)imageWithNewSize:(CGSize)newSize 14 | horizontalAlignment:(RSHorizontalAlignment)horizontalAlignment 15 | verticalAlignment:(RSVerticalAlignment)verticalAlignment 16 | scale:(CGFloat)scale 17 | { 18 | if (CGSizeEqualToSize(self.size, newSize) == NO) { 19 | CGFloat sourceWidth = self.size.width; 20 | CGFloat sourceHeight = self.size.height; 21 | CGFloat targetWidth = newSize.width; 22 | CGFloat targetHeight = newSize.height; 23 | CGFloat scaleFactor = 0.0f; 24 | CGFloat scaledWidth = targetWidth; 25 | CGFloat scaledHeight = targetHeight; 26 | CGPoint thumbnailPoint = CGPointMake(0.0f ,0.0f); 27 | 28 | CGFloat widthFactor = targetWidth / sourceWidth; 29 | CGFloat heightFactor = targetHeight / sourceHeight; 30 | 31 | if (widthFactor > heightFactor) { 32 | scaleFactor = widthFactor; // Fit height 33 | } else { 34 | scaleFactor = heightFactor; // Fit width 35 | } 36 | 37 | scaledWidth = sourceWidth * scaleFactor; 38 | scaledHeight = sourceHeight * scaleFactor; 39 | 40 | if (widthFactor > heightFactor) { 41 | switch (verticalAlignment) { 42 | case RSVerticalAlignmentCenter: 43 | // V: Center align 44 | thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 45 | break; 46 | case RSVerticalAlignmentTop: 47 | // V: Top align 48 | thumbnailPoint.y = 0; 49 | break; 50 | case RSVerticalAlignmentBottom: 51 | // V: Bottom align 52 | thumbnailPoint.y = targetHeight - scaledHeight; 53 | break; 54 | default: 55 | break; 56 | } 57 | } else if (widthFactor < heightFactor) { 58 | switch (horizontalAlignment) { 59 | case RSHorizontalAlignmentCenter: 60 | // H: Center align 61 | thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; 62 | break; 63 | case RSHorizontalAlignmentLeft: 64 | // H: Left align 65 | thumbnailPoint.x = 0; 66 | break; 67 | case RSHorizontalAlignmentRight: 68 | // H: Right align 69 | thumbnailPoint.x = targetWidth - scaledWidth; 70 | break; 71 | default: 72 | break; 73 | } 74 | } 75 | 76 | UIGraphicsBeginImageContextWithOptions(newSize, NO, scale); 77 | CGRect thumbnailRect = CGRectZero; 78 | thumbnailRect.origin = thumbnailPoint; 79 | thumbnailRect.size.width = scaledWidth; 80 | thumbnailRect.size.height = scaledHeight; 81 | [self drawInRect:thumbnailRect]; 82 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 83 | UIGraphicsEndImageContext(); 84 | 85 | return newImage; 86 | } 87 | return self; 88 | } 89 | 90 | - (UIImage *)imageWithNewSize:(CGSize)newSize 91 | { 92 | return [self imageWithNewSize:newSize 93 | horizontalAlignment:RSHorizontalAlignmentCenter 94 | verticalAlignment:RSVerticalAlignmentTop 95 | scale:[[UIScreen mainScreen] scale]]; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /RSReadingBoard.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSReadingBoard.h 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class RSArticle; 12 | 13 | @interface RSReadingBoard : UIViewController 14 | 15 | #pragma mark - Function 16 | 17 | /** 18 | * Whether enable drag to zoom in 19 | */ 20 | @property (nonatomic) BOOL enableImageDragZoomIn; // default is YES 21 | 22 | /** 23 | * Clip scale on tap 24 | */ 25 | @property (nonatomic) CGFloat scaleX; // default is 2.0f 26 | @property (nonatomic) CGFloat scaleY; // default is 2.0f 27 | 28 | #pragma mark - Appearance 29 | 30 | /** 31 | * Body text view background color 32 | */ 33 | @property (nonatomic, strong) UIColor *bodyBackgroundColor; // default is clear color 34 | 35 | /** 36 | * Body text view text color 37 | */ 38 | @property (nonatomic, strong) UIColor *bodyTextColor; // default is dark gray color 39 | 40 | /** 41 | * Body text view font 42 | */ 43 | @property (nonatomic, strong) UIFont *bodyFont; // default is body font 44 | 45 | #pragma mark - Model 46 | 47 | /** 48 | * Model object 49 | */ 50 | @property (nonatomic, strong) RSArticle *article; 51 | 52 | #pragma mark - Layout 53 | 54 | /** 55 | * Insets which controls the content area exclude the headline image 56 | */ 57 | @property (nonatomic) UIEdgeInsets contentInsets; // default is UIEdgeInsetsMake(60, 20, 20, 20) 58 | 59 | /** 60 | * Color view width layout constraint 61 | */ 62 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcvColorWidth; // default is 5 63 | 64 | /** 65 | * Horizontal space between color view and title label 66 | */ 67 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lchorizontalSpaceBetweenvColorlTitle; // default is 5 68 | 69 | /** 70 | * Horizontal space between source label and date label 71 | */ 72 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lchorizontalSpaceBetweenlSourcelDate; // default is 10 73 | 74 | /** 75 | * Vertical space between title label and source label & date label 76 | */ 77 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcVerticalSpaceBetweenlTitlelSource; // default is 10 78 | 79 | /** 80 | * Headline image width layout constraint 81 | */ 82 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcivImageWidth; 83 | 84 | /** 85 | * Headline image height layout constraint 86 | */ 87 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcivImageHeight; 88 | 89 | #pragma mark - Quick creation 90 | 91 | /** 92 | * Using default xib and bundle for initializing a reading board 93 | * 94 | * @return RSReadingBoard instance 95 | */ 96 | + (instancetype)board; 97 | 98 | /** 99 | * Using custom xib for initializing a reading board 100 | * 101 | * @param name Xib name 102 | * @param bundle Which bundle the xib file lives 103 | * 104 | * @return RSReadingBoard instance 105 | */ 106 | + (instancetype)boardWithWithNibName:(NSString *)name bundle:(NSBundle *)bundle; 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /RSReadingBoard.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSReadingBoard.m 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSReadingBoard.h" 10 | 11 | #import "RSArticle.h" 12 | 13 | // https://github.com/yeahdongcn/RSImageFitness 14 | #import "UIImage+Fitness.h" 15 | 16 | #ifdef UI_USER_INTERFACE_IDIOM 17 | #define IS_IPAD() (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 18 | #else 19 | #define IS_IPAD() (false) 20 | #endif 21 | 22 | #define PROPERTY_NAME(property) [[(@""#property) componentsSeparatedByString:@"."] lastObject] 23 | 24 | @interface RSClipView : UIImageView 25 | 26 | @end 27 | 28 | @implementation RSClipView 29 | 30 | @end 31 | 32 | @interface RSReadingBoard () 33 | 34 | @property (nonatomic, weak) IBOutlet UIScrollView *vContent; 35 | 36 | @property (nonatomic, weak) IBOutlet UIImageView *ivImage; 37 | @property (nonatomic) CGRect ivImageFrame; 38 | 39 | @property (nonatomic, weak) IBOutlet UIView *vColor; 40 | 41 | @property (nonatomic, weak) IBOutlet UILabel *lTitle; 42 | 43 | @property (nonatomic, weak) IBOutlet UILabel *lSource; 44 | 45 | @property (nonatomic, weak) IBOutlet UILabel *lDate; 46 | 47 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lclTitleTop; 48 | 49 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lclTitleTrailing; 50 | 51 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcvColorLeading; 52 | 53 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcivImageTrailing; 54 | 55 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcivImageTop; 56 | 57 | @property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcivImageBottom; 58 | 59 | @property (nonatomic, strong) NSLayoutManager *layoutManager; 60 | 61 | @property (nonatomic, strong) NSTextStorage *textStorage; 62 | 63 | @property (nonatomic, strong) NSMutableDictionary *oldConstants; 64 | 65 | @property (nonatomic, strong) NSMutableArray *clipViews; 66 | 67 | @property (nonatomic, strong) NSArray *clipViewsFrames; 68 | 69 | @property (nonatomic) NSUInteger lastPage; 70 | 71 | @end 72 | 73 | @implementation RSReadingBoard 74 | 75 | static NSString *const kReadingBoardNib_iPhone = @"RSReadingBoard_iPhone"; 76 | static NSString *const kReadingBoardNib_iPad = @"RSReadingBoard_iPad"; 77 | 78 | #pragma mark - Private methods 79 | 80 | - (CGFloat)widthForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 81 | { 82 | CGSize size = [UIScreen mainScreen].bounds.size; 83 | if (interfaceOrientation == UIInterfaceOrientationPortrait) { 84 | return size.width > size.height ? size.height : size.width; 85 | } else { 86 | return size.width > size.height ? size.width : size.height; 87 | } 88 | } 89 | 90 | - (void)layoutImageByInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 91 | { 92 | if (interfaceOrientation == UIInterfaceOrientationPortrait) { 93 | self.lcivImageWidth.constant = [self widthForInterfaceOrientation:UIInterfaceOrientationPortrait]; 94 | } else { 95 | self.lcivImageWidth.constant = roundf([self widthForInterfaceOrientation:UIInterfaceOrientationLandscapeLeft] / 2.0f); 96 | } 97 | self.lcivImageHeight.constant = roundf(self.lcivImageWidth.constant / 2.0f); 98 | 99 | [self.oldConstants setObject:@(self.lcivImageTop.constant) forKey:PROPERTY_NAME(self.lcivImageTop)]; 100 | [self.oldConstants setObject:@(self.lcivImageHeight.constant) forKey:PROPERTY_NAME(self.lcivImageHeight)]; 101 | } 102 | 103 | - (void)tap:(UITapGestureRecognizer *)tap 104 | { 105 | RSClipView *tappedClipView = (RSClipView *)tap.view; 106 | 107 | CGPoint center = CGPointZero; 108 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 109 | NSUInteger currentPage = roundf(self.vContent.contentOffset.y / (self.vContent.frame.size.height)); 110 | center = CGPointMake(self.vContent.center.x, self.vContent.center.y + self.vContent.bounds.size.height * currentPage); 111 | } else { 112 | NSUInteger currentPage = roundf(self.vContent.contentOffset.x / (self.vContent.frame.size.width)); 113 | center = CGPointMake(self.vContent.center.x + self.vContent.bounds.size.width * currentPage, self.vContent.center.y); 114 | } 115 | [UIView animateWithDuration:0.3f animations:^{ 116 | if (CGPointEqualToPoint(center, tappedClipView.center)) { 117 | tappedClipView.frame = [self.clipViewsFrames[tappedClipView.tag] CGRectValue]; 118 | } else { 119 | tappedClipView.center = center; 120 | tappedClipView.transform = CGAffineTransformScale(tappedClipView.transform, 121 | self.scaleX, self.scaleY); 122 | [self.vContent bringSubviewToFront:tappedClipView]; 123 | } 124 | }]; 125 | 126 | [UIView animateWithDuration:0.3f animations:^{ 127 | [self.clipViews enumerateObjectsUsingBlock:^(RSClipView *clipView, NSUInteger idx, BOOL *stop) { 128 | if (clipView != tappedClipView && CGPointEqualToPoint(center, clipView.center)) { 129 | clipView.frame = [self.clipViewsFrames[clipView.tag] CGRectValue]; 130 | if (!IS_IPAD()) { 131 | [self.vContent sendSubviewToBack:clipView]; 132 | } 133 | } 134 | }]; 135 | }]; 136 | } 137 | 138 | #pragma mark - Quick creation 139 | 140 | + (instancetype)board 141 | { 142 | NSString *name = kReadingBoardNib_iPhone; 143 | if (IS_IPAD()) { 144 | name = kReadingBoardNib_iPad; 145 | } 146 | return [self boardWithWithNibName:name bundle:[NSBundle mainBundle]]; 147 | } 148 | 149 | + (instancetype)boardWithWithNibName:(NSString *)name bundle:(NSBundle *)bundle 150 | { 151 | return [[bundle loadNibNamed:name owner:nil options:nil] firstObject]; 152 | } 153 | 154 | #pragma mark - NSObject 155 | 156 | - (id)initWithCoder:(NSCoder *)aDecoder 157 | { 158 | self = [super initWithCoder:aDecoder]; 159 | if (self) { 160 | self.scaleX = 3.0f; 161 | self.scaleY = 3.0f; 162 | 163 | self.contentInsets = UIEdgeInsetsMake(60, 20, 20, 20); 164 | 165 | self.enableImageDragZoomIn = YES; 166 | 167 | self.bodyBackgroundColor = [UIColor clearColor]; 168 | self.bodyTextColor = [UIColor darkGrayColor]; 169 | self.bodyFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 170 | } 171 | return self; 172 | } 173 | 174 | #pragma mark - UIViewController 175 | 176 | - (void)viewDidLoad 177 | { 178 | [super viewDidLoad]; 179 | 180 | /** 181 | * @NOTE: Turn off automatically adjusts scroll view insets in xib or here 182 | */ 183 | self.automaticallyAdjustsScrollViewInsets = NO; 184 | 185 | /** 186 | * @NOTE: Make sure the image view's content mode is aspect fill, set it in xib or here 187 | */ 188 | self.ivImage.contentMode = UIViewContentModeScaleAspectFill; 189 | 190 | /** 191 | * @NOTE: Enable content view's paging in xib or here 192 | */ 193 | self.vContent.pagingEnabled = YES; 194 | 195 | /** 196 | * @NOTE: Set content view's delegate in xib or here 197 | */ 198 | self.vContent.delegate = self; 199 | 200 | [self layoutImageByInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; 201 | 202 | [self.oldConstants setObject:@(self.lcvColorLeading.constant) forKey:PROPERTY_NAME(self.lcvColorLeading)]; 203 | [self.oldConstants setObject:@(self.lclTitleTrailing.constant) forKey:PROPERTY_NAME(self.lclTitleTrailing)]; 204 | 205 | [self.oldConstants setObject:@(self.lclTitleTop.constant) forKey:PROPERTY_NAME(self.lclTitleTop)]; 206 | [self.oldConstants setObject:@(self.lcVerticalSpaceBetweenlTitlelSource.constant) forKey:PROPERTY_NAME(self.lcVerticalSpaceBetweenlTitlelSource)]; 207 | if (self.lTitle.font) { 208 | [self.oldConstants setObject:self.lTitle.font forKey:[NSString stringWithFormat:@"%@%@", PROPERTY_NAME(self.lTitle), @"Font"]]; 209 | } 210 | if (self.lTitle.textColor) { 211 | [self.oldConstants setObject:self.lTitle.textColor forKey:[NSString stringWithFormat:@"%@%@", PROPERTY_NAME(self.lTitle), @"Color"]]; 212 | } 213 | } 214 | 215 | - (NSUInteger)supportedInterfaceOrientations 216 | { 217 | if (IS_IPAD()) { 218 | return UIInterfaceOrientationMaskAllButUpsideDown; 219 | } else { 220 | return UIInterfaceOrientationMaskPortrait; 221 | } 222 | } 223 | 224 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 225 | { 226 | // Reset last page flag 227 | self.lastPage = 0; 228 | 229 | self.lclTitleTop.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTop)] floatValue]; 230 | self.lcVerticalSpaceBetweenlTitlelSource.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcVerticalSpaceBetweenlTitlelSource)] floatValue]; 231 | self.lcvColorLeading.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcvColorLeading)] floatValue]; 232 | self.lclTitleTrailing.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTrailing)] floatValue]; 233 | 234 | self.lcivImageBottom.constant = 0; 235 | self.lcivImageTrailing.constant = 0; 236 | 237 | [self layoutImageByInterfaceOrientation:toInterfaceOrientation]; 238 | 239 | if (self.article) { 240 | self.article = self.article; 241 | } 242 | } 243 | 244 | #pragma mark - Setters 245 | 246 | - (void)setArticle:(RSArticle *)article 247 | { 248 | _article = article; 249 | 250 | dispatch_async(dispatch_get_main_queue(), ^{ 251 | // Header 252 | if (article.image) { 253 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 254 | UIImage *image = [article.image imageWithNewSize:CGSizeMake(self.lcivImageWidth.constant, self.lcivImageHeight.constant)]; 255 | dispatch_async(dispatch_get_main_queue(), ^{ 256 | self.ivImage.image = image; 257 | }); 258 | }); 259 | } else { 260 | self.ivImage.image = nil; 261 | self.lcivImageBottom.constant = 0; 262 | } 263 | self.lTitle.text = article.title; 264 | self.lSource.text = article.source; 265 | self.lDate.text = article.date; 266 | if (article.color) { 267 | self.vColor.backgroundColor = article.color; 268 | } else { 269 | self.vColor.backgroundColor = [UIColor clearColor]; 270 | } 271 | [self layoutHeader:NO]; 272 | 273 | // Body 274 | for (RSClipView *clipView in self.clipViews) { 275 | [clipView removeFromSuperview]; 276 | } 277 | [self.clipViews removeAllObjects]; 278 | 279 | if (article && article.clips) { 280 | [article.clips enumerateObjectsUsingBlock:^(UIImage *clip, NSUInteger idx, BOOL *stop) { 281 | RSClipView *clipView = [[RSClipView alloc] initWithImage:clip]; 282 | clipView.tag = idx; 283 | clipView.userInteractionEnabled = YES; 284 | [clipView sizeToFit]; 285 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]; 286 | [clipView addGestureRecognizer:tap]; 287 | [self.clipViews addObject:clipView]; 288 | [self.vContent addSubview:clipView]; 289 | }]; 290 | 291 | NSDictionary *attribute = @{NSFontAttributeName:self.bodyFont}; 292 | CGRect rect = [article.body boundingRectWithSize:CGSizeMake(self.vContent.bounds.size.width - self.contentInsets.left - self.contentInsets.right, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attribute context:nil]; 293 | NSUInteger pages = rect.size.height / self.vContent.bounds.size.height + ((NSInteger)rect.size.height % (NSInteger)self.vContent.bounds.size.height > 0 ? 1 : 0); 294 | NSUInteger numberOfClips = [article.clips count]; 295 | if (numberOfClips <= pages) { 296 | // One clip view at one page 297 | for (int i = 0; i < numberOfClips; i++) { 298 | CGRect frame = [self.clipViews[i] frame]; 299 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 300 | frame.origin.x = self.vContent.bounds.size.width - frame.size.width - self.contentInsets.right; 301 | frame.origin.y = self.vContent.bounds.size.height * ((i + 1) + 1) - frame.size.height - self.contentInsets.bottom; 302 | } else { 303 | frame.origin.x = self.vContent.bounds.size.width * ((i + 1) + 1) - frame.size.width - self.contentInsets.right; 304 | frame.origin.y = self.vContent.bounds.size.height - frame.size.height - self.contentInsets.bottom; 305 | } 306 | [self.clipViews[i] setFrame:frame]; 307 | } 308 | } else { 309 | // All clip views at (pages - 1) 310 | for (int i = 0; i < numberOfClips; i++) { 311 | CGRect frame = [self.clipViews[i] frame]; 312 | if (IS_IPAD()) { 313 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 314 | frame.origin.x = self.vContent.bounds.size.width - frame.size.width * (i + 1) - self.contentInsets.right * (i + 1); 315 | } else { 316 | frame.origin.x = self.vContent.bounds.size.width *pages - frame.size.width * (i + 1) - self.contentInsets.right * (i + 1); 317 | } 318 | } else { 319 | frame.origin.x = self.vContent.bounds.size.width - frame.size.width - self.contentInsets.right; 320 | } 321 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 322 | frame.origin.y = self.vContent.bounds.size.height * pages - frame.size.height - self.contentInsets.bottom; 323 | } else { 324 | frame.origin.y = self.vContent.bounds.size.height - frame.size.height - self.contentInsets.bottom; 325 | } 326 | [self.clipViews[i] setFrame:frame]; 327 | } 328 | } 329 | NSMutableArray *clipViewsFrames = [[NSMutableArray alloc] initWithCapacity:numberOfClips]; 330 | for (int i = 0; i < numberOfClips; i++) { 331 | [clipViewsFrames addObject:[NSValue valueWithCGRect:[self.clipViews[i] frame]]]; 332 | } 333 | self.clipViewsFrames = [NSArray arrayWithArray:clipViewsFrames]; 334 | } 335 | 336 | for (UIView *subview in self.vContent.subviews) { 337 | if ([subview isKindOfClass:[UITextView class]]) { 338 | [subview removeFromSuperview]; 339 | } 340 | } 341 | 342 | if (article && article.body) { 343 | self.textStorage = [[NSTextStorage alloc] initWithString:article.body]; 344 | self.layoutManager = [[NSLayoutManager alloc] init]; 345 | [self.textStorage addLayoutManager:self.layoutManager]; 346 | 347 | NSUInteger lastGlyph = 0; 348 | NSUInteger currentPage = 0; 349 | while (lastGlyph < self.layoutManager.numberOfGlyphs) { 350 | CGRect frame = CGRectZero; 351 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 352 | frame = CGRectMake(self.contentInsets.left, 353 | self.contentInsets.top + self.vContent.bounds.size.height * currentPage, 354 | self.vContent.bounds.size.width - self.contentInsets.left - self.contentInsets.right, 355 | self.vContent.bounds.size.height - self.contentInsets.top - self.contentInsets.bottom); 356 | 357 | } else { 358 | frame = CGRectMake(self.contentInsets.left + self.lcivImageWidth.constant * currentPage, 359 | (currentPage % 2 == 1) ? self.contentInsets.bottom : self.contentInsets.top, 360 | self.lcivImageWidth.constant - self.contentInsets.left - self.contentInsets.right, 361 | self.vContent.bounds.size.height - self.contentInsets.top - self.contentInsets.bottom); 362 | } 363 | 364 | if (currentPage == 0) { 365 | CGFloat δ = self.vColor.frame.origin.y + self.vColor.bounds.size.height; 366 | frame.origin.y = δ; 367 | frame.size.height = self.vContent.bounds.size.height - δ - self.contentInsets.bottom; 368 | } 369 | 370 | NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:frame.size]; 371 | NSMutableArray *paths = [[NSMutableArray alloc] init]; 372 | UIView *referenceView = [[UIView alloc] initWithFrame:frame]; 373 | [self.vContent addSubview:referenceView]; 374 | __block CGFloat y = NSNotFound; 375 | [self.clipViews enumerateObjectsUsingBlock:^(RSClipView *clipView, NSUInteger idx, BOOL *stop) { 376 | if (y == NSNotFound) { 377 | y = clipView.frame.origin.y; 378 | } else if (y != clipView.frame.origin.y) { 379 | y = CGFLOAT_MAX; 380 | *stop = YES; 381 | } 382 | }]; 383 | if (y == CGFLOAT_MAX) { 384 | for (RSClipView *clipView in self.clipViews) { 385 | CGRect frame = [referenceView convertRect:clipView.bounds 386 | fromView:clipView]; 387 | [paths addObject:[UIBezierPath bezierPathWithRect:frame]]; 388 | } 389 | } else { 390 | CGRect frame = CGRectMake(CGFLOAT_MAX, CGFLOAT_MAX, 0, 0); 391 | for (RSClipView *clipView in self.clipViews) { 392 | if (frame.origin.x > clipView.frame.origin.x) { 393 | frame.origin.x = clipView.frame.origin.x; 394 | } 395 | 396 | if (frame.origin.y > clipView.frame.origin.y) { 397 | frame.origin.y = clipView.frame.origin.y; 398 | } 399 | 400 | if ((clipView.frame.origin.x + clipView.frame.size.width) > frame.size.width) { 401 | frame.size.width = (clipView.frame.origin.x + clipView.frame.size.width); 402 | } 403 | if ((clipView.frame.origin.y + clipView.frame.size.height) > frame.size.height) { 404 | frame.size.height = (clipView.frame.origin.y + clipView.frame.size.height); 405 | } 406 | } 407 | frame.size.width -= frame.origin.x; 408 | frame.size.height -= frame.origin.y; 409 | UIView *view = [[UIView alloc] initWithFrame:frame]; 410 | [self.vContent addSubview:view]; 411 | frame = [referenceView convertRect:view.bounds 412 | fromView:view]; 413 | [paths addObject:[UIBezierPath bezierPathWithRect:frame]]; 414 | [view removeFromSuperview]; 415 | } 416 | [referenceView removeFromSuperview]; 417 | 418 | [textContainer setExclusionPaths:[NSArray arrayWithArray:paths]]; 419 | [self.layoutManager addTextContainer:textContainer]; 420 | 421 | UITextView *textView = [[UITextView alloc] initWithFrame:frame 422 | textContainer:textContainer]; 423 | [textView setBackgroundColor:self.bodyBackgroundColor]; 424 | [textView setTextColor:self.bodyTextColor]; 425 | [textView setFont:self.bodyFont]; 426 | textView.scrollEnabled = NO; 427 | textView.editable = NO; 428 | textContainer.size = textView.contentSize; 429 | [self.vContent addSubview:textView]; 430 | 431 | lastGlyph = NSMaxRange([self.layoutManager glyphRangeForTextContainer:textContainer]); 432 | currentPage++; 433 | } 434 | for (RSClipView *clipView in self.clipViews) { 435 | [self.vContent bringSubviewToFront:clipView]; 436 | } 437 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 438 | self.lcivImageBottom.constant = self.vContent.bounds.size.height * currentPage - self.lcivImageHeight.constant; 439 | } else { 440 | self.lcivImageTrailing.constant = self.vContent.bounds.size.width * (currentPage / 2 + ((currentPage % 2) == 1 ? 1 : 0)) - self.lcivImageWidth.constant; 441 | } 442 | } 443 | }); 444 | } 445 | 446 | - (NSMutableDictionary *)oldConstants 447 | { 448 | if (!_oldConstants) { 449 | _oldConstants = [[NSMutableDictionary alloc] init]; 450 | } 451 | return _oldConstants; 452 | } 453 | 454 | - (NSMutableArray *)clipViews 455 | { 456 | if (!_clipViews) { 457 | _clipViews = [[NSMutableArray alloc] init]; 458 | } 459 | return _clipViews; 460 | } 461 | 462 | #pragma mark - UIScrollViewDelegate 463 | 464 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView 465 | { 466 | if (scrollView == self.vContent) { 467 | if (self.enableImageDragZoomIn) { 468 | CGFloat yOffset = scrollView.contentOffset.y; 469 | if (yOffset < 0) { 470 | self.lcivImageTop.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcivImageTop)] floatValue] + yOffset; 471 | self.lcivImageHeight.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcivImageHeight)] floatValue] - yOffset; 472 | } else { 473 | self.lcivImageTop.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcivImageTop)] floatValue]; 474 | self.lcivImageHeight.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcivImageHeight)] floatValue]; 475 | } 476 | [self.ivImage layoutIfNeeded]; 477 | } 478 | } 479 | } 480 | 481 | - (void)layoutHeader:(BOOL)animated 482 | { 483 | void(^layoutIfNeeded)() = [^() { 484 | [self.lTitle layoutIfNeeded]; 485 | [self.lSource layoutIfNeeded]; 486 | [self.lDate layoutIfNeeded]; 487 | [self.vColor layoutIfNeeded]; 488 | [self.ivImage layoutIfNeeded]; 489 | } copy]; 490 | 491 | if (animated) { 492 | [UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ 493 | layoutIfNeeded(); 494 | } completion:nil]; 495 | } else { 496 | layoutIfNeeded(); 497 | } 498 | } 499 | 500 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 501 | { 502 | if (scrollView == self.vContent) { 503 | NSUInteger currentPage = 0; 504 | if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait) { 505 | currentPage = roundf(scrollView.contentOffset.y / (scrollView.frame.size.height)); 506 | } else { 507 | currentPage = roundf(scrollView.contentOffset.x / (scrollView.frame.size.width)); 508 | } 509 | if (currentPage == 0) { 510 | self.lTitle.font = [self.oldConstants objectForKey:[NSString stringWithFormat:@"%@%@", PROPERTY_NAME(self.lTitle), @"Font"]]; 511 | self.lTitle.textColor = [self.oldConstants objectForKey:[NSString stringWithFormat:@"%@%@", PROPERTY_NAME(self.lTitle), @"Color"]]; 512 | self.lclTitleTop.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTop)] floatValue]; 513 | self.lcVerticalSpaceBetweenlTitlelSource.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcVerticalSpaceBetweenlTitlelSource)] floatValue]; 514 | self.lSource.text = self.article.source; 515 | self.lDate.text = self.article.date; 516 | if ([[UIApplication sharedApplication] statusBarOrientation] != UIInterfaceOrientationPortrait) { 517 | // FIXME: Avoid auto layout warning logs 518 | if (self.lastPage < currentPage) { 519 | self.lclTitleTrailing.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTrailing)] floatValue]; 520 | self.lcvColorLeading.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcvColorLeading)] floatValue]; 521 | } else { 522 | self.lcvColorLeading.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcvColorLeading)] floatValue]; 523 | self.lclTitleTrailing.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTrailing)] floatValue]; 524 | } 525 | } 526 | [self layoutHeader:YES]; 527 | 528 | } else if (currentPage > 0) { 529 | self.lTitle.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]; 530 | [self.lTitle layoutIfNeeded]; 531 | self.lTitle.textColor = [UIColor lightGrayColor]; 532 | self.lclTitleTop.constant = self.vContent.bounds.size.height * currentPage - self.lcivImageTop.constant - self.lcivImageHeight.constant + roundf((self.contentInsets.top - self.lTitle.bounds.size.height) / 2.0f); 533 | self.lcVerticalSpaceBetweenlTitlelSource.constant = 0; 534 | self.lSource.text = nil; 535 | self.lDate.text = nil; 536 | if ([[UIApplication sharedApplication] statusBarOrientation] != UIInterfaceOrientationPortrait) { 537 | // FIXME: Avoid auto layout warning logs 538 | if (self.lastPage < currentPage) { 539 | self.lclTitleTrailing.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTrailing)] floatValue] + self.vContent.bounds.size.width * currentPage; 540 | self.lcvColorLeading.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcvColorLeading)] floatValue] + self.vContent.bounds.size.width * currentPage; 541 | } else { 542 | self.lcvColorLeading.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lcvColorLeading)] floatValue] + self.vContent.bounds.size.width * currentPage; 543 | self.lclTitleTrailing.constant = [[self.oldConstants objectForKey:PROPERTY_NAME(self.lclTitleTrailing)] floatValue] + self.vContent.bounds.size.width * currentPage; 544 | } 545 | 546 | self.lclTitleTop.constant = -self.lcivImageHeight.constant + roundf((self.contentInsets.top - self.lTitle.bounds.size.height) / 2.0f); 547 | } 548 | [self layoutHeader:YES]; 549 | } 550 | 551 | self.lastPage = currentPage; 552 | 553 | for (RSClipView *clipView in self.clipViews) { 554 | clipView.frame = [self.clipViewsFrames[clipView.tag] CGRectValue]; 555 | } 556 | } 557 | } 558 | 559 | @end 560 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D0071D8018EBE286002843A6 /* RSReadingBoard_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = D0071D7F18EBE286002843A6 /* RSReadingBoard_iPad.xib */; }; 11 | D080275C18E2CFD70095F1FB /* Body.txt in Resources */ = {isa = PBXBuildFile; fileRef = D080275B18E2CFD70095F1FB /* Body.txt */; }; 12 | D08897C318E9126100CF14D5 /* UIImage+Fitness.m in Sources */ = {isa = PBXBuildFile; fileRef = D08897C218E9126100CF14D5 /* UIImage+Fitness.m */; }; 13 | D0C2E45E18E15B2400B784B8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C2E45D18E15B2400B784B8 /* Foundation.framework */; }; 14 | D0C2E46018E15B2400B784B8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C2E45F18E15B2400B784B8 /* CoreGraphics.framework */; }; 15 | D0C2E46218E15B2400B784B8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C2E46118E15B2400B784B8 /* UIKit.framework */; }; 16 | D0C2E46818E15B2400B784B8 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0C2E46618E15B2400B784B8 /* InfoPlist.strings */; }; 17 | D0C2E46A18E15B2400B784B8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C2E46918E15B2400B784B8 /* main.m */; }; 18 | D0C2E46E18E15B2400B784B8 /* RSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C2E46D18E15B2400B784B8 /* RSAppDelegate.m */; }; 19 | D0C2E47918E15B2400B784B8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0C2E47818E15B2400B784B8 /* Images.xcassets */; }; 20 | D0C2E4A418E170C200B784B8 /* RSReadingBoard_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = D0C2E4A018E170C200B784B8 /* RSReadingBoard_iPhone.xib */; }; 21 | D0C2E4A518E170C200B784B8 /* RSReadingBoard.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C2E4A218E170C200B784B8 /* RSReadingBoard.m */; }; 22 | D0C2E4A818E174A600B784B8 /* RSArticle.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C2E4A718E174A600B784B8 /* RSArticle.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | D0071D7F18EBE286002843A6 /* RSReadingBoard_iPad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = RSReadingBoard_iPad.xib; path = ../RSReadingBoard_iPad.xib; sourceTree = ""; }; 27 | D080275B18E2CFD70095F1FB /* Body.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Body.txt; sourceTree = ""; }; 28 | D08897C118E9126100CF14D5 /* UIImage+Fitness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Fitness.h"; sourceTree = ""; }; 29 | D08897C218E9126100CF14D5 /* UIImage+Fitness.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Fitness.m"; sourceTree = ""; }; 30 | D0C2E45A18E15B2400B784B8 /* RSReadingBoardSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RSReadingBoardSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | D0C2E45D18E15B2400B784B8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 32 | D0C2E45F18E15B2400B784B8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 33 | D0C2E46118E15B2400B784B8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 34 | D0C2E46518E15B2400B784B8 /* RSReadingBoardSample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RSReadingBoardSample-Info.plist"; sourceTree = ""; }; 35 | D0C2E46718E15B2400B784B8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 36 | D0C2E46918E15B2400B784B8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 37 | D0C2E46B18E15B2400B784B8 /* RSReadingBoardSample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RSReadingBoardSample-Prefix.pch"; sourceTree = ""; }; 38 | D0C2E46C18E15B2400B784B8 /* RSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RSAppDelegate.h; sourceTree = ""; }; 39 | D0C2E46D18E15B2400B784B8 /* RSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RSAppDelegate.m; sourceTree = ""; }; 40 | D0C2E47818E15B2400B784B8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 41 | D0C2E47F18E15B2400B784B8 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 42 | D0C2E4A018E170C200B784B8 /* RSReadingBoard_iPhone.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = RSReadingBoard_iPhone.xib; path = ../RSReadingBoard_iPhone.xib; sourceTree = ""; }; 43 | D0C2E4A118E170C200B784B8 /* RSReadingBoard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSReadingBoard.h; path = ../RSReadingBoard.h; sourceTree = ""; }; 44 | D0C2E4A218E170C200B784B8 /* RSReadingBoard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RSReadingBoard.m; path = ../RSReadingBoard.m; sourceTree = ""; }; 45 | D0C2E4A618E174A600B784B8 /* RSArticle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSArticle.h; path = ../RSArticle.h; sourceTree = ""; }; 46 | D0C2E4A718E174A600B784B8 /* RSArticle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RSArticle.m; path = ../RSArticle.m; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | D0C2E45718E15B2400B784B8 /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | D0C2E46018E15B2400B784B8 /* CoreGraphics.framework in Frameworks */, 55 | D0C2E46218E15B2400B784B8 /* UIKit.framework in Frameworks */, 56 | D0C2E45E18E15B2400B784B8 /* Foundation.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | D08897C018E9126100CF14D5 /* RSImageFitness */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | D08897C118E9126100CF14D5 /* UIImage+Fitness.h */, 67 | D08897C218E9126100CF14D5 /* UIImage+Fitness.m */, 68 | ); 69 | name = RSImageFitness; 70 | path = ../RSImageFitness; 71 | sourceTree = ""; 72 | }; 73 | D0C2E45118E15B2400B784B8 = { 74 | isa = PBXGroup; 75 | children = ( 76 | D0C2E49518E15BFB00B784B8 /* RSReadingBoard */, 77 | D0C2E46318E15B2400B784B8 /* RSReadingBoardSample */, 78 | D0C2E45C18E15B2400B784B8 /* Frameworks */, 79 | D0C2E45B18E15B2400B784B8 /* Products */, 80 | ); 81 | sourceTree = ""; 82 | }; 83 | D0C2E45B18E15B2400B784B8 /* Products */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | D0C2E45A18E15B2400B784B8 /* RSReadingBoardSample.app */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | D0C2E45C18E15B2400B784B8 /* Frameworks */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | D0C2E45D18E15B2400B784B8 /* Foundation.framework */, 95 | D0C2E45F18E15B2400B784B8 /* CoreGraphics.framework */, 96 | D0C2E46118E15B2400B784B8 /* UIKit.framework */, 97 | D0C2E47F18E15B2400B784B8 /* XCTest.framework */, 98 | ); 99 | name = Frameworks; 100 | sourceTree = ""; 101 | }; 102 | D0C2E46318E15B2400B784B8 /* RSReadingBoardSample */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | D0C2E46C18E15B2400B784B8 /* RSAppDelegate.h */, 106 | D0C2E46D18E15B2400B784B8 /* RSAppDelegate.m */, 107 | D0C2E47818E15B2400B784B8 /* Images.xcassets */, 108 | D0C2E46418E15B2400B784B8 /* Supporting Files */, 109 | ); 110 | path = RSReadingBoardSample; 111 | sourceTree = ""; 112 | }; 113 | D0C2E46418E15B2400B784B8 /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | D080275B18E2CFD70095F1FB /* Body.txt */, 117 | D0C2E46518E15B2400B784B8 /* RSReadingBoardSample-Info.plist */, 118 | D0C2E46618E15B2400B784B8 /* InfoPlist.strings */, 119 | D0C2E46918E15B2400B784B8 /* main.m */, 120 | D0C2E46B18E15B2400B784B8 /* RSReadingBoardSample-Prefix.pch */, 121 | ); 122 | name = "Supporting Files"; 123 | sourceTree = ""; 124 | }; 125 | D0C2E49518E15BFB00B784B8 /* RSReadingBoard */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | D08897C018E9126100CF14D5 /* RSImageFitness */, 129 | D0C2E4A018E170C200B784B8 /* RSReadingBoard_iPhone.xib */, 130 | D0071D7F18EBE286002843A6 /* RSReadingBoard_iPad.xib */, 131 | D0C2E4A118E170C200B784B8 /* RSReadingBoard.h */, 132 | D0C2E4A218E170C200B784B8 /* RSReadingBoard.m */, 133 | D0C2E4A618E174A600B784B8 /* RSArticle.h */, 134 | D0C2E4A718E174A600B784B8 /* RSArticle.m */, 135 | ); 136 | name = RSReadingBoard; 137 | sourceTree = ""; 138 | }; 139 | /* End PBXGroup section */ 140 | 141 | /* Begin PBXNativeTarget section */ 142 | D0C2E45918E15B2400B784B8 /* RSReadingBoardSample */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = D0C2E48F18E15B2400B784B8 /* Build configuration list for PBXNativeTarget "RSReadingBoardSample" */; 145 | buildPhases = ( 146 | D0C2E45618E15B2400B784B8 /* Sources */, 147 | D0C2E45718E15B2400B784B8 /* Frameworks */, 148 | D0C2E45818E15B2400B784B8 /* Resources */, 149 | ); 150 | buildRules = ( 151 | ); 152 | dependencies = ( 153 | ); 154 | name = RSReadingBoardSample; 155 | productName = RSReadingBoardSample; 156 | productReference = D0C2E45A18E15B2400B784B8 /* RSReadingBoardSample.app */; 157 | productType = "com.apple.product-type.application"; 158 | }; 159 | /* End PBXNativeTarget section */ 160 | 161 | /* Begin PBXProject section */ 162 | D0C2E45218E15B2400B784B8 /* Project object */ = { 163 | isa = PBXProject; 164 | attributes = { 165 | CLASSPREFIX = RS; 166 | LastUpgradeCheck = 0510; 167 | ORGANIZATIONNAME = P.D.Q.; 168 | }; 169 | buildConfigurationList = D0C2E45518E15B2400B784B8 /* Build configuration list for PBXProject "RSReadingBoardSample" */; 170 | compatibilityVersion = "Xcode 3.2"; 171 | developmentRegion = English; 172 | hasScannedForEncodings = 0; 173 | knownRegions = ( 174 | en, 175 | Base, 176 | ); 177 | mainGroup = D0C2E45118E15B2400B784B8; 178 | productRefGroup = D0C2E45B18E15B2400B784B8 /* Products */; 179 | projectDirPath = ""; 180 | projectRoot = ""; 181 | targets = ( 182 | D0C2E45918E15B2400B784B8 /* RSReadingBoardSample */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXResourcesBuildPhase section */ 188 | D0C2E45818E15B2400B784B8 /* Resources */ = { 189 | isa = PBXResourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | D0C2E4A418E170C200B784B8 /* RSReadingBoard_iPhone.xib in Resources */, 193 | D0071D8018EBE286002843A6 /* RSReadingBoard_iPad.xib in Resources */, 194 | D080275C18E2CFD70095F1FB /* Body.txt in Resources */, 195 | D0C2E47918E15B2400B784B8 /* Images.xcassets in Resources */, 196 | D0C2E46818E15B2400B784B8 /* InfoPlist.strings in Resources */, 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | /* End PBXResourcesBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | D0C2E45618E15B2400B784B8 /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | D08897C318E9126100CF14D5 /* UIImage+Fitness.m in Sources */, 208 | D0C2E46A18E15B2400B784B8 /* main.m in Sources */, 209 | D0C2E46E18E15B2400B784B8 /* RSAppDelegate.m in Sources */, 210 | D0C2E4A518E170C200B784B8 /* RSReadingBoard.m in Sources */, 211 | D0C2E4A818E174A600B784B8 /* RSArticle.m in Sources */, 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | }; 215 | /* End PBXSourcesBuildPhase section */ 216 | 217 | /* Begin PBXVariantGroup section */ 218 | D0C2E46618E15B2400B784B8 /* InfoPlist.strings */ = { 219 | isa = PBXVariantGroup; 220 | children = ( 221 | D0C2E46718E15B2400B784B8 /* en */, 222 | ); 223 | name = InfoPlist.strings; 224 | sourceTree = ""; 225 | }; 226 | /* End PBXVariantGroup section */ 227 | 228 | /* Begin XCBuildConfiguration section */ 229 | D0C2E48D18E15B2400B784B8 /* Debug */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | ALWAYS_SEARCH_USER_PATHS = NO; 233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 234 | CLANG_CXX_LIBRARY = "libc++"; 235 | CLANG_ENABLE_MODULES = YES; 236 | CLANG_ENABLE_OBJC_ARC = YES; 237 | CLANG_WARN_BOOL_CONVERSION = YES; 238 | CLANG_WARN_CONSTANT_CONVERSION = YES; 239 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 240 | CLANG_WARN_EMPTY_BODY = YES; 241 | CLANG_WARN_ENUM_CONVERSION = YES; 242 | CLANG_WARN_INT_CONVERSION = YES; 243 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 246 | COPY_PHASE_STRIP = NO; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_OPTIMIZATION_LEVEL = 0; 250 | GCC_PREPROCESSOR_DEFINITIONS = ( 251 | "DEBUG=1", 252 | "$(inherited)", 253 | ); 254 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 257 | GCC_WARN_UNDECLARED_SELECTOR = YES; 258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 259 | GCC_WARN_UNUSED_FUNCTION = YES; 260 | GCC_WARN_UNUSED_VARIABLE = YES; 261 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 262 | ONLY_ACTIVE_ARCH = YES; 263 | SDKROOT = iphoneos; 264 | TARGETED_DEVICE_FAMILY = "1,2"; 265 | }; 266 | name = Debug; 267 | }; 268 | D0C2E48E18E15B2400B784B8 /* Release */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ALWAYS_SEARCH_USER_PATHS = NO; 272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 273 | CLANG_CXX_LIBRARY = "libc++"; 274 | CLANG_ENABLE_MODULES = YES; 275 | CLANG_ENABLE_OBJC_ARC = YES; 276 | CLANG_WARN_BOOL_CONVERSION = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 283 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 284 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 285 | COPY_PHASE_STRIP = YES; 286 | ENABLE_NS_ASSERTIONS = NO; 287 | GCC_C_LANGUAGE_STANDARD = gnu99; 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 295 | SDKROOT = iphoneos; 296 | TARGETED_DEVICE_FAMILY = "1,2"; 297 | VALIDATE_PRODUCT = YES; 298 | }; 299 | name = Release; 300 | }; 301 | D0C2E49018E15B2400B784B8 /* Debug */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 305 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 306 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 307 | GCC_PREFIX_HEADER = "RSReadingBoardSample/RSReadingBoardSample-Prefix.pch"; 308 | INFOPLIST_FILE = "RSReadingBoardSample/RSReadingBoardSample-Info.plist"; 309 | PRODUCT_NAME = "$(TARGET_NAME)"; 310 | WRAPPER_EXTENSION = app; 311 | }; 312 | name = Debug; 313 | }; 314 | D0C2E49118E15B2400B784B8 /* Release */ = { 315 | isa = XCBuildConfiguration; 316 | buildSettings = { 317 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 318 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 319 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 320 | GCC_PREFIX_HEADER = "RSReadingBoardSample/RSReadingBoardSample-Prefix.pch"; 321 | INFOPLIST_FILE = "RSReadingBoardSample/RSReadingBoardSample-Info.plist"; 322 | PRODUCT_NAME = "$(TARGET_NAME)"; 323 | WRAPPER_EXTENSION = app; 324 | }; 325 | name = Release; 326 | }; 327 | /* End XCBuildConfiguration section */ 328 | 329 | /* Begin XCConfigurationList section */ 330 | D0C2E45518E15B2400B784B8 /* Build configuration list for PBXProject "RSReadingBoardSample" */ = { 331 | isa = XCConfigurationList; 332 | buildConfigurations = ( 333 | D0C2E48D18E15B2400B784B8 /* Debug */, 334 | D0C2E48E18E15B2400B784B8 /* Release */, 335 | ); 336 | defaultConfigurationIsVisible = 0; 337 | defaultConfigurationName = Release; 338 | }; 339 | D0C2E48F18E15B2400B784B8 /* Build configuration list for PBXNativeTarget "RSReadingBoardSample" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | D0C2E49018E15B2400B784B8 /* Debug */, 343 | D0C2E49118E15B2400B784B8 /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | /* End XCConfigurationList section */ 349 | }; 350 | rootObject = D0C2E45218E15B2400B784B8 /* Project object */; 351 | } 352 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample.xcodeproj/project.xcworkspace/xcshareddata/RSReadingBoardSample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | BD347749-70A8-4027-8455-D197B03EB5E2 9 | IDESourceControlProjectName 10 | RSReadingBoardSample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 4AF81FA6-2133-454E-B28A-364CAC56958E 14 | https://github.com/yeahdongcn/RSReadingBoard.git 15 | 16 | IDESourceControlProjectPath 17 | RSReadingBoardSample/RSReadingBoardSample.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 4AF81FA6-2133-454E-B28A-364CAC56958E 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/yeahdongcn/RSReadingBoard.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 4AF81FA6-2133-454E-B28A-364CAC56958E 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 4AF81FA6-2133-454E-B28A-364CAC56958E 36 | IDESourceControlWCCName 37 | RSReadingBoard 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample.xcodeproj/xcshareddata/xcschemes/RSReadingBoardSample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Body.txt: -------------------------------------------------------------------------------- 1 | (CNN) -- More than 300 relatives and friends of missing Flight MH370 passengers marched to the Malaysian Embassy in Beijing Tuesday to express their anger and frustration with Malaysian authorities. 2 | Hundreds of uniformed police blocked media from joining the protesters as they approached the gates of the embassy. 3 | Relatives despair as weather delays Flight 370 search 4 | Many protesters wore white t-shirts that read, "Please pray for the passengers of MH370. We pray for their safe return." 5 | Some carried signs with messages of frustration and grief. "Malaysian government, tell the truth. We've been waiting too long," read one. "Husband, please come home," said another. 6 | Flight news leaves families full of grief Missing plane: 'Unprecedented event' Bad weather hampers missing plane search 7 | Overcome by stress and raw emotion, one woman was carried out from the cordoned area on a stretcher by paramedics. 8 | Petition letter 9 | Earlier, the protesters had walked on foot from the Lido Hotel, near Beijing's International Airport, after police prevented them from boarding buses to the embassy. Many relatives have been staying at the hotel since the airliner vanished more than two weeks ago. 10 | The protesters left the embassy on buses on Tuesday afternoon after a Malaysian official accepted a petition letter from the families. 11 | The previous evening, Malaysia's prime minister announced that Flight MH370's last position was in a remote part of the Indian Ocean. Soon after, Malaysian Airlines informed relatives that the lives of all on board the plane had been lost. Relatives at the Lido Hotel screamed and sobbed after hearing the news. 12 | The airline has already given family members $5,000 in compensation for each passenger aboard the ill-fated flight, and is preparing to make additional payments as the search continues. 13 | "No amount of compensation or consolation will make up for any loss of life," Malaysia Airlines Chairman Mohamad Nor Yusof said Tuesday. 14 | The company is working on an arrangement to fly families to Australia once wreckage is found. 15 | Visa fees will be waived for the families of MH370 passengers and crew flying in to Australia, the country's defense minister David Johnston said Tuesday. 16 | Texts criticism 17 | Malaysia Airlines has defended its decision to inform the families by text message -- along with phone calls and face-to-face meetings -- that the flight ended in the Indian Ocean. 18 | The airline's CEO, Ahmad Jauhari Yahya, said Tuesday that text messages were used to ensure the nearly 1,000 family members "heard the tragic news before the world did." 19 | China has asked Malaysia to share any evidence that led it to conclude the airliner crashed in the Indian Ocean with no survivors. 20 | 21 | #REPEAT 22 | 23 | (CNN) -- More than 300 relatives and friends of missing Flight MH370 passengers marched to the Malaysian Embassy in Beijing Tuesday to express their anger and frustration with Malaysian authorities. 24 | Hundreds of uniformed police blocked media from joining the protesters as they approached the gates of the embassy. 25 | Relatives despair as weather delays Flight 370 search 26 | Many protesters wore white t-shirts that read, "Please pray for the passengers of MH370. We pray for their safe return." 27 | Some carried signs with messages of frustration and grief. "Malaysian government, tell the truth. We've been waiting too long," read one. "Husband, please come home," said another. 28 | Flight news leaves families full of grief Missing plane: 'Unprecedented event' Bad weather hampers missing plane search 29 | Overcome by stress and raw emotion, one woman was carried out from the cordoned area on a stretcher by paramedics. 30 | Petition letter 31 | Earlier, the protesters had walked on foot from the Lido Hotel, near Beijing's International Airport, after police prevented them from boarding buses to the embassy. Many relatives have been staying at the hotel since the airliner vanished more than two weeks ago. 32 | The protesters left the embassy on buses on Tuesday afternoon after a Malaysian official accepted a petition letter from the families. 33 | The previous evening, Malaysia's prime minister announced that Flight MH370's last position was in a remote part of the Indian Ocean. Soon after, Malaysian Airlines informed relatives that the lives of all on board the plane had been lost. Relatives at the Lido Hotel screamed and sobbed after hearing the news. 34 | The airline has already given family members $5,000 in compensation for each passenger aboard the ill-fated flight, and is preparing to make additional payments as the search continues. 35 | "No amount of compensation or consolation will make up for any loss of life," Malaysia Airlines Chairman Mohamad Nor Yusof said Tuesday. 36 | The company is working on an arrangement to fly families to Australia once wreckage is found. 37 | Visa fees will be waived for the families of MH370 passengers and crew flying in to Australia, the country's defense minister David Johnston said Tuesday. 38 | Texts criticism 39 | Malaysia Airlines has defended its decision to inform the families by text message -- along with phone calls and face-to-face meetings -- that the flight ended in the Indian Ocean. 40 | The airline's CEO, Ahmad Jauhari Yahya, said Tuesday that text messages were used to ensure the nearly 1,000 family members "heard the tragic news before the world did." 41 | China has asked Malaysia to share any evidence that led it to conclude the airliner crashed in the Indian Ocean with no survivors. 42 | 43 | #REPEAT 44 | 45 | (CNN) -- More than 300 relatives and friends of missing Flight MH370 passengers marched to the Malaysian Embassy in Beijing Tuesday to express their anger and frustration with Malaysian authorities. 46 | Hundreds of uniformed police blocked media from joining the protesters as they approached the gates of the embassy. 47 | Relatives despair as weather delays Flight 370 search 48 | Many protesters wore white t-shirts that read, "Please pray for the passengers of MH370. We pray for their safe return." 49 | Some carried signs with messages of frustration and grief. "Malaysian government, tell the truth. We've been waiting too long," read one. "Husband, please come home," said another. 50 | Flight news leaves families full of grief Missing plane: 'Unprecedented event' Bad weather hampers missing plane search 51 | Overcome by stress and raw emotion, one woman was carried out from the cordoned area on a stretcher by paramedics. 52 | Petition letter 53 | Earlier, the protesters had walked on foot from the Lido Hotel, near Beijing's International Airport, after police prevented them from boarding buses to the embassy. Many relatives have been staying at the hotel since the airliner vanished more than two weeks ago. 54 | The protesters left the embassy on buses on Tuesday afternoon after a Malaysian official accepted a petition letter from the families. 55 | The previous evening, Malaysia's prime minister announced that Flight MH370's last position was in a remote part of the Indian Ocean. Soon after, Malaysian Airlines informed relatives that the lives of all on board the plane had been lost. Relatives at the Lido Hotel screamed and sobbed after hearing the news. 56 | The airline has already given family members $5,000 in compensation for each passenger aboard the ill-fated flight, and is preparing to make additional payments as the search continues. 57 | "No amount of compensation or consolation will make up for any loss of life," Malaysia Airlines Chairman Mohamad Nor Yusof said Tuesday. 58 | The company is working on an arrangement to fly families to Australia once wreckage is found. 59 | Visa fees will be waived for the families of MH370 passengers and crew flying in to Australia, the country's defense minister David Johnston said Tuesday. 60 | Texts criticism 61 | Malaysia Airlines has defended its decision to inform the families by text message -- along with phone calls and face-to-face meetings -- that the flight ended in the Indian Ocean. 62 | The airline's CEO, Ahmad Jauhari Yahya, said Tuesday that text messages were used to ensure the nearly 1,000 family members "heard the tragic news before the world did." 63 | China has asked Malaysia to share any evidence that led it to conclude the airliner crashed in the Indian Ocean with no survivors. -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip0.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "clip0@2x.png" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip0.imageset/clip0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip0.imageset/clip0@2x.png -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "clip1@2x.png" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip1.imageset/clip1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip1.imageset/clip1@2x.png -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "clip2@2x.png" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip2.imageset/clip2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/clip2.imageset/clip2@2x.png -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "image@2x.png" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/image.imageset/image@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/RSReadingBoardSample/RSReadingBoardSample/Images.xcassets/image.imageset/image@2x.png -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/RSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSAppDelegate.h 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RSAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/RSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSAppDelegate.m 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSAppDelegate.h" 10 | 11 | #import "RSArticle.h" 12 | 13 | #import "RSReadingBoard.h" 14 | 15 | @implementation RSAppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | RSReadingBoard *board = [RSReadingBoard board]; 20 | RSArticle *article = [RSArticle new]; 21 | article.image = [UIImage imageNamed:@"image"]; 22 | article.title = @"MH370: Angry families march on Malaysian Embassy in Beijing"; 23 | article.source = @"By Sophie Brown, CNN"; 24 | article.date = @"March 25, 2014 -- Updated 1129 GMT (1929 HKT)"; 25 | article.body = [NSString stringWithContentsOfFile:[[[NSBundle mainBundle] URLForResource:@"Body" withExtension:@"txt"] path] encoding:NSUTF8StringEncoding error:nil]; 26 | article.color = [UIColor blackColor]; 27 | article.clips = @[[UIImage imageNamed:@"clip0"], 28 | [UIImage imageNamed:@"clip1"], 29 | [UIImage imageNamed:@"clip2"]]; 30 | board.article = article; 31 | 32 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 33 | self.window.rootViewController = board; 34 | [self.window makeKeyAndVisible]; 35 | 36 | return YES; 37 | } 38 | 39 | - (void)applicationWillResignActive:(UIApplication *)application 40 | { 41 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 42 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 43 | } 44 | 45 | - (void)applicationDidEnterBackground:(UIApplication *)application 46 | { 47 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 48 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 49 | } 50 | 51 | - (void)applicationWillEnterForeground:(UIApplication *)application 52 | { 53 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 54 | } 55 | 56 | - (void)applicationDidBecomeActive:(UIApplication *)application 57 | { 58 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 59 | } 60 | 61 | - (void)applicationWillTerminate:(UIApplication *)application 62 | { 63 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/RSReadingBoardSample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.pdq.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/RSReadingBoardSample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /RSReadingBoardSample/RSReadingBoardSample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RSReadingBoardSample 4 | // 5 | // Created by R0CKSTAR on 3/25/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "RSAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([RSAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /RSReadingBoard_iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 45 | 52 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /RSReadingBoard_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 45 | 52 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /iPad_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/RSReadingBoard/b7994e6e285ac7b1e92e9d67b06936359c29bf31/iPad_landscape.png --------------------------------------------------------------------------------