Move different UIView In UIScrollView - ios

In my iOS application i have a scrollview in which there are many imageviews and textviews.
I have to move all this views down to a fixed value, but i don't want to move them to left, right or resize them. I just want to move them down, on an event. The problem is that i can't know which are the values of these UIView.
This is my code:
for(UIView* subview in [myScrollView subviews])
{
subview.frame = CGRectMake(0, 0, screenWidth, screenHeight);
}
i'd like to do this:
for(UIView* subview in [myScrollView subviews])
{
subview.frame = CGRectMake(previousValue+100, previousValue, previousValue, previousValue);
}
I hope I explained myself

If you just want to move them down, why don't you just set scrollView's contentInset?
scrollView.contentInset = UIEdgeInsetsMake(100, previousValue, previousValue, previousValue);
this will make all your subViews down.

try something like this:
UIView *lastView;
for(UIView* subview in [myScrollView subviews])
{
CGrect lastFrame;
if (!lastView) {
lastFrame = CGRectMake(0,0,100,100); // your initial frame
} else {
lastFrame = lastView.frame;
}
lastFrame.origin.x += 100;
subview.frame = lastFrame;
lastView = subview;
}

Related

Change vertical position of back button text in UINavigationBar

I've been able to change the vertical posiiton of the back button icon but not the text.
I'm using the layoutSubviews method in UINavigationBar:
- (void)layoutSubviews {
[super layoutSubviews];
BOOL fixed = NO;
NSArray *classNamesToReposition = #[#"_UINavigationBarBackIndicatorView", #"UINavigationButton", #"UINavigationItemButtonView"];
for (UIView *view in [self subviews]) {
if ([classNamesToReposition containsObject:NSStringFromClass([view class])] && !fixed) {
CGRect frame = [view frame];
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
frame.origin.y = 14.5;
} else if ([NSStringFromClass([view class]) isEqualToString:#"UINavigationButton"]) {
frame.origin.y = 9.0;
} else if ([NSStringFromClass([view class]) isEqualToString:#"UINavigationItemButtonView"]) {
frame.origin.y = 5.0;
}
[view setFrame:frame];
}
}
}
The problem is that any frame change I make on UINavigationItemButtonView does not seem to have any effect, nor any frame change I make on it's UILabel subview that is the actual button text. When I log the views the frames seem to be changing but the text is not moving in my view. What am I doing wrong?
You subclass a UINavigationBar called MyNavigationBar, in layoutSubviews, change the back indicator position.
for (UIView *view in [self subviews]) {
CGRect frame = [view frame];
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
frame.origin.y = 19.5; //default is 11.5, move down by 8.
}
[view setFrame:frame];
}
And you can change backBarItem's title position by adding this in applicationDidFinished.
[[UIBarButtonItem appearanceWhenContainedIn:[MyNavigationBar class], nil] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, 8) forBarMetrics:UIBarMetricsDefault];

UItableview Separator line's height

Can I adjust the height of the UITableview's separator line? I add UIView at the cell to use as separator line and its good, the problem is that when I slide the cell to delete it, the delete button is the problem, its overlapping the separator line, or can I adjust the delete button's height?
The code pasted in by Rashad is pretty old (found here) and doesn't seem to work for iOS 7 or iOS 8.
Here is updated code that works:
-(void)layoutSubviews {
UIView *deleteButtonView = nil;
for (UIView *subview in self.subviews) {
// find the delete view in iOS 8
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"]){
deleteButtonView = subview;
break;
}
// find the delete view in iOS 7
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellScrollView"]) {
for (UIView *secondSubview in [subview subviews]) {
if ([NSStringFromClass([secondSubview class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"]) {
deleteButtonView = secondSubview;
break;
}
}
}
}
int heightOffset = 5;
CGRect buttonFrame = deleteButtonView.frame;
buttonFrame.origin.y = heightOffset;
buttonFrame.size.height = self.frame.size.height-2*heightOffset;
deleteButtonView.frame = buttonFrame;
}
If you can't resize the delete button, resize your bottom UIView so it can overlap the delete button.
I always draw separator line like a subView on contentView of cell. And disable separatorStyle in tableView. And customise delete button like here: https://stackoverflow.com/a/22396248/887325
In you TableViewCell layoutSubviews method write this:
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"]) {
UIView *deleteButtonView = (UIView *)[subview.subviews objectAtIndex:0];
CGRect newf = deleteButtonView.frame;
newf.origin.x = 250;
newf.origin.y = 47;
newf.size.width = 30;
newf.size.height = 50;
deleteButtonView.frame = newf;
}
Hope this helps.. :)

