亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS模仿電子書首頁實現書架布局樣式

2020-07-26 03:26:28
字體:
來源:轉載
供稿:網友

本文實現了類似電子書首頁,用來展示圖書或小說的布局頁面,書架列表【iPhone6模擬器】,屏幕尺寸還沒進行適配,只是做個簡單的demo【純代碼實現方式】

實現采用的是UICollectionView和UICollectionViewFlowLayout。關于UICollectionView的詳細講解請參考

 

一、實現layout的DecorationView


//// FWBookShelfDecarationViewCollectionReusableView.h// FWPersonalApp//// Created by hzkmn on 16/2/18.// Copyright © 2016年 ForrstWoo. All rights reserved.//#import <UIKit/UIKit.h>extern NSInteger const kDecorationViewHeight;@interface FWBookShelfDecarationView : UICollectionReusableView@end
//// FWBookShelfDecarationViewCollectionReusableView.m// FWPersonalApp//// Created by hzkmn on 16/2/18.// Copyright © 2016年 ForrstWoo. All rights reserved.//#import "FWBookShelfDecarationView.h"NSInteger const kDecorationViewHeight = 216;@implementation FWBookShelfDecarationView- (instancetype)initWithFrame:(CGRect)frame{  if (self = [super initWithFrame:frame])  {    UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, kDecorationViewHeight)];    img.image = [UIImage imageNamed:@"boolshelf.png"];    [self addSubview:img];  }    return self;}@end 

FWBookShelfDecarationView類非常簡單只是定義了Decarationview的背景圖片,圖上。

二、下載及導入可重新排序的第三方layout,用于我們移動圖書后重新布局
在實際項目中你或許會遇到在一個集合視圖中移動一項到另外一個位置,那么此時我們需要對視圖中的元素進行重新排序,今天推薦一個很好用的第三方類LXReorderableCollectionViewFlowLayout【點此鏈接進入GITHUB】

下面附上實現代碼

