Enhanced ZGPullDragScrollView

This commit is contained in:
Kyle Fang
2013-02-27 08:31:20 +08:00
parent 4fb61a3185
commit fccdd0c004
7 changed files with 292 additions and 20 deletions

View File

@@ -6,7 +6,6 @@ platform :ios, '6.0'
pod 'AHAlertView', '~>0.0.2'
pod 'GVUserDefaults', '~>0.9.0'
pod 'SVProgressHUD', '~>0.9'
pod 'ZGPullDragScrollView', '~>0.0.1'
target :ProgressTests, :exclusive => true do
pod 'GVUserDefaults', '~>0.9.0'

View File

@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
040E055516DD864D00E0731D /* UIScrollView+ZGPullDrag.m in Sources */ = {isa = PBXBuildFile; fileRef = 040E055416DD864D00E0731D /* UIScrollView+ZGPullDrag.m */; };
041C811716DB0DFB0034A3A8 /* GVUserDefaults+Progress.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FD824616DB02910028AF2A /* GVUserDefaults+Progress.m */; };
041C811B16DB0EAD0034A3A8 /* PPEvenKitManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FD824116DAFB770028AF2A /* PPEvenKitManager.m */; };
041C811E16DB0F080034A3A8 /* PPEvenKitManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 041C811D16DB0F080034A3A8 /* PPEvenKitManagerTest.m */; };
@@ -50,6 +51,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
040E055316DD864D00E0731D /* UIScrollView+ZGPullDrag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+ZGPullDrag.h"; sourceTree = "<group>"; };
040E055416DD864D00E0731D /* UIScrollView+ZGPullDrag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+ZGPullDrag.m"; sourceTree = "<group>"; };
041C811C16DB0F080034A3A8 /* PPEvenKitManagerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPEvenKitManagerTest.h; sourceTree = "<group>"; };
041C811D16DB0F080034A3A8 /* PPEvenKitManagerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPEvenKitManagerTest.m; sourceTree = "<group>"; };
04386A0B16908C4C0058C876 /* Progress.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Progress.entitlements; sourceTree = "<group>"; };
@@ -158,6 +161,8 @@
04BDDECA16902D0900D04A9E /* Progress */ = {
isa = PBXGroup;
children = (
040E055316DD864D00E0731D /* UIScrollView+ZGPullDrag.h */,
040E055416DD864D00E0731D /* UIScrollView+ZGPullDrag.m */,
048D437016DBC4E000A40CB1 /* ReminderItemCell.h */,
048D437116DBC4E000A40CB1 /* ReminderItemCell.m */,
048D433E16DB9D5300A40CB1 /* PPRemindersViewController.h */,
@@ -365,6 +370,7 @@
04FD824716DB02910028AF2A /* GVUserDefaults+Progress.m in Sources */,
048D434016DB9D5400A40CB1 /* PPRemindersViewController.m in Sources */,
048D437216DBC4E000A40CB1 /* ReminderItemCell.m in Sources */,
040E055516DD864D00E0731D /* UIScrollView+ZGPullDrag.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -9,7 +9,7 @@
#import "PPRemindersViewController.h"
#import "PPEvenKitManager.h"
#import <SVProgressHUD/SVProgressHUD.h>
#import <UIScrollView+ZGPullDrag.h>
#import "UIScrollView+ZGPullDrag.h"
#import <NUI/NUIConverter.h>
#import <NUI/NUIGraphics.h>
#import "ReminderItemCell.h"
@@ -17,6 +17,8 @@
@interface PPRemindersViewController () <ReminderItemCellDelegate, ZGPullDragViewDelegate>
@property (strong, nonatomic) IBOutlet UIView *pullDownView;
@property (nonatomic, strong) UITableViewCell *placeHolderCell;
@property (nonatomic, strong) UITableViewCell *editingCell;
@property (nonatomic) BOOL isEdingAReminder;
@property (nonatomic) NSArray *remindersDatasource;
@end
@@ -24,10 +26,13 @@
static NSString *CellIdentifier = @"ReminderCell";
- (void)viewDidLoad
{
[super viewDidLoad];
self.isEdingAReminder = NO;
self.clearsSelectionOnViewWillAppear = NO;
self.navigationController.navigationBarHidden = YES;
@@ -72,35 +77,35 @@ static NSString *CellIdentifier = @"ReminderCell";
if (!_placeHolderCell) {
_placeHolderCell = [[UITableViewCell alloc] initWithFrame:CGRectZero];
_placeHolderCell.frame = CGRectMake(0, 0, self.view.frame.size.width, self.tableView.rowHeight);
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 29, 300, 21)];
textField.borderStyle = UITextBorderStyleNone;
textField.font = [UIFont systemFontOfSize:17.0];
textField.tag = 1;
[_placeHolderCell addSubview:textField];
}
return _placeHolderCell;
}
- (void)pullView:(UIView *)pullView hangForCompletionBlock:(void (^)())completed{
[[self.placeHolderCell viewWithTag:1] becomeFirstResponder];
- (void)userPullOrDragStoppedWithPullView:(UIView *)pullView dragView:(UIView *)dragView{
NSLog(@"Stopped");
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.remindersDatasource.count;
return self.isEdingAReminder ? self.remindersDatasource.count+1 : self.remindersDatasource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ReminderItemCell *cell = [[ReminderItemCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
EKReminder *reminder = [self.remindersDatasource objectAtIndex:indexPath.row];
cell.delegate = self;
cell.textLabel.text = reminder.title;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", indexPath.row];
cell.accessoryType = reminder.completed ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
if (self.isEdingAReminder && indexPath.row == 0) {
return self.editingCell;
} else {
ReminderItemCell *cell = [[ReminderItemCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
EKReminder *reminder = [self.remindersDatasource objectAtIndex:self.isEdingAReminder?indexPath.row-1:indexPath.row];
cell.delegate = self;
cell.textLabel.text = reminder.title;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", indexPath.row];
cell.accessoryType = reminder.completed ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{

View File

@@ -29,11 +29,11 @@
UIImageView *checkMarkView = [[UIImageView alloc] initWithFrame:checkMarkOriginFrame];
checkMarkView.backgroundColor = [UIColor greenColor];
checkMarkView.highlightedImage = nil;
checkMarkView.alpha = 0;
checkMarkView.tag = 1;
UIImageView *deleteMarkView = [[UIImageView alloc] initWithFrame:deleteMarkOriginFrame];
deleteMarkView.backgroundColor = [UIColor redColor];
deleteMarkView.highlightedImage = nil;
deleteMarkView.alpha = 0;
deleteMarkView.tag = 2;
[self insertSubview:checkMarkView atIndex:0];
[self insertSubview:deleteMarkView atIndex:0];
@@ -73,7 +73,9 @@
if (gesture.state == UIGestureRecognizerStateBegan) {
self.originalCenter = self.center;
checkMarkView.frame = checkMarkOriginFrame;
checkMarkView.alpha = 0;
deleteMarkView.frame = deleteMarkOriginFrame;
deleteMarkView.alpha = 0;
} else {
CGPoint translation = [gesture translationInView:self];
CGFloat xOffset = translation.x;
@@ -81,7 +83,9 @@
self.center = CGPointMake(self.originalCenter.x+xOffset, self.originalCenter.y);
if (xOffset>-kDefaultEdageXOffset && xOffset<kDefaultEdageXOffset) {
checkMarkView.frame = CGRectOffset(checkMarkOriginFrame, -xOffset, 0);
checkMarkView.alpha = fabs(xOffset)/80.f;
deleteMarkView.frame = CGRectOffset(deleteMarkOriginFrame, -xOffset, 0);
deleteMarkView.alpha = fabs(xOffset)/80.f;
}
} else if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateCancelled) {
if (xOffset>kDefaultEdageXOffset) {

View File

@@ -0,0 +1,32 @@
//
// UIScrollView+ZGPullDrag.h
// ZGPullDragScrollView
//
// Created by Kyle Fang on 2/26/13.
// Copyright (c) 2013 Kyle Fang. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol ZGPullDragViewDelegate <NSObject>
@optional
//Push Down
- (void)pullView:(UIView *)pullView Show:(CGFloat )shownPixels ofTotal:(CGFloat )totalPixels;
- (void)pullView:(UIView *)pullView hangForCompletionBlock:(void (^)())completed;
//Drag Up
- (void)dragView:(UIView *)dragView Show:(CGFloat )showPixels ofTotal:(CGFloat )totalPixels;
- (void)dragView:(UIView *)dragView hangForCompletionBlock:(void (^)())completed;
//User Pull or Drag stopped
- (void)userPullOrDragStoppedWithPullView:(UIView *)pullView dragView:(UIView *)dragView;
@end
@interface UIScrollView (ZGPullDrag)
- (void)addZGPullView:(UIView *)pullView;
- (void)addZGDragView:(UIView *)dragView;
@property (nonatomic) id <ZGPullDragViewDelegate> pullDragDelegate;
@end

View File

@@ -0,0 +1,203 @@
//
// UIScrollView+ZGPullDrag.m
// ZGPullDragScrollView
//
// Created by Kyle Fang on 2/26/13.
// Copyright (c) 2013 Kyle Fang. All rights reserved.
//
#import "UIScrollView+ZGPullDrag.h"
#import <objc/runtime.h>
static char UIScrollViewZGPullDragViewDelegate;
static char UIScrollViewZGPullDragViewObserving;
static char UIScrollViewZGPullView;
static char UIScrollViewZGDragView;
static char UIScrollViewWasDragging;
@interface UIScrollView (ZGPullDragPropertyCategory)
@property (nonatomic) BOOL isObserving;
@property (nonatomic, assign) UIView *pullView;
@property (nonatomic, assign) UIView *dragView;
@property (nonatomic) BOOL wasDragging;
@end
@implementation UIScrollView (ZGPullDragPropertyCategory)
- (void)setIsObserving:(BOOL)isObserving {
if (self.isObserving == YES && isObserving == NO) {
@try {
[self removeObserver:self forKeyPath:@"contentOffset"];
}
@catch (NSException *exception) {
//It's not observing
}
} else if (self.isObserving == NO && isObserving == YES) {
[self addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
[self willChangeValueForKey:@"isObserving"];
objc_setAssociatedObject(self, &UIScrollViewZGPullDragViewObserving,
[NSNumber numberWithBool:isObserving],
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self didChangeValueForKey:@"isObserving"];
}
- (BOOL)isObserving {
NSNumber *number = objc_getAssociatedObject(self, &UIScrollViewZGPullDragViewObserving);
if (number == nil) {
return NO;
} else {
return [number boolValue];
}
}
- (void)setPullView:(UIView *)pullView{
[self willChangeValueForKey:@"pullView"];
objc_setAssociatedObject(self, &UIScrollViewZGPullView, pullView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self didChangeValueForKey:@"pullView"];
}
- (UIView *)pullView{
return objc_getAssociatedObject(self, &UIScrollViewZGPullView);
}
- (void)setDragView:(UIView *)dragView{
[self willChangeValueForKey:@"dragView"];
objc_setAssociatedObject(self, &UIScrollViewZGDragView, dragView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self didChangeValueForKey:@"dragView"];
}
- (UIView *)dragView{
return objc_getAssociatedObject(self, &UIScrollViewZGDragView);
}
- (void)setWasDragging:(BOOL)wasDragging{
[self willChangeValueForKey:@"wasDragging"];
objc_setAssociatedObject(self, &UIScrollViewWasDragging, [NSNumber numberWithBool:wasDragging], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self didChangeValueForKey:@"wasDragging"];
}
- (BOOL)wasDragging{
NSNumber *number = objc_getAssociatedObject(self, &UIScrollViewWasDragging);
if (number == nil) {
return NO;
} else {
return [number isEqualToNumber:@YES];
}
}
@end
@implementation UIScrollView (ZGPullDrag)
@dynamic pullDragDelegate;
- (void)setPullDragDelegate:(id<ZGPullDragViewDelegate>)pullDragDelegate{
[self willChangeValueForKey:@"pullDragDelegate"];
objc_setAssociatedObject(self, &UIScrollViewZGPullDragViewDelegate, pullDragDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self didChangeValueForKey:@"pullDragDelegate"];
}
- (id<ZGPullDragViewDelegate>)pullDragDelegate{
return objc_getAssociatedObject(self, &UIScrollViewZGPullDragViewDelegate);
}
- (void)addZGPullView:(UIView *)pullView{
if (self.pullView != pullView) {
[self.pullView removeFromSuperview];
}
pullView.frame = CGRectOffset(pullView.frame, -pullView.frame.origin.x, -pullView.frame.origin.y-pullView.frame.size.height);
[self addSubview:pullView];
self.pullView = pullView;
self.isObserving = YES;
}
- (void)addZGDragView:(UIView *)dragView{
if (self.dragView != dragView) {
[self.dragView removeFromSuperview];
}
[self layoutIfNeeded];
CGFloat originY = MAX(self.frame.size.height, self.contentSize.height);
dragView.frame = CGRectOffset(dragView.frame, -dragView.frame.origin.x, -dragView.frame.origin.y+originY);
[self addSubview:dragView];
self.dragView = dragView;
self.isObserving = YES;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:@"contentOffset"]) {
[self scrollViewDidScroll:[[change valueForKey:NSKeyValueChangeNewKey] CGPointValue]];
}
}
- (void)scrollViewDidScroll:(CGPoint )contentOffset {
CGFloat yOffset = contentOffset.y;
if (yOffset<0) {
[self pullViewHandler:-yOffset];
} else if (self.dragView.frame.origin.y == self.frame.size.height) {
[self dragViewHandler:yOffset];
} else if (self.dragView.frame.origin.y == self.contentSize.height && yOffset > self.dragView.frame.origin.y - self.frame.size.height) {
[self dragViewHandler:yOffset-(self.dragView.frame.origin.y - self.frame.size.height)];
}
if (self.wasDragging && !self.isDragging) {
if ([self.pullDragDelegate respondsToSelector:@selector(userPullOrDragStoppedWithPullView:dragView:)]) {
[self.pullDragDelegate userPullOrDragStoppedWithPullView:self.pullView dragView:self.dragView];
}
}
self.wasDragging = self.isDragging;
}
- (void)pullViewHandler:(CGFloat )visiblePixels{
if ([self.pullDragDelegate respondsToSelector:@selector(pullView:Show:ofTotal:)]) {
[self.pullDragDelegate pullView:self.pullView Show:visiblePixels ofTotal:self.pullView.frame.size.height];
}
if (visiblePixels>self.pullView.frame.size.height && !self.isDragging && [self.pullDragDelegate respondsToSelector:@selector(pullView:hangForCompletionBlock:)]) {
[UIView animateWithDuration:0.1
animations:^{
self.contentInset = UIEdgeInsetsMake(self.pullView.frame.size.height, 0, 0, 0);
} completion:^(BOOL finished) {
[self.pullDragDelegate pullView:self.pullView hangForCompletionBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[UIView animateWithDuration:0.2 animations:^{
self.contentInset = UIEdgeInsetsZero;
}];
}];
}];
}];
}
}
- (void)dragViewHandler:(CGFloat )visiblePixels{
if ([self.pullDragDelegate respondsToSelector:@selector(dragView:Show:ofTotal:)]) {
[self.pullDragDelegate dragView:self.dragView Show:visiblePixels ofTotal:self.dragView.frame.size.height];
}
if (visiblePixels>self.dragView.frame.size.height && !self.isDragging && [self.pullDragDelegate respondsToSelector:@selector(dragView:hangForCompletionBlock:)]) {
[UIView animateWithDuration:0.1
animations:^{
if (self.dragView.frame.origin.y == self.frame.size.height) {
self.contentInset = UIEdgeInsetsMake(0, 0, self.dragView.frame.size.height + self.frame.size.height - self.contentSize.height, 0);
} else {
self.contentInset = UIEdgeInsetsMake(0, 0, self.dragView.frame.size.height, 0);
}
} completion:^(BOOL finished) {
[self.pullDragDelegate dragView:self.dragView hangForCompletionBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[UIView animateWithDuration:0.2 animations:^{
self.contentInset = UIEdgeInsetsZero;
}];
}];
}];
}];
}
}
- (void)dealloc{
if (self.isObserving) {
self.isObserving = NO;
}
}
@end

View File

@@ -13,9 +13,32 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ReminderCell" textLabel="Gi2-2j-rob" detailTextLabel="nvd-Qt-JxD" style="IBUITableViewCellStyleValue1" id="dwc-W6-Rod" customClass="ReminderItemCell">
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="EditingCell" id="h0U-eI-tuO">
<rect key="frame" x="0.0" y="22" width="320" height="80"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="79"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="#task" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="J3Y-ph-mra">
<constraints>
<constraint firstAttribute="width" constant="300" id="0si-pG-2j5"/>
<constraint firstAttribute="height" constant="30" id="Es2-z9-CFd"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstItem="J3Y-ph-mra" firstAttribute="centerY" secondItem="h0U-eI-tuO" secondAttribute="centerY" type="default" id="E5b-2u-6yA"/>
<constraint firstItem="J3Y-ph-mra" firstAttribute="centerX" secondItem="h0U-eI-tuO" secondAttribute="centerX" type="default" id="Wyp-B5-Ez8"/>
</constraints>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ReminderCell" textLabel="Gi2-2j-rob" detailTextLabel="nvd-Qt-JxD" style="IBUITableViewCellStyleValue1" id="dwc-W6-Rod" customClass="ReminderItemCell">
<rect key="frame" x="0.0" y="102" width="320" height="80"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="79"/>
<autoresizingMask key="autoresizingMask"/>