IOS - Have UITableViewCells scroll over UIView (like the shazam app) - ios

I have a UIView above my UITableView. When the user scrolls down I want the UIView to stay in place at the top of the screen and have the cells scroll over it. The first page of the Shazam app does what I want.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.tableView.contentOffset.y > 0) {
CGRect newframe = self.publicTopView.frame;
newframe.origin.y = -self.tableView.contentOffset.y;
self.publicTopView.frame = newframe;
}
}
This is what I've tried so far, but it doesn't do anything. Thanks

I would set the tableView.backgroundView to your view, and then set your cells to be clear (or whatever transparency you like). This will allow the cells to move over the view.

You need to have a scrollView with a transparent background. Then add a subview to it that is not transparent and offset down a bit. Here's an overkill example. The TextureView is just so you can see that the background isn't moving.
#import "ViewController.h"
#interface TextureView : UIView
#end
#implementation TextureView
-(void)drawRect:(CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
CGContextMoveToPoint(context, 0, rect.size.height);
CGContextAddLineToPoint(context, rect.size.width, 0);
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor]CGColor]);
CGContextSetLineWidth(context, 8);
CGContextStrokePath(context);
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGRect scrollViewFrame = self.view.frame;
CGFloat sectionHeight = 300;
int numberSections = 3;
CGFloat clearSpaceAtTop = 300;
CGRect sectionsViewFrame = CGRectMake(0, clearSpaceAtTop, scrollViewFrame.size.width, sectionHeight * numberSections);
CGSize contentSize = CGSizeMake(scrollViewFrame.size.width, CGRectGetMaxY(sectionsViewFrame));
TextureView *backGroundView = [[TextureView alloc]initWithFrame:scrollViewFrame];
backGroundView.backgroundColor = [UIColor blueColor];
[self.view addSubview:backGroundView];
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:scrollViewFrame];
scrollView.contentSize = contentSize;
scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:scrollView];
UIView *sectionViewsParent = [[UIView alloc]initWithFrame:sectionsViewFrame];
sectionViewsParent.backgroundColor = [UIColor lightGrayColor];
[scrollView addSubview:sectionViewsParent];
NSArray *colors = #[[UIColor redColor],[UIColor greenColor],[UIColor purpleColor]];
CGFloat spacer = 4;
CGRect colorViewFrame = CGRectMake(0, 0, sectionsViewFrame.size.width, sectionHeight - spacer);
for (UIColor *color in colors){
UIView *sectionView = [[UIView alloc]initWithFrame:colorViewFrame];
sectionView.backgroundColor = color;
[sectionViewsParent addSubview:sectionView];
colorViewFrame.origin.y += sectionHeight;
}
}
#end

If the UIView instance is called iconView, the UITableView instance is called tableView,
If your view controller is UIViewController.
[self.view addSubview:iconView];
[self.view addSubview:tableView];
//and you need set tableView.background to transparent.
If your view controller is UITableViewController, read this question:
UITableViewController Background Image

basically all you have to do is to use UIScrollView's contentInset property
let topInset = topViewHeight.constant //based on your needs
sampleTableView.contentInset = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0)
see my github sample here

Related

IOS/Objective-C: Subview of Subview not displaying

I am trying to create a chart where a bar in the form of a UIView displays on top of a background UIView. I'd like both to display on top of the UIView for the whole screen. I have done this before successfully, but while I can get the first view to display, I somehow can't get my code to display the bar. Could it have something to do with setting the color? Or can anyone suggest why the second subview is not displaying.
My code:
//Make background box:
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat graphWidth = screenWidth-40;
CGFloat graphHeight = 160;
CGRect graphBounds =CGRectMake(20, 200, graphWidth, graphHeight);
float tableStartY = graphBounds.origin.y;
UIView *graphBox = [[UIView alloc] initWithFrame:graphBounds];
graphBox.backgroundColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:0.2]; graphBox.layer.borderWidth = 1;
graphBox.layer.borderColor = [UIColor blueColor].CGColor;
//Make Bar
CGFloat barWidth = 20;
CGFloat barHeight = 100;
CGRect aBar = CGRectMake(20, tableStartY+1, barWidth, barHeight);
UIView *barView = [[UIView alloc] initWithFrame:aBar];
barView.backgroundColor = [UIColor blueColor];
barView.layer.borderWidth = 1;
barView.layer.borderColor = [UIColor redColor].CGColor;
// [graphBox addSubview:barView];
[self.view addSubview: graphBox];
If I run the above code, it displays the graphBox. If I add the bar directly to the view as a subView instead of the graphBox, the bar displays. However, if I uncomment out the line shown and add the barView first to the graphBox and then add the graphBox to the view, the barView does not display.
Thanks in advance for any suggestions.
If I understand correctly what you need to do, you should replace
CGRect aBar = CGRectMake(20, tableStartY+1, barWidth, barHeight);
with
CGRect aBar = CGRectMake(20, 1, barWidth, barHeight);
[edit: and obviously uncomment the addSubview line]
Perhaps this is an accident in your posted code, but you have specifically commented out where the barView would be added to the screen.
// [graphBox addSubview:barView];
In addition, as another answer lists, your offset is incorrect if you are adding barView to graphBox. If you add it to self.view instead, your offset is correct.
So, you've got two choices, depending on the containment you desire in your view hierarchy:
CGRect aBar = CGRectMake(20, 1, barWidth, barHeight);
// ...
[graphBox addSubview:barView];
or
CGRect aBar = CGRectMake(20, tableStartY+1, barWidth, barHeight);
// ...
[self.view addSubview: graphBox];
[self.view addSubview:barView];
Note that in the second option, the order is important to get the barView to display over top of the graphBox as they will be siblings.

