CardView
Mock tantan card flow interactive control, project address :(github.com/chenzhengxu…)
How do I use CardView
- Install via CocoaPods:
pod 'CardView'
- Manual import:
- Drag all files in the CardView folder into the project
- Import main file: #import “CardView”
CardView.h CardItemView.h
Copy the code
Control is introduced
Control mimics the TableView’s data source and proxy methods, as well as the TableViewCell’s cache pool logic
#import <UIKit/UIKit.h>
#import "CardItemView.h"
@class CardView;
@protocol CardViewDelegate <NSObject>
@optional
/** Which itemView*/ was clicked
- (void)cardView:(CardView *)cardView didClickItemAtIndex:(NSInteger)index;
@end
@protocol CardViewDataSource <NSObject>
@required
/** How many CardItemView objects are there */
- (NSInteger)numberOfItemViewsInCardView:(CardView *)cardView;
/** Returns the number of CardItemView objects */
- (CardItemView *)cardView:(CardView *)cardView itemViewAtIndex:(NSInteger)index;
/** request more data */
- (void)cardViewNeedMoreData:(CardView *)cardView;
@optional
- (CGSize)cardView:(CardView *)cardView sizeForItemViewAtIndex:(NSInteger)index;
@end
@interface CardView : UIView
/** Data source */
@property (nonatomic.weak) id <CardViewDataSource> dataSource;
Agent / * * * /
@property (nonatomic.weak) id <CardViewDelegate> delegate;
/** Get the identifier of the CardItemView object */
- (CardItemView *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
/** Delete the first CardItemView object from the left */
- (void)deleteTheTopItemViewWithLeft:(BOOL)left;
/** Reload the view */
- (void)reloadData;
@end
Copy the code
#import <UIKit/UIKit.h>
@class CardItemView;
@protocol CardItemViewDelegate <NSObject>
/** itemView removed from parent view */
- (void)cardItemViewDidRemoveFromSuperView:(CardItemView *)CardItemView;
/** How many angles did the item move, and whether it was animated */
- (void)cardItemViewDidMoveRate:(CGFloat)rate anmate:(BOOL)anmate;
@end
@interface CardItemView : UIView
Agent / * * * /
@property (weak.nonatomic) id<CardItemViewDelegate> delegate;
/** Identifier */
@property (nonatomic.readonly.copy) NSString *reuseIdentifier;
/** Initialize the view */
- (void)initView;
/** Initializes the view and binds the identifier */
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;
/** remove from parent view, whether from left */
- (void)removeWithLeft:(BOOL)left;
@end
Copy the code
The custom
Inherit from CardItemView to customize the card stream
Buffer pool
To optimize memory, a cache pool is set up to display four CardItemView objects simultaneously by default.
@property (copy, nonatomic) NSMutableDictionary *reuseDict;
Copy the code
At the same time, only CardItemView objects visible on the screen can be stored in memory, allowing multiple CardItemView objects with different ReuseIdentifiers to make cache calls. When the first CardItemView object is removed from the view, it will still be saved in the cache pool dictionary and called at the same time
- (CardItemView *)cardView:(CardView *)cardView itemViewAtIndex:(NSInteger)index;
Copy the code
Go get the last CardItemView object and add it to the view display.
By default, the datasource method is called five times ahead from the end, similar to the pull-up loading of the TableView
- (void)cardViewNeedMoreData:(CardView *)cardView;
Copy the code
animation
Animation principle, add UIPanGestureRecognizer on CardItemView, according to the drag feedback of the action method @selector(panGestHandle:), determine how much Angle the CardItemView object should be rotated. Should be removed from the superview.
- (void)panGestHandle:(UIPanGestureRecognizer *)panGest {
if (panGest.state == UIGestureRecognizerStateChanged) {
CGPoint movePoint = [panGest translationInView:self];
_isLeft = (movePoint.x < 0);
self.center = CGPointMake(self.center.x + movePoint.x, self.center.y + movePoint.y);
CGFloat angle = (self.center.x - self.frame.size.width / 2.0) / self.frame.size.width / 4.0;
_currentAngle = angle;
self.transform = CGAffineTransformMakeRotation(-angle);
[panGest setTranslation:CGPointZero inView:self];
if ([self.delegate respondsToSelector:@selector(cardItemViewDidMoveRate:anmate:)]) {
CGFloat rate = fabs(angle)/0.15>1 ? 1 : fabs(angle)/0.15;
[self.delegate cardItemViewDidMoveRate:rate anmate:NO]; }}else if (panGest.state == UIGestureRecognizerStateEnded) {
CGPoint vel = [panGest velocityInView:self];
if (vel.x > 800 || vel.x < - 800) {[self remove];
return ;
}
if (self.frame.origin.x + self.frame.size.width > 150 && self.frame.origin.x < self.frame.size.width - 150) {[UIView animateWithDuration:0.5 animations:^{
self.center = _originalCenter;
self.transform = CGAffineTransformMakeRotation(0);
if ([self.delegate respondsToSelector:@selector(cardItemViewDidMoveRate:anmate:)]) {
[self.delegate cardItemViewDidMoveRate:0 anmate:YES]; }}]; }else{[selfremove]; }}}Copy the code
According to the index index of the CardItemView object, the different frame of each card is adjusted to reflect the sense of stacking of the card.
CGSize size = [self itemViewSizeAtIndex:index];
[self insertSubview:itemView atIndex:0];
itemView.tag = index+1;
itemView.frame = CGRectMake(self.frame.size.width / 2.0 - size.width / 2.0.self.frame.size.height / 2.0 - size.height / 2.0, size.width, size.height);
Copy the code