//// LXReorderableCollectionViewFlowLayout.h//// Created by Stan Chang Khin Boon on 1/10/12.// Copyright (c) 2012 d--buzz. All rights reserved.//#import <UIKit/UIKit.h>@interface LXReorderableCollectionViewFlowLayout : UICollectionViewFlowLayout <UIGestureRecognizerDelegate>@property (assign, nonatomic) CGFloat scrollingSpeed;@property (assign, nonatomic) UIEdgeInsets scrollingTriggerEdgeInsets;@property (strong, nonatomic, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer;@property (strong, nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer;- (void)setUpGestureRecognizersOnCollectionView __attribute__((deprecated("Calls to setUpGestureRecognizersOnCollectionView method are not longer needed as setup are done automatically through KVO.")));@end@protocol LXReorderableCollectionViewDataSource <UICollectionViewDataSource>@optional- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath willMoveToIndexPath:(NSIndexPath *)toIndexPath;- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath didMoveToIndexPath:(NSIndexPath *)toIndexPath;- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath;- (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath canMoveToIndexPath:(NSIndexPath *)toIndexPath;@end@protocol LXReorderableCollectionViewDelegateFlowLayout <UICollectionViewDelegateFlowLayout>@optional- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout willBeginDraggingItemAtIndexPath:(NSIndexPath *)indexPath;- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout didBeginDraggingItemAtIndexPath:(NSIndexPath *)indexPath;- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout willEndDraggingItemAtIndexPath:(NSIndexPath *)indexPath;- (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout didEndDraggingItemAtIndexPath:(NSIndexPath *)indexPath;@end
//// LXReorderableCollectionViewFlowLayout.m//// Created by Stan Chang Khin Boon on 1/10/12.// Copyright (c) 2012 d--buzz. All rights reserved.//#import "LXReorderableCollectionViewFlowLayout.h"#import <QuartzCore/QuartzCore.h>#import <objc/runtime.h>#define LX_FRAMES_PER_SECOND 60.0#ifndef CGGEOMETRY_LXSUPPORT_H_CG_INLINE CGPointLXS_CGPointAdd(CGPoint point1, CGPoint point2) {  return CGPointMake(point1.x + point2.x, point1.y + point2.y);}#endiftypedef NS_ENUM(NSInteger, LXScrollingDirection) {  LXScrollingDirectionUnknown = 0,  LXScrollingDirectionUp,  LXScrollingDirectionDown,  LXScrollingDirectionLeft,  LXScrollingDirectionRight};static NSString * const kLXScrollingDirectionKey = @"LXScrollingDirection";static NSString * const kLXCollectionViewKeyPath = @"collectionView";@interface CADisplayLink (LX_userInfo)@property (nonatomic, copy) NSDictionary *LX_userInfo;@end@implementation CADisplayLink (LX_userInfo)- (void) setLX_userInfo:(NSDictionary *) LX_userInfo {  objc_setAssociatedObject(self, "LX_userInfo", LX_userInfo, OBJC_ASSOCIATION_COPY);}- (NSDictionary *) LX_userInfo {  return objc_getAssociatedObject(self, "LX_userInfo");}@end@interface UICollectionViewCell (LXReorderableCollectionViewFlowLayout)- (UIImage *)LX_rasterizedImage;@end@implementation UICollectionViewCell (LXReorderableCollectionViewFlowLayout)- (UIImage *)LX_rasterizedImage {  UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0f);  [self.layer renderInContext:UIGraphicsGetCurrentContext()];  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();  UIGraphicsEndImageContext();  return image;}@end@interface LXReorderableCollectionViewFlowLayout ()@property (strong, nonatomic) NSIndexPath *selectedItemIndexPath;@property (strong, nonatomic) UIView *currentView;@property (assign, nonatomic) CGPoint currentViewCenter;@property (assign, nonatomic) CGPoint panTranslationInCollectionView;@property (strong, nonatomic) CADisplayLink *displayLink;@property (assign, nonatomic, readonly) id<LXReorderableCollectionViewDataSource> dataSource;@property (assign, nonatomic, readonly) id<LXReorderableCollectionViewDelegateFlowLayout> delegate;@end@implementation LXReorderableCollectionViewFlowLayout- (void)setDefaults {  _scrollingSpeed = 300.0f;  _scrollingTriggerEdgeInsets = UIEdgeInsetsMake(50.0f, 50.0f, 50.0f, 50.0f);}- (void)setupCollectionView {  _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self                                        action:@selector(handleLongPressGesture:)];  _longPressGestureRecognizer.delegate = self;    // Links the default long press gesture recognizer to the custom long press gesture recognizer we are creating now  // by enforcing failure dependency so that they doesn't clash.  for (UIGestureRecognizer *gestureRecognizer in self.collectionView.gestureRecognizers) {    if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {      [gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer];    }  }    [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self                                  action:@selector(handlePanGesture:)];  _panGestureRecognizer.delegate = self;  [self.collectionView addGestureRecognizer:_panGestureRecognizer];  // Useful in multiple scenarios: one common scenario being when the Notification Center drawer is pulled down  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleApplicationWillResignActive:) name: UIApplicationWillResignActiveNotification object:nil];}- (id)init {  self = [super init];  if (self) {    [self setDefaults];    [self addObserver:self forKeyPath:kLXCollectionViewKeyPath options:NSKeyValueObservingOptionNew context:nil];  }  return self;}- (id)initWithCoder:(NSCoder *)aDecoder {  self = [super initWithCoder:aDecoder];  if (self) {    [self setDefaults];    [self addObserver:self forKeyPath:kLXCollectionViewKeyPath options:NSKeyValueObservingOptionNew context:nil];  }  return self;}- (void)dealloc {  [self invalidatesScrollTimer];  [self removeObserver:self forKeyPath:kLXCollectionViewKeyPath];  [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];}- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {  if ([layoutAttributes.indexPath isEqual:self.selectedItemIndexPath]) {    layoutAttributes.hidden = YES;  }}- (id<LXReorderableCollectionViewDataSource>)dataSource {  return (id<LXReorderableCollectionViewDataSource>)self.collectionView.dataSource;}- (id<LXReorderableCollectionViewDelegateFlowLayout>)delegate {  return (id<LXReorderableCollectionViewDelegateFlowLayout>)self.collectionView.delegate;}- (void)invalidateLayoutIfNecessary {  NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:self.currentView.center];  NSIndexPath *previousIndexPath = self.selectedItemIndexPath;    if ((newIndexPath == nil) || [newIndexPath isEqual:previousIndexPath]) {    return;  }    if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] &&    ![self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath canMoveToIndexPath:newIndexPath]) {    return;  }    self.selectedItemIndexPath = newIndexPath;    if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) {    [self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath willMoveToIndexPath:newIndexPath];  }  __weak typeof(self) weakSelf = self;  [self.collectionView performBatchUpdates:^{    __strong typeof(self) strongSelf = weakSelf;    if (strongSelf) {      [strongSelf.collectionView deleteItemsAtIndexPaths:@[ previousIndexPath ]];      [strongSelf.collectionView insertItemsAtIndexPaths:@[ newIndexPath ]];    }  } completion:^(BOOL finished) {    __strong typeof(self) strongSelf = weakSelf;    if ([strongSelf.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) {      [strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:previousIndexPath didMoveToIndexPath:newIndexPath];    }  }];}- (void)invalidatesScrollTimer {  if (!self.displayLink.paused) {    [self.displayLink invalidate];  }  self.displayLink = nil;}- (void)setupScrollTimerInDirection:(LXScrollingDirection)direction {  if (!self.displayLink.paused) {    LXScrollingDirection oldDirection = [self.displayLink.LX_userInfo[kLXScrollingDirectionKey] integerValue];    if (direction == oldDirection) {      return;    }  }    [self invalidatesScrollTimer];  self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleScroll:)];  self.displayLink.LX_userInfo = @{ kLXScrollingDirectionKey : @(direction) };  [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];}#pragma mark - Target/Action methods// Tight loop, allocate memory sparely, even if they are stack allocation.- (void)handleScroll:(CADisplayLink *)displayLink {  LXScrollingDirection direction = (LXScrollingDirection)[displayLink.LX_userInfo[kLXScrollingDirectionKey] integerValue];  if (direction == LXScrollingDirectionUnknown) {    return;  }    CGSize frameSize = self.collectionView.bounds.size;  CGSize contentSize = self.collectionView.contentSize;  CGPoint contentOffset = self.collectionView.contentOffset;  UIEdgeInsets contentInset = self.collectionView.contentInset;  // Important to have an integer `distance` as the `contentOffset` property automatically gets rounded  // and it would diverge from the view's center resulting in a "cell is slipping away under finger"-bug.  CGFloat distance = rint(self.scrollingSpeed / LX_FRAMES_PER_SECOND);  CGPoint translation = CGPointZero;    switch(direction) {    case LXScrollingDirectionUp: {      distance = -distance;      CGFloat minY = 0.0f - contentInset.top;            if ((contentOffset.y + distance) <= minY) {        distance = -contentOffset.y - contentInset.top;      }            translation = CGPointMake(0.0f, distance);    } break;    case LXScrollingDirectionDown: {      CGFloat maxY = MAX(contentSize.height, frameSize.height) - frameSize.height + contentInset.bottom;            if ((contentOffset.y + distance) >= maxY) {        distance = maxY - contentOffset.y;      }            translation = CGPointMake(0.0f, distance);    } break;    case LXScrollingDirectionLeft: {      distance = -distance;      CGFloat minX = 0.0f - contentInset.left;            if ((contentOffset.x + distance) <= minX) {        distance = -contentOffset.x - contentInset.left;      }            translation = CGPointMake(distance, 0.0f);    } break;    case LXScrollingDirectionRight: {      CGFloat maxX = MAX(contentSize.width, frameSize.width) - frameSize.width + contentInset.right;            if ((contentOffset.x + distance) >= maxX) {        distance = maxX - contentOffset.x;      }            translation = CGPointMake(distance, 0.0f);    } break;    default: {      // Do nothing...    } break;  }    self.currentViewCenter = LXS_CGPointAdd(self.currentViewCenter, translation);  self.currentView.center = LXS_CGPointAdd(self.currentViewCenter, self.panTranslationInCollectionView);  self.collectionView.contentOffset = LXS_CGPointAdd(contentOffset, translation);}- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer {  switch(gestureRecognizer.state) {    case UIGestureRecognizerStateBegan: {      NSIndexPath *currentIndexPath = [self.collectionView indexPathForItemAtPoint:[gestureRecognizer locationInView:self.collectionView]];            if ([self.dataSource respondsToSelector:@selector(collectionView:canMoveItemAtIndexPath:)] &&        ![self.dataSource collectionView:self.collectionView canMoveItemAtIndexPath:currentIndexPath]) {        return;      }            self.selectedItemIndexPath = currentIndexPath;            if ([self.delegate respondsToSelector:@selector(collectionView:layout:willBeginDraggingItemAtIndexPath:)]) {        [self.delegate collectionView:self.collectionView layout:self willBeginDraggingItemAtIndexPath:self.selectedItemIndexPath];      }            UICollectionViewCell *collectionViewCell = [self.collectionView cellForItemAtIndexPath:self.selectedItemIndexPath];            self.currentView = [[UIView alloc] initWithFrame:collectionViewCell.frame];            collectionViewCell.highlighted = YES;      UIImageView *highlightedImageView = [[UIImageView alloc] initWithImage:[collectionViewCell LX_rasterizedImage]];      highlightedImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;      highlightedImageView.alpha = 1.0f;            collectionViewCell.highlighted = NO;      UIImageView *imageView = [[UIImageView alloc] initWithImage:[collectionViewCell LX_rasterizedImage]];      imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;      imageView.alpha = 0.0f;            [self.currentView addSubview:imageView];      [self.currentView addSubview:highlightedImageView];      [self.collectionView addSubview:self.currentView];            self.currentViewCenter = self.currentView.center;            __weak typeof(self) weakSelf = self;      [UIView       animateWithDuration:0.3       delay:0.0       options:UIViewAnimationOptionBeginFromCurrentState       animations:^{         __strong typeof(self) strongSelf = weakSelf;         if (strongSelf) {           strongSelf.currentView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);           highlightedImageView.alpha = 0.0f;           imageView.alpha = 1.0f;         }       }       completion:^(BOOL finished) {         __strong typeof(self) strongSelf = weakSelf;         if (strongSelf) {           [highlightedImageView removeFromSuperview];                      if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didBeginDraggingItemAtIndexPath:)]) {             [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didBeginDraggingItemAtIndexPath:strongSelf.selectedItemIndexPath];           }         }       }];            [self invalidateLayout];    } break;    case UIGestureRecognizerStateCancelled:    case UIGestureRecognizerStateEnded: {      NSIndexPath *currentIndexPath = self.selectedItemIndexPath;            if (currentIndexPath) {        if ([self.delegate respondsToSelector:@selector(collectionView:layout:willEndDraggingItemAtIndexPath:)]) {          [self.delegate collectionView:self.collectionView layout:self willEndDraggingItemAtIndexPath:currentIndexPath];        }                self.selectedItemIndexPath = nil;        self.currentViewCenter = CGPointZero;                UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:currentIndexPath];                __weak typeof(self) weakSelf = self;        [UIView         animateWithDuration:0.3         delay:0.0         options:UIViewAnimationOptionBeginFromCurrentState         animations:^{           __strong typeof(self) strongSelf = weakSelf;           if (strongSelf) {             strongSelf.currentView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);             strongSelf.currentView.center = layoutAttributes.center;           }         }         completion:^(BOOL finished) {           __strong typeof(self) strongSelf = weakSelf;           if (strongSelf) {             [strongSelf.currentView removeFromSuperview];             strongSelf.currentView = nil;             [strongSelf invalidateLayout];                          if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didEndDraggingItemAtIndexPath:)]) {               [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didEndDraggingItemAtIndexPath:currentIndexPath];             }           }         }];      }    } break;          default: break;  }}- (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer {  switch (gestureRecognizer.state) {    case UIGestureRecognizerStateBegan:    case UIGestureRecognizerStateChanged: {      self.panTranslationInCollectionView = [gestureRecognizer translationInView:self.collectionView];      CGPoint viewCenter = self.currentView.center = LXS_CGPointAdd(self.currentViewCenter, self.panTranslationInCollectionView);            [self invalidateLayoutIfNecessary];            switch (self.scrollDirection) {        case UICollectionViewScrollDirectionVertical: {          if (viewCenter.y < (CGRectGetMinY(self.collectionView.bounds) + self.scrollingTriggerEdgeInsets.top)) {            [self setupScrollTimerInDirection:LXScrollingDirectionUp];          } else {            if (viewCenter.y > (CGRectGetMaxY(self.collectionView.bounds) - self.scrollingTriggerEdgeInsets.bottom)) {              [self setupScrollTimerInDirection:LXScrollingDirectionDown];            } else {              [self invalidatesScrollTimer];            }          }        } break;        case UICollectionViewScrollDirectionHorizontal: {          if (viewCenter.x < (CGRectGetMinX(self.collectionView.bounds) + self.scrollingTriggerEdgeInsets.left)) {            [self setupScrollTimerInDirection:LXScrollingDirectionLeft];          } else {            if (viewCenter.x > (CGRectGetMaxX(self.collectionView.bounds) - self.scrollingTriggerEdgeInsets.right)) {              [self setupScrollTimerInDirection:LXScrollingDirectionRight];            } else {              [self invalidatesScrollTimer];            }          }        } break;      }    } break;    case UIGestureRecognizerStateCancelled:    case UIGestureRecognizerStateEnded: {      [self invalidatesScrollTimer];    } break;    default: {      // Do nothing...    } break;  }}#pragma mark - UICollectionViewLayout overridden methods- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {  NSArray *layoutAttributesForElementsInRect = [super layoutAttributesForElementsInRect:rect];    for (UICollectionViewLayoutAttributes *layoutAttributes in layoutAttributesForElementsInRect) {    switch (layoutAttributes.representedElementCategory) {      case UICollectionElementCategoryCell: {        [self applyLayoutAttributes:layoutAttributes];      } break;      default: {        // Do nothing...      } break;    }  }    return layoutAttributesForElementsInRect;}- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {  UICollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];    switch (layoutAttributes.representedElementCategory) {    case UICollectionElementCategoryCell: {      [self applyLayoutAttributes:layoutAttributes];    } break;    default: {      // Do nothing...    } break;  }    return layoutAttributes;}#pragma mark - UIGestureRecognizerDelegate methods- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {  if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {    return (self.selectedItemIndexPath != nil);  }  return YES;}- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {  if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {    return [self.panGestureRecognizer isEqual:otherGestureRecognizer];  }    if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {    return [self.longPressGestureRecognizer isEqual:otherGestureRecognizer];  }    return NO;}#pragma mark - Key-Value Observing methods- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {  if ([keyPath isEqualToString:kLXCollectionViewKeyPath]) {    if (self.collectionView != nil) {      [self setupCollectionView];    } else {      [self invalidatesScrollTimer];    }  }}#pragma mark - Notifications- (void)handleApplicationWillResignActive:(NSNotification *)notification {  self.panGestureRecognizer.enabled = NO;  self.panGestureRecognizer.enabled = YES;}#pragma mark - Depreciated methods#pragma mark Starting from 0.1.0- (void)setUpGestureRecognizersOnCollectionView {  // Do nothing...}@end