Gap between Navigation bar and view controller content

I am about create "No connection" view in gap between navigation bar and view controller content.
I want to subclass UINavigationViewController and move content of view controllers inside a bit down.
Question is how to do this in right way?
My current solution is working but it is also quite hacky. I would like make it better.
// subclass of AGNavigationController
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
static BOOL firstTime = YES;
if (firstTime) {
contentView = nil;
for (UIView *v in self.view.subviews) {
if ([v isKindOfClass:[NSClassFromString(#"UINavigationTransitionView") class]]) {
contentView = v;
break;
}
}
firstTime = NO;
origFrame = contentView.frame;
noConnectionView.frame = CGRectMake(0, self.navigationBar.frame.origin.y+self.navigationBar.frame.size.height, 320, 20);
}
[self adjustToConnection:NO withAnimation:NO];
}
-(void)adjustToConnection:(BOOL)isConnection withAnimation:(BOOL)animation {
if (isConnection) {
[noConnectionView removeFromSuperview];
contentView.frame = origFrame;
} else {
[self.view addSubview:noConnectionView];
contentView.frame = CGRectMake(0, origFrame.origin.y+20, 320, origFrame.size.height-20);
}
}
Create your UIView and set its frame to something like (0, 0, self.view.frame.size.witdh, 40).
Use [self.view addSubview:myView]; to add the view to your UIViewController.
Move your elements down in your main view, with the vertical offset set at myView.frame.size.height.
This is all you can get with a question like this one. If you need more help, you have to be more precise about what you tried, and what doesn't work.

How to pass event from outer scroll to inner scroll in a single move

I have two scrollViews i.e one inside other,
-OuterScroll
----InnerScroll
Need Outer scrollView to stop automatically and inner starts in a single scroll when outer ScrollView reaches contentOffSet value of greater than 300.
So far..
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self.view endEditing:YES];
if (scrollView ==scrollSuperView)
{
if (scrollView.contentOffset.y>300) {
[scrollContentView setScrollEnabled:YES];
}else if (scrollView.contentOffset.y<10){
[scrollContentView setScrollEnabled:NO];
}
}
}
By the way scrollSuperView is outerScroll and scrollContentView is inner.
Any help appreciated.
1.scrollSuperView (Outer)
frame = CGRect(0, 0, 320, 468)
contentSize = CGSizeMake(320, 600)
2.scrollContentView (Inner)
frame = CGRect(0, 300, 320, 468)
contentSize = CGSizeMake(320, 600)
So i have above two scrollViews as mentioned outer and inner
Once outer scrollView reaches content offset of >300 then scrollEvent much be passed to inner ScrollView if user is scrolling by putting finger on inner ScrollView..
Hope its more clear now.
Setting outer scrollView's delaysContentTouches to NO will pass touch events from outer scrollView to inner scrollView... "in a single move"
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == scrollSuperView) {
//outer scrollView
if (scrollView.contentOffset.y >= 300) {
//NSLog(#"Outer scrollView ContentOffset has reached 300");
[scrollSuperView setDelaysContentTouches:NO];
[scrollContentView setScrollEnabled:YES];
}
}
else if (scrollView == scrollContentView) {
//inner scrollView
if (scrollView.contentOffset.y == 0) {
//NSLog(#"Inner scrollView ContentOffset has reached 0");
[scrollSuperView setDelaysContentTouches:YES];
[scrollContentView setScrollEnabled:NO];
}
}
}
Assumptions:
scrollSuperView (Outer)
frame = CGRect(0, 0, 320, 300)
contentSize = CGSizeMake(320, 600)
delaysContentTouches = YES
scrollEnabled = YES
scrollContentView (Inner)
frame = CGRect(0, 400, 320, 200)
contentSize = CGSizeMake(320, 400)
delaysContentTouches = YES
scrollEnabled = NO
-(void)viewDidLoad{
//write your code here
innerScrollView.scrollEnabled =NO;
outerScrollView.scrollEnabled =YES;
//above two lines makes touch(scroll) events given to outer and not inner.
}
And your modified method,
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self.view endEditing:YES];
if (scrollView ==scrollSuperView)
{
if (scrollView.contentOffset.y>300) {
outerScrollView.scrollEnabled =NO;
innerScrollView.scrollEnabled =YES;
[outerScrollView setContentOffset:CGPointMake(0, 200)];
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
[self.view endEditing:YES];
if (scrollView ==scrollSuperView && decelerate==NO)
{
if (scrollView.contentOffset.y>300) {
outerScrollView.scrollEnabled =NO;
innerScrollView.scrollEnabled =YES;
[outerScrollView setContentOffset:CGPointMake(0, 200) animated:YES];
}
}
}

UIScrollView paging enabled with content inset is working strange

I created the UIScrollView with content insets.
scrollView.frame = CGRectMake(-80, 180, 480, 190)
self.scrollView.contentInset = UIEdgeInsetsMake(0, 160, 0, 160);
self.scrollView.pagingEnabled = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];
// Add three Views
[self.scrollView addSubview:view1];
[self.scrollView addSubview:view2];
[self.scrollView addSubview:view3];
[view1 setFrame:CGRectMake(0, 0, 160, 190)];
[view2 setFrame:CGRectMake(160, 0, 160, 190)];
[view3 setFrame:CGRectMake(320, 0, 160, 190)];
At first time, scrollView.contentOffset.x was -160.0
But the weird problem is when I tap on scrollView(Yellow Area), content offset x value is resetting to 0 and shown like this.
I tried several times, but tapping on Scroll View resets the content offset to 0.
How can I prevent this?
UIScrollView paging works by scrolling pages with the same width of the scrollView (in your case pages of 480 width). This means that you have 1 single page (you'd still be able to scroll left and right due to the 160 content inset).
One way to make this work would be:
self.scrollView.frame = CGRectMake(80, 180, 160, 190);
self.scrollView.clipsToBounds = NO;
self.scrollView.contentInset = UIEdgeInsetsZero;
self.scrollView.pagingEnabled = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];
This will draw and scroll correctly, however, the sides of the screen will not be interactive (80 pixels on each side, since the control starts at frame.origin.x=80 and ends at 80+160=240).
Second option would be to handle paging yourself, by using methods provided by UIScrollViewDelegate.
- (void)viewDidLoad
{
[super viewDidLoad];
// pageIndex must be declared as a class member - this is used to prevent skipping pages during scroll
pageIndex = 0;
self.scrollView.frame = CGRectMake(0, 180, 320, 190);
self.scrollView.contentInset = UIEdgeInsetsMake(0, 80, 0, 80);
self.scrollView.pagingEnabled = NO;
self.scrollView.clipsToBounds = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];
self.scrollView.delegate = self;
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
int pageWidth = 160;
int pageX = pageIndex*pageWidth-scrollView.contentInset.left;
if (targetContentOffset->x<pageX) {
if (pageIndex>0) {
pageIndex--;
}
}
else if(targetContentOffset->x>pageX){
if (pageIndex<3) {
pageIndex++;
}
}
targetContentOffset->x = pageIndex*pageWidth-scrollView.contentInset.left;
NSLog(#"%d %d", pageIndex, (int)targetContentOffset->x);
}
In addition to alex's first approach with setting clipsToBounds to NO, I need to react to the scroll outside of the scroll view bounds. So I created ScrollForwarderView class which is subclass of UIView.
ScrollForwarderView.h
#import <UIKit/UIKit.h>
#interface ScrollForwarderView : UIView
#property (nonatomic, weak) UIScrollView *scrollView;
#end
ScrollForwarderView.m
...
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
return _scrollView;
}
return nil;
}
Then place UIView with custom class ScrollForwarderView above the scroll view, link scrollView property to my scroll view and it nicely forwarded the user events to scrollview.

Resources