should this CustomView be a category or a subclass?

I want to extend an existing custom UIViewclass so it can be used in several places within an app. The view has a method that arranges multiple UIButtonsin a circle. The number of UIButtons will vary depending on where the method is called. So too will the size of the UIButton and the radius of the circle. It would also be useful (but not essential) to be able to call the method several times within the same UIView.
Which is the better way ? to make this a category or a sub-class? It would appear I could use either based on this discussion of pros and cons. But my question is more specific.
I’ve made categories for UIColor and UIFontbut so far I have not been able to make this method work as a category just by following Apple's documentation (I tried it both as a class method and as an instance method). Before I try to make it work as a subclass, can someone who has done it before, either way, please recommend the better approach based on my example below.
Here is the method as it was in the CustomView
circleOfButtons
- (void)circleOfButtons {
screenCentre.x = CGRectGetWidth (self.bounds) / 2;
screenCentre.y = CGRectGetHeight (self.bounds) / 2;
for (int i = 1; i <= buttonCount; i++) {
radians = 2 * M_PI * i / buttonCount;
CGFloat arcStartPoint = - M_PI / 2; // first point clockwise after 12 o'clock
buttonCentre.x = screenCentre.x + radius * cos(radians + arcStartPoint);
buttonCentre.y = screenCentre.y + radius * sin(radians + arcStartPoint);
CGPoint target = CGPointMake(buttonCentre.x, buttonCentre.y);
CGFloat x = screenCentre.x - buttonSize / 2;
CGFloat y = screenCentre.y - buttonSize / 2;
CGFloat wide = buttonSize;
CGFloat high = buttonSize;
UIButton *circleButton = [[UIButton alloc] initWithFrame:CGRectMake(x, y, wide, high)];
[circleButton setTag:i];
circleButton.clipsToBounds = YES;
circleButton.layer.masksToBounds = NO;
circleButton.layer.borderWidth = 0.25f;
circleButton.layer.cornerRadius = buttonSize/2;
circleButton.layer.borderColor = [UIColor blackColor].CGColor;
circleButton.backgroundColor = UIColor.whiteColor;
[circleButton setTitle:[NSString stringWithFormat:#"%i", i] forState:UIControlStateNormal];
[self addSubview:circleButton];
// animation 1
[UIView animateWithDuration:0.5 animations:^{
circleButton.transform = CGAffineTransformMakeScale(1.0, 1.0);
circleButton.center = screenCentre;
}
completion:^(BOOL finished){}];
// animation 2
[UIView animateWithDuration:1.0f animations:^{
circleButton.transform = CGAffineTransformIdentity;
circleButton.center = target;
}
completion:^(BOOL finished){}];
}
and here is the CustomView
CustomView.m
#import <UIKit/UIKit.h>
#import "CustomView.h"
#implementation CustomView : UIView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:[UIScreen mainScreen].bounds];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = true;
self.backgroundColor = [UIColor lightGrayColor];
buttonCount = 5; //16;
buttonSize = 80; //41;
radius = 68; //105;
[self circleOfButtons];
}
return self;
}
CustomView.h
#import <UIKit/UIKit.h>
#interface CustomView : UIView {
CGPoint screenCentre, buttonCentre;
float radius, radians, buttonSize;
int buttonCount;
}
ViewController.m
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGRect rect = [UIScreen mainScreen].bounds;
float statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
CGRect screenFrame = CGRectMake(0, statusBarHeight, rect.size.width, rect.size.height - statusBarHeight);
self.view = [[UIView alloc] initWithFrame: screenFrame];
CustomView *cv = [[CustomView alloc]initWithFrame:screenFrame];
[self.view addSubview:cv];
}