效果圖:

 

三、實現自己的layout

首先繼承LXReorderableCollectionViewFlowLayout,讓該類具有重新排序功能。

//// FWBookshelfCollectionViewLayout.h// FWPersonalApp//// Created by hzkmn on 16/2/18.// Copyright © 2016年 ForrstWoo. All rights reserved.//#import "LXReorderableCollectionViewFlowLayout.h"extern NSString * const FWBookshelfCollectionViewLayoutDecorationViewKind;@interface FWBookshelfCollectionViewLayout : LXReorderableCollectionViewFlowLayout@end

//// FWBookshelfCollectionViewLayout.m// FWPersonalApp//// Created by hzkmn on 16/2/18.// Copyright © 2016年 ForrstWoo. All rights reserved.//#import "FWBookshelfCollectionViewLayout.h"#import "FWBookShelfDecarationView.h"NSString * const FWBookshelfCollectionViewLayoutDecorationViewKind = @"FWBookshelfCollectionViewLayoutDecorationViewKind";@interface FWBookshelfCollectionViewLayout ()@property (nonatomic, strong) NSDictionary *bookShelfRectanges;@property NSInteger countOfRow;@end@implementation FWBookshelfCollectionViewLayout- (void)prepareLayout{  [super prepareLayout];    [self registerClass:[FWBookShelfDecarationView class] forDecorationViewOfKind:FWBookshelfCollectionViewLayoutDecorationViewKind];    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];    NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];  self.countOfRow = ceilf(itemCount / 3.0);  for (int row = 0; row < self.countOfRow; row++)  {    dictionary[[NSIndexPath indexPathForItem:row inSection:0]] = [NSValue valueWithCGRect:CGRectMake(0, kDecorationViewHeight * row, screenSize.width, kDecorationViewHeight)];  }    self.bookShelfRectanges = [NSDictionary dictionaryWithDictionary:dictionary];}#pragma mark Runtime Layout Calculations- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{  // call super so flow layout can return default attributes for all cells, headers, and footers  // NOTE: Flow layout has already taken care of the Cell view layout attributes! :)  NSArray *array = [super layoutAttributesForElementsInRect:rect];    // create a mutable copy so we can add layout attributes for any shelfs that  // have frames that intersect the rect the CollectionView is interested in  NSMutableArray *newArray = [array mutableCopy];  //  NSLog(@"in rect:%@",NSStringFromCGRect(rect));  // Add any decoration views (shelves) who's rect intersects with the  // CGRect passed to the layout by the CollectionView  [self.bookShelfRectanges enumerateKeysAndObjectsUsingBlock:^(id key, id shelfRect, BOOL *stop) {    //    NSLog(@"[shelfRect CGRectValue]:%@",NSStringFromCGRect([shelfRect CGRectValue]));        if (CGRectIntersectsRect([shelfRect CGRectValue], rect))    {      UICollectionViewLayoutAttributes *shelfAttributes =      [self layoutAttributesForDecorationViewOfKind:FWBookshelfCollectionViewLayoutDecorationViewKind                       atIndexPath:key];      [newArray addObject:shelfAttributes];    }  }];    for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++)  {    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];        [newArray addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];  }    return [newArray copy];}- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{  //  NSLog(@"%@", NSStringFromCGSize([self screenSize]));375 667  UICollectionViewLayoutAttributes *attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];    NSInteger currentRow = indexPath.item / 3;  CGRect frame = CGRectMake(20 + (indexPath.item % 3) * (kCellWidth + 17.5), 35+ currentRow * (kCellHeight + 65), kCellWidth, kCellHeight);  attris.frame = frame;  attris.zIndex = 1;    return attris;}- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind atIndexPath:(NSIndexPath *)indexPath{    id shelfRect = self.bookShelfRectanges[indexPath];    // this should never happen, but just in case...  if (!shelfRect)    return nil;    UICollectionViewLayoutAttributes *attributes =  [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:decorationViewKind                                withIndexPath:indexPath];  attributes.frame = [shelfRect CGRectValue];  //  NSLog(@"UICollectionViewLayoutAttributes :.%@", NSStringFromCGRect([shelfRect CGRectValue]));    attributes.zIndex = -1; // shelves go behind other views    return attributes;}- (CGSize)collectionViewContentSize{  CGSize contentSize = CGSizeMake(self.collectionView.bounds.size.width, self.countOfRow * kDecorationViewHeight + 20);    return contentSize;}@end

