I've subclassed a UITableViewCell to create custom layout and animations for my table view. Basically, when I swipe left, I enter edit mode and when I swipe right, I exit edit mode -- each with the appropriate animation.
The swiping is working as expected, but I can't seem to figure out how to set a cell to a non-editing state whenever the table view scrolls or another cell enter the editing state.
The idea is to reset the cell to the "normal" state whenever the tableview scrolls or the users starts editing (swipes left) on another cell.
Here's my custom UITableViewCell class:
//
// CustomTableViewCell.m
//
// Created by Spencer Müller Diniz on 27/03/13.
// Copyright (c) 2013 Family. All rights reserved.
//
#import "CustomTableViewCell.h"
#implementation CustomTableViewCell
#synthesize customView;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
CGRect customFrame = CGRectMake(0.0f, 0.0f, self.contentView.bounds.size.width, self.contentView.bounds.size.height);
self.customView = [[CustomTableViewCellView alloc] initWithFrame:customFrame];
[self.contentView addSubview:self.customView];
UISwipeGestureRecognizer* sgrLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(cellSwipedLeft:)];
[sgrLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[self addGestureRecognizer:sgrLeft];
UISwipeGestureRecognizer* sgrRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(cellSwipedRight:)];
[sgrRight setDirection:UISwipeGestureRecognizerDirectionRight];
[self addGestureRecognizer:sgrRight];
}
return self;
}
- (void)cellSwipedLeft:(UIGestureRecognizer *)gestureRecognizer {
if (!self.isEditing)
[self setEditing:YES animated:YES];
}
- (void)cellSwipedRight:(UIGestureRecognizer *)gestureRecognizer {
if (self.isEditing)
[self setEditing:NO animated:YES];
}
- (void)layoutSubviews {
if (self.isEditing) {
[UIView animateWithDuration:0.5f animations:^{
self.customView.forgroundView.frame = CGRectMake(-100.0f, 0.0f, self.customView.forgroundView.frame.size.width, self.customView.forgroundView.frame.size.height);
}];
}
else {
[UIView animateWithDuration:0.5f animations:^{
self.customView.forgroundView.frame = CGRectMake(0.0f, 0.0f, self.customView.forgroundView.frame.size.width, self.customView.forgroundView.frame.size.height);
}];
}
}
#end
Related
I have a custom UIView with a UICollectionView.
On screen rotation I am trying to get the UICollectionView to stretch across the screen, and then redraw its cells.
After I had the data downloaded I tried both [grid setNeedsLayout] and [grid setNeedsDisplay] but that didn't work.
This is what I want to happen:
Portrait
Landscape
(This is also how it appears when the app is started in landscape, but if you change to portrait it doens't update.)
But this is what I get if I start in Portrait mode and switch to Landscape.
I am creating these views programmatically. I am not using any Storyboards.
I have tried:
-(void)viewDidLayoutSubviews {
grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
}
I have also tried toying with:
- (void) viewWillLayoutSubviews {
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
//LANDSCAPE
if(grid){
NSLog(#"Grid Needs Landscape Layout");
grid.frame =CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
[grid refreshData];
}
}else {
//PORTRIAT
if(grid){
NSLog(#"Grid Needs Portrait Layout");
grid.frame =CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
[grid refreshData];
}
}
}
But I can't get it to stretch.
Any help?
MyThumbnailGridView
#interface ViewController () <UINavigationControllerDelegate> {
MyThumbnailGridView *grid;
NSMutableArray * arrImages;
}
- (void)viewDidLoad {
[super viewDidLoad];
arrImages = [NSMutableArray new];
grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
//grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectZero];
NSLog(#"showThumbnailGrid Grid View Size: %#", NSStringFromCGRect(grid.frame));
[self.view addSubview:grid];
[self getListOfImages];
}
-(void) getListOfImages {
//Do background task to get images and fill arrImages
[self onDownloadImageDataComplete];
}
- (void) onDownloadImageDataComplete{
grid.imageDataSource = arrImages;
// [grid setNeedsLayout];
// [grid setNeedsDisplay];
}
//...
#end
*MyThumbnailGridView.h
#interface MyThumbnailGridView : UIView
-(id)initWithFrame:(CGRect)frame;
-(void) refreshData;
#property (nonatomic,strong) NSArray *imageDataSource;
#end
*MyThumbnailGridView.m
#interface MyThumbnailGridView () <UICollectionViewDelegate, UICollectionViewDataSource>{
UICollectionView *collectionView;
}
#end
#implementation MyThumbnailGridView
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self){
[self customInit];
}
return self;
}
- (void) customInit {
collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:[[MyFlowLayout alloc] init]];
collectionView.delegate = self;
collectionView.dataSource = self;
collectionView.allowsMultipleSelection = NO;
collectionView.showsVerticalScrollIndicator = YES;
[collectionView setBackgroundColor:[UIColor darkGrayColor]];
[collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:#"MyId"];
[self addSubview:collectionView];
}
- (void) refreshData {
NSLog(#"Refresh Grid Data");
[collectionView reloadData];
}
////other code
#end
MyFlowLayout
#interface MyFlowLayout : UICollectionViewFlowLayout
#end
#implementation MyFlowLayout
- (instancetype)init{
self = [super init];
if (self)
{
self.minimumLineSpacing = 1.0;
self.minimumInteritemSpacing = 1.0;
self.scrollDirection = UICollectionViewScrollDirectionVertical;
}
return self;
}
- (CGSize)itemSize {
NSInteger numberOfColumns = 3;
CGFloat itemWidth = (CGRectGetWidth(self.collectionView.frame) - (numberOfColumns - 1)) / numberOfColumns;
return CGSizeMake(itemWidth, itemWidth);
}
#end
MyCollectionViewCell
#interface MyCollectionViewCell : UICollectionViewCell
#property (strong, nonatomic) UIImageView *imageView;
#end
#implementation MyCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.imageView = [UIImageView new];
[self.imageView setContentMode:UIViewContentModeScaleAspectFill];
[self.imageView setClipsToBounds:YES];
[self.imageView setBackgroundColor:[UIColor darkGrayColor]];
[self.contentView addSubview:self.imageView];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.imageView.image = nil;
[self.imageView setHidden:NO];
}
- (void)layoutSubviews {
[super layoutSubviews];
[self.imageView setFrame:self.contentView.bounds];
}
#end
This can be solved with
either you can change the frame of MyThumbnailGridView view in delegate function of orientation or create the view with constraints like this
(void)viewDidLoad {
[super viewDidLoad];
arrImages = [NSMutableArray new];
grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
[self.view addSubview:grid];
[self getListOfImages];
}
-(void)viewDidLayoutSubviews
{
if(Once){
Once = NO;
// adding constraints
MyThumbnailGridView.translatesAutoresizingMaskIntoConstraints = NO;
[self.MyThumbnailGridView.widthAnchor constraintEqualToConstant:self.view.frame.size.width].active = YES;
[self.MyThumbnailGridView.heightAnchor constraintEqualToConstant:self.view.frame.size.height/2].active = YES;
[self.MyThumbnailGridView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[self.MyThumbnailGridView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:self.view.frame.size.height/2].active = YES;
}
}
Also implement this
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[self.view layoutIfNeeded];
[MyThumbnailGridView.collectionView invalidate];
// Do view manipulation here.
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
The problem is that the collection view itself is not changing size when the app rotates. You have given the collection view a fixed frame and then just walked away. So it never changes. So never lays itself out again.
You should give your MyThumbnailGridView and its collection view subview autolayout contraints to their superviews, so that they change size correctly when the app rotates.
I'm trying to add the move gesture of uiview inside uiscrollview but I can not disable the srcoll event of uiscrollview. I have implemented the UIScrollview with paging enable in Main class. In another class, i added uiview in it, add gesture for it but i dont know how to disable scrolling of uiscrollview.
Please give me some advice. Thanks in advance.
You need to communicate from your UIView class with gesture in it by means of delegate to the main class asking scroll view to stop scrolling and later on enabling it. I have enclosed the code.
Your UIView.h file
#protocol MyUIViewProtocol <NSObject>
- (void)setScrollViewScrollEnabled:(BOOL)enabled;
#end
#interface MyUIView : UIView
#property (weak, nonatomic) id<MyUIViewProtocol> delegate;
#end
Your UIView.m file
#implementation MyUIView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self setBackgroundColor:[UIColor redColor]];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureMade:)];
[self addGestureRecognizer:panGesture];
}
return self;
}
- (void)panGestureMade:(UIPanGestureRecognizer *)recognizer
{
CGPoint pointsToMove = [recognizer translationInView:self];
[self setCenter:CGPointMake(self.center.x + pointsToMove.x, self.center.y + pointsToMove.y)];
[recognizer setTranslation:CGPointZero inView:self];
//Disable the scroll when gesture begins and enable the scroll when gesture ends.
if (self.delegate && [self.delegate respondsToSelector:#selector(setScrollViewScrollEnabled:)]) {
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self.delegate setScrollViewScrollEnabled:NO];
}
else if (recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateEnded) {
[self.delegate setScrollViewScrollEnabled:YES];
}
}
}
Your main class file with scroll view in it.
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 568)];
[self.scrollView setBackgroundColor:[UIColor yellowColor]];
[self.scrollView setPagingEnabled:YES];
[self.scrollView setContentSize:CGSizeMake(320 * 3, 568)];
[self.view addSubview:self.scrollView];
MyUIView *view = [[MyUIView alloc] initWithFrame:CGRectMake(40, 100, 100, 100)];
view.delegate = self;
[self.scrollView addSubview:view];
}
- (void)setScrollViewScrollEnabled:(BOOL)enabled
{
[self.scrollView setScrollEnabled:enabled];
}
Hope this answer helps you.
This question already has answers here:
iOS - Dismiss keyboard when touching outside of UITextField
(38 answers)
Closed 8 years ago.
I have one TableViewCell that has UITextField in it.
I want when click out of UITextField hidden keyboard but I don't about that.
this is my code:
#implementation TextFieldCell
#synthesize Textfield,placeholder;
- (void)awakeFromNib
{
// Initialization code
Textfield = [self makeTextField];
[self addSubview:Textfield];
placeholder = [self PlaceHolderLabel];
[self addSubview:placeholder];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (UITextField *)makeTextField
{
CGRect TextFrame = CGRectMake(0,0,300,80);
UITextField *textfield = [[UITextField alloc]initWithFrame:TextFrame];
textfield.delegate = self;
textfield.textColor = [UIColor colorWithRed:0/256.0 green:84/256.0 blue:129/256.0 alpha:1.0];
textfield.backgroundColor = [UIColor yellowColor];
textfield.placeholder = [NSString stringWithFormat:#"Mamal"];
UIView *spacerleftView = [[UIView alloc] initWithFrame:CGRectMake(0,0,20,20)];
UIView *spacerrightView = [[UIView alloc] initWithFrame:CGRectMake(0,0,20,20)];
[textfield setLeftViewMode:UITextFieldViewModeAlways];
[textfield setRightViewMode:UITextFieldViewModeAlways];
textfield.leftView = spacerleftView;
textfield.rightView = spacerrightView;
return textfield;
}
- (UILabel *)PlaceHolderLabel{
NSString *labelText = Textfield.placeholder;
Textfield.placeholder = nil;
CGRect labelFrame = CGRectMake(0,0,280,80);
UILabel *placeholderLabel = [[UILabel alloc] initWithFrame:labelFrame];
[placeholderLabel setTextColor:[UIColor lightGrayColor]];
[placeholderLabel setText:labelText];
placeholderLabel.textAlignment = NSTextAlignmentRight;
return placeholderLabel;
}
- (UILabel *)clearPlaceHolderLabel{
NSString *labelText = nil;
CGRect labelFrame = CGRectMake(0,0,280,80);
UILabel *placeholderLabel = [[UILabel alloc] initWithFrame:labelFrame];
[placeholderLabel setText:labelText];
return placeholderLabel;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//Keyboard becomes visible
//perform actions.
NSLog(#"start");
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"end");
}
Add gesture recogniser in viewDidLoad :
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(closeKeyboard:)];
[self.view addGestureRecognizer:tap];
and then implement closeKeyboard:
- (IBAction)closeKeyboard:(id)sender {
[self.view endEditing:YES];}
my friend I had this problem but I can solve that.
you don't need add UITextField in TableViewCell , you can create TextField in ViewController or TableViewController that your tableView is inner it and then add TextField inside any cell that you want.
like this code:
ViewController.h
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate>
#property (nonatomic,strong) UITableView *table;
#property (weak,nonatomic) UITextField *Textfield;
ViewController.m
#implementation ViewController
#synthesize table,Textfield;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//add table in view
table = [self makeTableView];
[self.view addSubview:table];
[self.view setBackgroundColor: RGB(193,60,46)]; //will give a UIColor objct
//run textfield programmatically
Textfield = [self makeTextField];
//hide keyboard with hideKeyboard selector
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.table addGestureRecognizer:gestureRecognizer];
}
- (void) hideKeyboard {
[Textfield resignFirstResponder];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
Try to use
[self.view setEditing:YES];
in -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
try this:
// somewhere in viewDidLoad
UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnBackground)];
[self.view addGestureRecognizer:tapRecognizer];
self.view.userInteractionEnabled = YES;
// ...
- (void)tapOnBackground
{
[self.view endEditing:YES];
}
Add this code in your textField implementation method.
//Set to Remove Keyboard from view
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
After that create dismissKeyboard method.
//First Responder Remove Keyboard
-(void)dismissKeyboard {
[Textfield resignFirstResponder];
}
I'm trying for a while to build an ebook, flipping page (from left to right) and zooming.
So far I've tested a few projects but none of them was good enough to do both.
I've decided to build one of my own, so I started with basic flip animation like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.scrollView.delegate = self;
self.scrollView.maximumZoomScale = 5.0f;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tapGesture.delegate = self;
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:tapGesture];
}
#pragma mark - UIScrollView Delegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
#pragma mark - UIGestureRecognizer Delegate
- (void)handleTap:(UITapGestureRecognizer *)tapGestur
{
NSLog(#"%s", __PRETTY_FUNCTION__);
if (tapGestur.state == UIGestureRecognizerStateEnded) {
[UIView transitionWithView:self.imageView duration:1 options:UIViewAnimationOptionTransitionFlipFromRight|UIViewAnimationOptionCurveEaseInOut animations:^{
if (!flipped) {
self.imageView.image = [UIImage imageNamed:#"2-IPAD-P.jpg"];
flipped = YES;
}
else {
self.imageView.image = [UIImage imageNamed:#"1-IPAD-P.jpg"];
}
} completion:^(BOOL finished) {
//
}];
}
}
What I'm trying to do now is transition flipping page (left to right) from the middle of the image.
Any idea how can I do this using UIVIew? Or maybe better options?
You should also give a look to CATansition. Have a look at this example.
Also, have you looked at UIViewAnimationOptions's UIViewAnimationOptionTransitionCurlUp and UIViewAnimationOptionTransitionCurlDown for page animations ?
I have a very simple RootView Controller ->Detail View Controller, to display a list of core data object and show details on a selected object in the DetailViewController.
The DetailViewController is a UITableView with custom UITableViewCell that has a UITextField to allow user edits.
I am able to display the table, able to edit the text field and so on. However, I am not sure how to actually update the manage object once the user chooses the Done button or cancel the changes upon a Cancel button action.
I understand I can probably achieve this by using a EditViewController, that can be used to edit one property at a time. But, I am interested in a solution where I could support inline editing in the DetailViewController. Any suggestions would be very helpful.
Thanks,
Custom UITableView Cell code
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
_textField = [[UITextField alloc] initWithFrame:CGRectZero];
[_textField setTextAlignment:UITextAlignmentLeft];
[_textField setReturnKeyType:UIReturnKeyDone];
[_textField setClearButtonMode:UITextFieldViewModeWhileEditing];
[_textField setDelegate:self];
[[self contentView] addSubview:_textField];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void) layoutSubviews {
[super layoutSubviews];
CGRect contentRect = [self.contentView bounds];
// In this example we will never be editing, but this illustrates the appropriate pattern
if ([self isEditing]) {
self.textLabel.frame = CGRectZero;
self.textField.frame = CGRectMake(contentRect.origin.x + kCellLeftOffset, kCellTopOffset, contentRect.size.width - kCellLeftOffset, kCellHeight);
}
else {
CGRect frame = CGRectMake(contentRect.origin.x + kCellLeftOffset, kCellTopOffset, 90, kCellHeight);
CGRect textFrame = CGRectMake(frame.origin.x + frame.size.width + kCellLeftOffset, kCellTopOffset, 180, kCellHeight);
self.textLabel.frame = frame;
self.textField.frame = textFrame;
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (!editing)
[_textField resignFirstResponder];
}
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
return [self isEditing];
}
The text editing should really be handled in a controller rather than a view. Your custom cell is a view, the appropriate place to put the text field delegate methods would be the detail view controller.
Here is your solution:
Pass the managedObjectModel of your root view controller to your detail view controller as a property. Do the same with the managed object to be edited.
In the delegate methods of your text field, update the object's properties as appropriate
- (void)textFieldDidEndEditing:(UITextField *)textField {
self.managedObject.textAttribute = textField.text;
}
Finally, in your handlers of the Done and Cancel buttons, save or discard the changes:
-(void)cancel {
[self.managedObjectContext rollback];
[self dismissModalViewControllerAnimated:YES]; // or pop
}
-(void)done {
[self.managedObjectContext save:nil]; // better use proper error handling
[self dismissModalViewControllerAnimated:YES]; // or pop
}