How to create view based animation in objective c?

I have to add the following animation in my iOS app, I have used a scroll bar along with UITableView and achieved the top and bottom animation, but I'm still stuck at the middle animation part where the 4 UIViews come in a single horizontal line. Any suggestions?
http://www.image-maps.com/m/private/0/af8u4ulika9siddnf6k6hhrtg2_untitled-2.gif
Code:-
#implementation AnimatedView {
UIScrollView *mainScroll;
UIScrollView *backgroundScrollView;
UILabel *_textLabel;
UITableView *_commentsTableView;
UIView *menuView;
UIView *_commentsViewContainer;
UIView *fadeView;
UIImageView *imageView;
NSMutableArray *comments;
}
- (id)init {
self = [super init];
if (self) {
_mainScrollView = [[UIScrollView alloc] initWithFrame:[UIApplication sharedApplication].keyWindow.frame];
self.view = _mainScrollView;
_backgroundScrollView = [[UIScrollView alloc] initWithFrame:HEADER_INIT_FRAME];
imageView = [[UIImageView alloc] initWithFrame:HEADER_INIT_FRAME];
fadeView = [[UIView alloc] initWithFrame:imageView.frame];
_textLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 100.0f, 150.0f, 25.0f)];
menuView = [[UIView alloc] initWithFrame:CGRectMake(0,_textLabel.frame.size.height+150, self.view.frame.size.width+30, 180)];
[_backgroundScrollView addSubview:imageView];
[_backgroundScrollView addSubview:fadeView];
[_backgroundScrollView addSubview:menuView];
[_backgroundScrollView addSubview:_textLabel];
_commentsViewContainer = [[UIView alloc] init];
_commentsTableView = [[UITableView alloc] init];
_commentsTableView.scrollEnabled = NO;
_commentsTableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
[self.view addSubview:_backgroundScrollView];
[_commentsViewContainer addSubview:_commentsTableView];
[self.view addSubview:_commentsViewContainer];
// fake data!
comments = [#[#"Array for tableview"] mutableCopy];
}
return self;
}
#pragma mark Scroll
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat delta = 0.0f;
CGRect rect = HEADER_INIT_FRAME;
// Here is where I do the "Zooming" image and the quick fade out the text and toolbar
if (scrollView.contentOffset.y < 0.0f) {
delta = fabs(MIN(0.0f, _mainScrollView.contentOffset.y));
_backgroundScrollView.frame = CGRectMake(CGRectGetMinX(rect) - delta / 2.0f, CGRectGetMinY(rect) - delta, CGRectGetWidth(rect) + delta, CGRectGetHeight(rect) + delta);
[_commentsTableView setContentOffset:(CGPoint){0,0} animated:NO];
} else {
delta = _mainScrollView.contentOffset.y;
_textLabel.alpha = 1.0f;
CGFloat backgroundScrollViewLimit = _backgroundScrollView.frame.size.height - kBarHeight;
// Here I check whether or not the user has scrolled passed the limit where I want to stick the header, if they have then I move the frame with the scroll view
// to give it the sticky header look
if (delta > backgroundScrollViewLimit) {
_backgroundScrollView.frame = (CGRect) {.origin = {0, delta - _backgroundScrollView.frame.size.height + kBarHeight}, .size = {self.view.frame.size.width, HEADER_HEIGHT}};
_commentsViewContainer.frame = (CGRect){.origin = {0, CGRectGetMinY(_backgroundScrollView.frame) + CGRectGetHeight(_backgroundScrollView.frame)}, .size = _commentsViewContainer.frame.size };
_commentsTableView.contentOffset = CGPointMake (0, delta - backgroundScrollViewLimit);
CGFloat contentOffsetY = -backgroundScrollViewLimit * kBackgroundParallexFactor;
[_backgroundScrollView setContentOffset:(CGPoint){0,contentOffsetY} animated:NO];
}
else {
_backgroundScrollView.frame = rect;
_commentsViewContainer.frame = (CGRect){.origin = {0, CGRectGetMinY(rect) + CGRectGetHeight(rect)}, .size = _commentsViewContainer.frame.size };
[_commentsTableView setContentOffset:(CGPoint){0,0} animated:NO];
[_backgroundScrollView setContentOffset:CGPointMake(0, -delta * kBackgroundParallexFactor)animated:NO];
}
}
}
- (void)viewDidAppear:(BOOL)animated {
_mainScrollView.contentSize = CGSizeMake(CGRectGetWidth(self.view.frame), _commentsTableView.contentSize.height + CGRectGetHeight(_backgroundScrollView.frame));
}
You don't need any scrollview to implement this really. All you need is 1 UITableView with 2 sections. First section has a single empty element (but set the row height to 0), and enable the header for both sections. You can use UIViews for the headerViews. Then, you only need to change the header height (with icon positioning) based on tableview Delegate scrollViewDidScroll. scrollViewDidScroll is also a delegate of UITableView since one of TableView's element inherits from UIScrollView.