四、應用

//// FWAncientPoetryCollectionViewController.m// FWPersonalApp//// Created by hzkmn on 16/2/17.// Copyright © 2016年 ForrstWoo. All rights reserved.//#import "FWAncientPoetryCollectionViewController.h"#import "FWBookShelfDecarationView.h"#import "FWBookshelfCollectionViewLayout.h"#import "FWBookCategoryViewController.h"@interface FWAncientPoetryCollectionViewController () <LXReorderableCollectionViewDataSource, LXReorderableCollectionViewDelegateFlowLayout>@property (nonatomic, strong) NSMutableArray *books;@end@implementation FWAncientPoetryCollectionViewControllerstatic NSString * const cellReuseIdentifier = @"Cell";- (void)viewDidLoad {  [super viewDidLoad];  self.title = @"古籍";  self.collectionView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"bookShelfBackground.png"]];  [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellReuseIdentifier];  self.books = [[NSMutableArray alloc] initWithArray:[self bookNameOfAllBooks]];}- (NSArray *)bookNameOfAllBooks{ return [[FWDataManager getDataForPoetry] allKeys];}#pragma mark <UICollectionViewDataSource>- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{  return 1;}- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{  return [self.books count];}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{  UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellReuseIdentifier forIndexPath:indexPath];  UIImage *image = [UIImage imageNamed:self.books[indexPath.item]];  cell.backgroundColor = [UIColor colorWithPatternImage:image];  return cell;}- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath willMoveToIndexPath:(NSIndexPath *)toIndexPath{  NSString *theBookName = self.books[fromIndexPath.item];  [self.books removeObjectAtIndex:fromIndexPath.item];  [self.books insertObject:theBookName atIndex:toIndexPath.item];}#pragma mark - UICollectionViewDelegateFlowLayout- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{  return CGSizeMake(kCellWidth, kCellHeight);}- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{  FWBookCategoryViewController *vc = [[FWBookCategoryViewController alloc] initWithUrlString:[[FWDataManager getDataForPoetry] objectForKey:self.books[indexPath.item]]];  [self.navigationController pushViewController:vc animated:YES];}- (void)didReceiveMemoryWarning {  [super didReceiveMemoryWarning];  [self.books removeAllObjects];  self.books = nil;}@end

