I have scroll view which contains 5 views and it include page control when i clicked over fourth bubble of page control it moves to second view but i want it should directly move to fourth view please help me to solve this problem.
calling of pageControl is as follows:
[pageControl addTarget:self action:#selector(pageTurn:) forControlEvents:UIControlEventValueChanged];
implementation of pageTurn method is as follows:
- (void) pageTurn: (UIPageControl *) aPageControl
{
int whichPage = aPageControl.currentPage;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
scrollView.contentOffset = CGPointMake(320 * whichPage, 0);
[UIView commitAnimations];
}
and my scrollViewDidScroll is as follows:
- (void) scrollViewDidScroll: (UIScrollView *) aScrollView
{
CGPoint offset = aScrollView.contentOffset;
pageControl.currentPage = offset.x /320 ;
}
If you look at the UIPageControl in the documentation, it says this:
When a user taps a page control to move to the next or previous page, the control sends the UIControlEventValueChanged event for handling by the delegate. The delegate can then evaluate the currentPage property to determine the page to display. The page control advances only one page in either direction.
The UIPageControl can only be used to switch one page at a time, hence it only changes to the second page when you click it (and not the fourth, no matter what dot you press).
You'll probably want to create custom UIButtons that make up your pagination control.
Related
I got an gridview. Each cell within that grid is clickable. If a cell is clicked, another viewcontroller must be presented as a modal viewcontroller. The presentedviewcontroller must slide in fro the right to the left. After that, the modalviewcontroller can be dismissed with a slide. How do i achieve this? I got some images to show it :
Both views are separate viewcontrollers.
[Solution]
The answer from Matthew pointed me in the right direction. What i needed was a UIPanGestureRecognizer. Because UISwipeGestureRecognizer only registers one single swipe and i needed the view to follow the users finger. I did the following to accomplish it :
If i cell is tapped inside my UICollectionView, the extra view needs to pop up. So i implemented the following code first :
/* The next piece of code represents the action called when a touch event occours on
one of the UICollectionviewCells.
*/
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSString* release_id = releases[indexPath.row][0];
// Next boolean makes sure that only one new view can be seen. In the past, a user can click multiple cells and it allocs multiple instances of ReleaseViewController.
if(releaseViewDismissed) {
// Alloc UIViewController and initWithReleaseID does a request to a server to initialize some data.
ReleaseViewController *releaseViewController = [[ReleaseViewController alloc] initWithReleaseID: release_id];
// Create a new UIView and assign the height and width of the grid
UIView *releaseViewHolder = [[UIView alloc] initWithFrame:CGRectMake(gridSize.width, 0, gridSize.width, gridSize.height)];
// Add the view of the releaseViewController as a subview of the newly created view.
[releaseViewHolder addSubview:releaseViewController.view];
// Then add the UIView with the view of the releaseViewController to the current UIViewController's view.
[self.view addSubview:releaseViewHolder];
// Place the x coordinate of the new view to the same as width of the screen. Then after that get the x to 0 with an animation.
[UIView animateWithDuration:0.3 animations:^{
releaseViewHolder.frame = CGRectMake(0, 0, releaseViewHolder.frame.size.width, releaseViewHolder.frame.size.height);
// This is important. alloc an UIPanGestureRecognizer and set the method that handles those events to handleSwipes.
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipes:)];
// Add the UIPanGestureRecognizer to the created view.
[releaseViewHolder addGestureRecognizer:_panGestureRecognizer];
releaseViewDismissed = NO;
}];
}
}
Then my handleSwipes is as follows:
-(void)handleSwipes:(UIPanGestureRecognizer *)sender {
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
CGPoint translation = [sender translationInView:sender.view];
CGRect newFrame = [sender view].frame;
[sender setTranslation:CGPointZero inView:sender.view];
if (sender.state == UIGestureRecognizerStateChanged)
{
newFrame.origin.x = newFrame.origin.x + translation.x;
// Makes sure it can't go beyond the left of the screen.
if(newFrame.origin.x > 0) {
[sender view].frame = newFrame;
}
}
if(sender.state == UIGestureRecognizerStateEnded){
CGRect newFrame = [sender view].frame;
CGFloat velocityX = (0.3*[(UIPanGestureRecognizer*)sender velocityInView:self.view].x);
// If the user swipes less then half of the screen, it has to bounce back.
if(newFrame.origin.x < ([sender view].bounds.size.width/2)) {
newFrame.origin.x = 0;
}
// If a user swipes fast, the velocity is added to the new x of the frame.
if(newFrame.origin.x + velocityX > ([sender view].bounds.size.width/2)) {
newFrame.origin.x = [sender view].bounds.size.width + velocityX;
releaseViewDismissed = YES;
}
// Do it all with a animation.
[UIView animateWithDuration:0.25
animations:^{
[sender view].frame = newFrame;
}
completion:^(BOOL finished){
if(releaseViewDismissed) {
// Finally remove the new view from the superView.
[[sender view] removeFromSuperview];
}
}];
}
}
If you want the presented view controller to slide in from the right to the left, it cannot be a modal view. #Juan suggested one way to achieve the right to left and swipe back, but it would result in the grid view being pushed out of the way by the new view. If you would like the new view to cover the grid view when it slides in, you will either need to accept the vertical slide of modal views or write your own code to slide the view in from the right -- the latter would not actually be all that difficult*.
As for the swipe to get back, the easiest way to do that from either a modally presented view or a view you animate in yourself is to use a UISwipeGestureRecognizer. You create the recognizer, tell it what direction of swipe to look for, and you tell it what method to call when the swipe occurs.
*The gist of this approach is to create a UIView, add it as a subview of the grid view, and give it the same frame as your grid view but an x-position equal to the width of the view, and then use the following code to make the view animate in from the right.
[UIView animateWithDuration:0.3 animations:^{
slidingView.frame = CGRectMake(0, 0, slidingView.frame.size.width, slidingView.frame.size.height);
}];
I believe what you need is the following:
Create another controller that is going to handle navigation between these two (ContentViewController for example). This controller should have a ScrollView with paging enabled.
Here is a simple tutorial if you donĀ“t already know how to do this: click here
Once the cell is clicked you have to:
Create the new ViewController to be shown.
Enable paging and add this ViewController to the ContentViewController
Force paging to this newly created ViewController
Additionally you have to add some logic so that when the user swipes to change back to the first page, paging is disabled until a new cell is clicked to repeat the process.
I am trying to force EGORefreshTableHeaderView to update from the code. When I pull down everything works perfect and the TableView (root) gets refreshed. But I have a modal view where the user can subscribe to certain entities. When he subscribes to one the reload method in the first (root) table view gets triggered. This method establishes a connection to a server, loads some specific data based on the subscription, stores it in a CoreData DB and updates the TableView (root).
The problem is that when the user is only connected to 3G or Edge network the download, which is processed in an own thread, can take several seconds. To indicate the user that something happens I would like to show the EGORefreshTableHeaderView.
I found out that I can set the indent of the refresh view and manually show the loading icon but I was wondering if there is not an easier solution by just triggering a delegate or a method on the EGORefreshTableHeaderView?
Did you try using egoRefreshScrollViewDataSourceStartManualLoading?
Assuming your EGORefreshTableHeaderView instance is named _refreshTableHeaderView, then a call like:
[_refreshTableHeaderView egoRefreshScrollViewDataSourceStartManualLoading:self.tableView];
works for me...
So, it's been too long since I used this, and I forgot I applied the change myself...
I modified EGORefreshTableHeaderDelegate (declared in EGORefreshTableHeaderView.h) to add this additional protocol:
- (void)egoRefreshScrollViewDataSourceStartManualLoading:(UIScrollView *)scrollView;
And the implementation (in EGORefreshTableHeaderView.m):
- (void)egoRefreshScrollViewDataSourceStartManualLoading:(UIScrollView *)scrollView {
[self setState:EGOOPullRefreshLoading];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.2];
scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
[UIView commitAnimations];
if ([_delegate respondsToSelector:#selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {
[_delegate egoRefreshTableHeaderDidTriggerRefresh:self];
}
}
Let me know if you need more help there.
(And thank-you enormego for the great work!)
Thanks to Reuven and his code I have improved it a little bit that it can also be used in an UIScrollView that is larger as the screen. Additionally, I have changed the deprecated commitAnimations to block animations.
#pragma mark - Manually refresh view update
- (void)egoRefreshScrollViewDataSourceStartManualLoading:(UIScrollView *)scrollView {
[self.refreshHeaderView setState:EGOOPullRefreshLoading];
//animating pull down scroll view
[UIView animateWithDuration:0.2
animations:^{
scrollView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);
scrollView.contentOffset = CGPointMake(0, -60.0f);
}
];
//triggering refreshview regular refresh
if ([self.tableView.delegate respondsToSelector:#selector(egoRefreshTableHeaderDidTriggerRefresh:)]) {
[self egoRefreshTableHeaderDidTriggerRefresh:self.refreshHeaderView];
}
}
I have a headerView which can expand and collapse when pressed. It's default state is collapsed.
I use the following code to expand the headerView.
if (!self.headerViewIsExpanded) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self.collapsedHeaderView removeFromSuperview];
self.headerView.frame = self.expandedHeaderView.frame;
[self.headerView addSubview:self.expandedHeaderView];
self.tableView.frame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y + offset, self.tableView.frame.size.width, self.tableView.frame.size.height - offset);
[UIView commitAnimations];
self.headerViewIsExpanded = YES;
}
It correctly expands the view frame and diminishes the tableView frame. However, it fails to expand the touches received area of the original UIControl, so I can only collapse it by pressing where the original frame was.
How can I resolve this issue?
EDIT: Alternatively, I would accept an answer with a good explanation of why I cannot resolve the issue, or at least not resolve it safely.
EDIT 1: To be more clear, the headerView is NOT a tableView header view. It is just a view that sits on top of the table that happens to be called headerView. Both headerView and tableView are subviews of the main UIView that spans the available window.
You can try to overload layoutSubviews method. Inside you should use setFrame method for your headerView to define all view elements position.
I am using a tableViewController having 2 sections ....
1st section has 7 rows & 2nd section has 2 rows.
So when i edit in textfields of 2nd section keyboard hides these field so how i will handle
keyboard for these fields only.(i am using tableviewController which has default scrolling).
I am new to objective -C.....Your help please.
Thanks.
On tapping any cell with text field, you can navigate to another view with only a text field, keyboard and Done and Cancel buttons. this feels pretty neat. You can see this in many of apple's iphone apps as well... e.g. Go to iPhone Settings -> Mail, Contacts, Calendars -> Signature.
EDIT: since you cant use the standard way you can move the complete view up with following code:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
CGPoint currentCenter = [self.view center];
CGPoint newCenter = CGPointMake(currentCenter.x, currentCenter.y - 150);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[self.view setCenter:newCenter];
[UIView commitAnimations];
return YES;
}
change the animation duration and the change in position of the center (150) in this code according to your requirements. I have assumed that your view controller is the delegate for your textfield.
To bring the view back to it's original position, use same code but add to center.y in textFieldShouldReturn or textFieldShouldEndEditing etc
CGPoint newCenter = CGPointMake(currentCenter.x, currentCenter.y - 150);
P.S. : I'm still not sure you should be using this second approach.
Okay, this is the code:
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
scrollingTextView.contentSize = lblMessage.frame.size;
float width = (lblMessage.frame.size.width) + (480);
[UIView beginAnimations:#"pan" context:nil];
[UIView setAnimationDuration:durationValue];
[UIView setAnimationRepeatCount:5];
scrollingTextView.contentOffset = CGPointMake(width,0);
[UIView commitAnimations];
//The scrolling text view is rotated.
scrollingTextView.transform = CGAffineTransformMakeRotation (3.14/2);
[self.navigationController setNavigationBarHidden:YES];
btnChange.transform = CGAffineTransformMakeRotation (3.14/2);
I have the user enter in some text, press a button and then a label is replaced with the text, turned 90 degrees in a scrollview on a page.
After a certain number of characters, for example say 20.. the animation just won't load. I can go back down until the animation will run.
Any ideas on where I am going wrong, or a better way of storing the text etc etc ?
Core Animation animations are performed on a separate thread. When you enclose the change in contentOffset in a beginAnimations / commitAnimations block, that change will be animated gradually. The scrolling text view rotation that occurs next, outside of the animation block, will be performed instantly. Since both are interacting with the same control on different threads, it's not surprising that you're getting weird behavior.
If you want to animate the rotation of the text in the same way as the contentOffset, move that line of code to within the animation block.
If you want to have the rotation occur after the offset change animation has completed, set up a callback delegate method. You can use code in the beginning of your animation block similar to the following:
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(contentOffsetAnimationHasFinished:finished:context:)];
which requires you to implement a delegate method like the following:
- (void)contentOffsetAnimationHasFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context;
{
// Do what you need to, now that the first animation has completed
}
EDIT (2/6/2009):
I just created a simplified version of your application, using only the sideways text scrolling, and find no problem with the animation on the device with any number of characters. I removed all extraneous calls to layout the buttons, etc., and only animate the text. Rather than apply the rotation transform to the scroll view every time you click the button, I have it start rotated and stay that way.
I thought it might be a layer size issue, as the iPhone has a 1024 x 1024 texture size limit (after which you need to use a CATiledLayer to back your UIView), but I was able to lay out text wider than 1024 pixels and still have this work.
A full Xcode project demonstrating this can be downloaded here. I don't know what your issue is, but it's not with the text animating code you present here.
Right, this code is working fine in the simulator, and works fine until i enter more than say 20 characters in txtEnter.text:
- (IBAction)updateMessage:(id)sender
{
//Animation coding
//Put the message in a resize the label
[lblMessage setText: txtEnter.text];
[lblMessage sizeToFit];
//Resize the scrolliew and change the width.
scrollingTextView.contentSize = lblMessage.frame.size;
float width = (lblMessage.frame.size.width) + (480);
scrollingTextView.transform = CGAffineTransformMakeRotation (3.14/2);
//Begin the animations
[UIView beginAnimations:#"pan" context:nil];
[UIView setAnimationDuration:durationValue];
[UIView setAnimationRepeatCount:5];
//Start the scrolling text view to go across the screen
scrollingTextView.contentOffset = CGPointMake(width,0);
[UIView commitAnimations];
//General hiding and showing points.
[txtEnter resignFirstResponder];
[btnChange setHidden:NO];
[txtEnter setHidden:YES];
[btnUpdate setHidden:YES];
[lblSpeed setHidden:YES];
[lblBackground setHidden:YES];
[backgroundColourControl setHidden:YES];
[speedSlider setHidden:YES];
[scrollingTextView setHidden:NO];
[backgroundImg setHidden:NO];
[toolbar setHidden:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
//Depending on the choice from the segment control, different colours are loaded
switch([backgroundColourControl selectedSegmentIndex] + 1)
{
case 1:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
break;
case 2:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];
break;
default: break;
}
btnChange.transform = CGAffineTransformMakeRotation (3.14/2);
}
I've tried your method Brad, but can't seem to get the (void) section to work properly.
What my app does its fill the label with a message and then rotates them all to act like it's in landscape mode. Then what it does it scroll the label within a scrollview to act like a scrolling message across the screen.