updating custom uiview's frame after adding subviews to it

I am having a big mental block figuring out something I think easy. Please see this very short video: http://screencast.com/t/eaW7rbECv4Ne.
I would like to draw a rectangle in my layoutSubviews method around the whole area that covers the subviews. I currently draw yellow rect around each term as you can see in the video.
I have a StatementView. In each key tap I am creating new objectView and adding it to my StatementView like below. I add the objectViews to a containerView and try to get the origin and size of the containerView in order to draw the stroke around it. However, it always gives me 0.
How should I update containerViews bounds values after I add the subviews to it?
// Created by ilteris on 1/31/15.
// Copyright (c) 2015 ilteris. All rights reserved.
#implementation QWZStatementView
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.userInteractionEnabled = NO;
self.textField = [[MyUITextField alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
self.textField.inputView = [LNNumberpad defaultLNNumberpad];
self.textField.delegate = self;
self.isNumerator = NO;
self.isDenominator = NO;
[self addSubview:self.textField];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(statementOneTextFieldChanged:) name:UITextFieldTextDidChangeNotification object:nil];
self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[self addSubview:self.containerView];
self.autoresizesSubviews = YES;
self.objectsArray = [NSMutableArray arrayWithCapacity:1];
self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
}
return self;
}
-(void)statementOneTextFieldChanged:(NSNotification *)notification {
NSLog(#"statementOneTextFieldChanged");
QWZObjectView *objectView = [[QWZObjectView alloc] initWithFrame:self.bounds];
[self.containerView addSubview:objectView];
QWZTerm* term = [QWZQuestionDetailViewController createAndReturnCoreDataTermForJSONDict:objectData];
[objectView createTerm:term];
[self.objectsArray addObject:objectView];
[self setNeedsLayout];
}
- (void)layoutSubviews {
NSLog(#"layoutSubviews StatementView");
[super layoutSubviews];
CGSize totalSize = CGSizeMake(0, 0);
for (QWZObjectView* objectView in self.objectsArray) {
CGSize textSize = objectView.bounds.size;
objectView.frame = CGRectMake(totalSize.width , totalSize.height, textSize.width , textSize.height);
totalSize.width = textSize.width + totalSize.width;
}
CGRect bounds = self.containerView.bounds;
/*
NSLog(#"self.containerView.bounds is %#", NSStringFromCGRect(self.containerView.bounds)); //always 0.
bounds.origin = CGPointMake(totalSize.width/2, self.containerView.bounds.origin.y); //adding this code didn't help at all.
CGFloat borderWidth = 2.0f;
self.bounds = CGRectInset(self.bounds, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor redColor].CGColor;
self.layer.borderWidth = borderWidth;
*/
bounds.origin = CGPointMake(totalSize.width/2, self.containerView.bounds.origin.y);
self.containerView.bounds = bounds;
}
#end

iOS: Why does UITextField with setCornerRadius cut off text

I'm trying to load a UITextField with rounded corners into a table view for iOS. For the most part, everything is working fine. However, the left-most character gets partially cut off due to the corner radius property. Is there a way to set a margin on the text that's inputted into a UITextField, so that it displays properly? Here's my code:
textInput = [[UITextField alloc] init];
textInput.backgroundColor = [UIColor whiteColor];
textInput.placeholder = #"example#gmail.com";
textInput.textColor = [UIColor blackColor];
textInput.keyboardType = UIKeyboardTypeEmailAddress;
textInput.returnKeyType = UIReturnKeyDone;
[[textInput layer] setBorderColor:[[UIColor whiteColor] CGColor]];
[[textInput layer] setBorderWidth:2.3];
[[textInput layer] setCornerRadius:15];
[textInput setClipsToBounds: YES];
[textInput setDelegate:self];
[self.contentView addSubview:textInput];
[textInput release];
I figured out a solution. I created a custom textfield, subclassed from UITextField:
#import "CR_customTextField.h"
#implementation CR_customTextField
- (CGRect)textRectForBounds:(CGRect)bounds {
int margin = 10;
CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width - margin, bounds.size.height);
return inset;
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
int margin = 10;
CGRect inset = CGRectMake(bounds.origin.x + margin, bounds.origin.y, bounds.size.width - margin, bounds.size.height);
return inset;
}
#end
Use this
[textInput sizeToFit];
it May Helps you
textInput.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);
//helps to start writing text from given pixel

Resources