以上就是本文的全部內容,ios模仿實現書架效果,類似于手機上的掌上閱讀軟件的首頁,希望本文對大家的學習有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人www视频在线观看| y97精品国产97久久久久久| 国产精品一区二区三区在线播放| 91嫩草在线视频| 日韩视频免费中文字幕| 欧美巨猛xxxx猛交黑人97人| 亚洲欧洲美洲在线综合| 午夜精品一区二区三区视频免费看| 久久免费视频网| 亚洲精品国产综合区久久久久久久| 成人中文字幕+乱码+中文字幕| 国产不卡一区二区在线播放| 国产91精品高潮白浆喷水| 国产欧美韩国高清| 国产91精品久久久久久久| 国产区精品视频| 91精品国产色综合久久不卡98| 狠狠做深爱婷婷久久综合一区| 国产精品久久久久久五月尺| 欧美日韩亚洲系列| 亚洲欧美激情视频| 亚洲三级av在线| 国产亚洲精品va在线观看| 亚洲欧洲一区二区三区在线观看| 影音先锋日韩有码| 国产精品免费视频xxxx| 欧美在线不卡区| 国产在线一区二区三区| 国产视频亚洲精品| 欧美裸体视频网站| 国产精品三级久久久久久电影| 91久久久精品| 国产美女精品免费电影| 欧美日韩综合视频| 久久久91精品国产一区不卡| 久久久999国产精品| 国产精品综合不卡av| 91干在线观看| 欧美激情国产日韩精品一区18| 国产va免费精品高清在线| 欧美乱人伦中文字幕在线| 亚洲成色777777在线观看影院| 久久影院中文字幕| 久久亚洲精品视频| 国产精国产精品| 欧美国产欧美亚洲国产日韩mv天天看完整| 福利微拍一区二区| 伊是香蕉大人久久| 日韩高清av在线| 日韩欧美国产成人| 91国内揄拍国内精品对白| 国产精品久久久久久久久久小说| 国内精品久久久久久久久| 综合国产在线观看| 国产精品你懂得| 久久久久免费视频| 高跟丝袜欧美一区| 精品女厕一区二区三区| 色综合91久久精品中文字幕| 欧美日韩激情视频8区| 国产在线视频91| 亚洲小视频在线观看| 亚洲精品影视在线观看| 亚洲精品www久久久久久广东| 亚洲欧美中文在线视频| 欧美日韩aaaa| 91国内精品久久| 91香蕉亚洲精品| 亚洲国产成人久久综合| 91精品国产沙发| 美女视频黄免费的亚洲男人天堂| 深夜福利亚洲导航| 欧美在线视频在线播放完整版免费观看| 国内精品久久久久影院 日本资源| 国产精品情侣自拍| 久久视频在线免费观看| 欧美精品国产精品日韩精品| 欧洲成人免费视频| 欧美日韩国产一区二区三区| 国产精品免费久久久久影院| 色偷偷偷亚洲综合网另类| 久久久久久久国产精品视频| 亚洲第一免费网站| 国产成人精品一区二区| 亚洲精品www久久久久久广东| 日韩av观看网址| 国产欧美一区二区白浆黑人| 日产精品久久久一区二区福利| 亚洲欧美综合另类中字| 2020欧美日韩在线视频| 成人午夜在线影院| 成人有码在线视频| 日本久久久久久久| 国产欧美日韩中文字幕| 亚洲国产欧美一区二区三区久久| 98午夜经典影视| 久久久精品国产| 国产a∨精品一区二区三区不卡| 久久久97精品| 欧美日韩激情小视频| 久久香蕉精品香蕉| 亚洲欧美国内爽妇网| 亚洲国产天堂网精品网站| 久久国产精品久久久久久久久久| 国产欧美日韩综合精品| 自拍偷拍亚洲区| 欧美激情视频一区| 亚洲成人性视频| 国产成+人+综合+亚洲欧洲| 性夜试看影院91社区| 日韩免费av片在线观看| 午夜精品久久久久久久99黑人| 成人97在线观看视频| 精品久久久久人成| 91日本在线观看| 国产精品pans私拍| 亚洲国产精品人久久电影| 欧美最猛性xxxxx(亚洲精品)| 国内精品国产三级国产在线专| 亚洲国产精品va在线| 日本人成精品视频在线| 久久久国产精品x99av| 国产97色在线| 欧美精品免费播放| 亚洲欧洲一区二区三区在线观看| 中文字幕欧美日韩在线| 日韩欧美福利视频| 亚洲欧美激情另类校园| 97免费中文视频在线观看| 欧美激情国产精品| 狠狠躁夜夜躁人人躁婷婷91| 成人免费观看a| 91久久久久久久一区二区| 国产高清视频一区三区| 欧美日韩中文字幕在线| 久久久久久久一区二区三区| 午夜伦理精品一区| 欧美精品激情blacked18| 亚洲免费av网址| 欧美猛交ⅹxxx乱大交视频| 久久免费精品日本久久中文字幕| 亚洲欧美中文日韩v在线观看| 国产日产欧美a一级在线| 91精品国产99久久久久久| 欧美精品免费在线观看| 欧美日韩亚洲系列| 亚洲激情视频网站| 中文字幕日韩精品在线观看| 国产精品一区二区3区| 国产在线一区二区三区| 亚洲天堂成人在线| 久久久成人av| 日本不卡高字幕在线2019| 欧美国产在线视频| 国产一区二区免费| 国产精品久久久久久久av电影| 亚洲片国产一区一级在线观看| 人人爽久久涩噜噜噜网站| 国产99久久精品一区二区永久免费| 伊人久久久久久久久久久久久| 久久久天堂国产精品女人| 欧美性xxxxxxx| 欧美放荡办公室videos4k| 欧美大全免费观看电视剧大泉洋|