Iphone Draw Line on top of ScrollView - iphone

I have UIViewController and a ScrollView. I add the scrollview as a subview to the UIViewController. The main aim of the scroll view is to add the tiled images. I have basically followed the example provided by developer.apple.com.
http://developer.apple.com/library/ios/#samplecode/ScrollViewSuite/Introduction/Intro.html
The question is how do I draw line on top of the scrollView. The sample code adds label on top of each tile (i.e. in scroll view class).
Can anyone, explain me on how to draw line on top of the view.
I did try adding lines using
- (void)drawRect:(CGRect)rect
{
CGFloat red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetStrokeColor(c, red);
CGContextBeginPath(c);
CGContextMoveToPoint(c, 5.0f, 5.0f);
CGContextAddLineToPoint(c, 50.0f, 50.0f);
CGContextStrokePath(c);
}
But the problem with this approach is that though the line is being draw its been hidden under the tiled image.
Can anyone help me on this?

Add the line to a transparent subview that is layered on top of the scrollview?

Use a CAShapeLayer (the code is a lot like what you have now, only building up a path for the CAShapeLayer). Then you can add the line layer as a sublayer ahead of the other content in the scroll view.

Related

What type of contents UIViewContentMode mode refers to?

According to the official doc on UIView about the contentMode property:
The content mode specifies how the cached bitmap of the view’s layer is adjusted when the view’s bounds change
What's defined the content in this definition? Is it a sub view or when we have define a background color for a view for example.
My very first guess was that it should apply at least for the subviews in a view, but for example the following code snippet will not give me the expected result when playing with the UIViewContentModeCenter tag:
UIView* redView = [[UIView alloc] initWithFrame:CGRectMake(80, 80, 150, 200)];
redView.contentMode = UIViewContentModeCenter;
redView.backgroundColor = [UIColor redColor];
UIView* greenView = [[UIView alloc] initWithFrame:redView.bounds];
greenView.backgroundColor = [UIColor greenColor];
[redView addSubview:greenView];
redView.frame = CGRectInset(redView.frame, -5, -5);
[self.view addSubview:redView];
I have just set up a redView that will include a greenView. I have also set-up the content mode of the redview to UIViewContentModeCenter - why in the code I wrote the greenView is not centered when I change the frame of its parent? isn't what UIViewContentModeCenter is supposed to do?
Thanks for clarifying!
Ps: You can easily test the above code in the loadView of a simple view controller template project.
From the documentation:
The content mode specifies how the cached bitmap of the view’s layer
is adjusted when the view’s bounds change.
For an image view, this is talking about the image. For a view that
draws its content, this is talking about the drawn content. It does
not affect the layout of subviews.
You need to look at the autoresizing masks in place on the subviews.
Content mode is a red herring here. If you can't achieve the layout
you need using autoresizing masks, then you need to implement
layoutSubviews and calculate the subview positions and frames
manually.
from jrturton's answer to: https://stackoverflow.com/a/14111480/1374512
First read about Content Modes here
In your example you change the frame of the red view. That will invoke layoutSubviews on the view which will reposition the green view according to the layout constraints or autoresizing masks. You haven't specified any. So the frame of the green view will stay the same.
The content mode specifies how the view's layer should update when resizing. Depending on the content mode drawRect will be called or not.
You can test the effect of the different content modes with the following example:
Add a UIView subclass, that draws a circle using this drawRect implementation:
- (void)drawRect:(CGRect)rect
{
// Drawing code
NSLog(#"drawRect %#", NSStringFromCGRect(rect));
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddEllipseInRect(ctx, self.bounds);
[[UIColor redColor] setFill];
CGContextFillPath(ctx);
}
In the view controller create and add the circle view:
CircleView* circleView = [[CircleView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
circleView.contentMode = UIViewContentModeCenter; // <- try different modes here
[self.view addSubview:circleView];
Now lets animate the frame and see what happens:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:5 animations:^{
circleView.frame = CGRectMake(10, 10, 100, 200);
}];
});
I'm doing that asynchronously to force CoreGraphics to draw the view at least one time with the original frame.
When you don't set the content mode you end up with a blurry circle, because it just scales up without redrawing. UIViewContentModeCenter makes the small circle stay at the center - also no redraw needed. UIViewContentModeRedraw makes the view draw the view again with the new frame. Actually that happens before the animation starts.
Note that the content mode can affect the drawing performance.

Custom shaped (inverted T) bordered Uiview in iOS

I have to create a custom shaped (inverted T) bordered Uiview on iOS. I am attaching the screenshot below. I have researched a lot and I found a way using UIBezierPath from here.
But I didn't get any idea to shape my view as inverted T shaped.
UIViews are always rectangular. From the documentation:
The UIView class defines a rectangular area on the screen and the interfaces for managing the content in that area.
Even though the view is limited to being rectangular, you can shape your active area in any way that you like. By combining that with a transparent background, you can imitate a view of any shape that you can draw.
When your rectangular view receives touches and other events, your event handlers should first check if the activity has happened in the inverted-T area. If the activity is outside, the event should be ignored.
Phew.. Finally I have done it. I have used two UiViews subclasses (top & bottom).
The main challenge I faced was about the border, because if I set the border to my two views (top & bottom), it will not show as a single container item. :)
Steps that I done:
Created two UiView subclasses. Lets call topView and bottomView.
TopView *topView = [[TopView alloc] initWithFrame:CGRectMake(220, 60, 200, 200)];
[topView setBackgroundColor:[UIColor yellowColor]];
[self.view addSubview:topView];
BottomView *bottomView = [[BottomView alloc] initWithFrame:CGRectMake(130, 260, 380, 200)];
[bottomView setBackgroundColor:[UIColor yellowColor]];
bottomView.customShape = topView; //Set the custom shape as TopView to frame to draw the border.
[self.view addSubview:topView];
I have drawn three borders (top,right,left) for TopView and two full borders (bottom, right), two partial borders (top left, top right) for BottomView through overriding the drawRect method.
See my TopView class here.
See my BottomView class here.
Thanks to all.
Output:
It should be possible to create a view with a CAShapeLayer as layer.
Make a subclass of UIView and override the layerClass method:
+ (Class)layerClass {
return [CAShapeLayer class];
}
Then in the viewDidLoad you can specify the bezierPath to the shapeLayer:
- (void)viewDidLoad {
[(CAShapeLayer *)self.layer setPath:someBezierPath.CGPath];
[self.layer setBackgroundColor:[UIColor redColor].CGColor];
}

How to draw a line in interface builder in Xcode 4

I'd like to draw a simple inset line in Interface Builder to separate some items in a list and make the UI a bit more tidy. I don't see any "line" or similar objects in the objects library and can't seem to find any drawing commands in Interface builder.
I use a very narrow UIView with backgroundColor set to the appropriate color.
There are no lines in the iPhone UI library. This functionality on Max OS X was supplied by NSBox, but on the iPhone there is no corresponding UI element.
If you're afraid a UIView might affect performance, you can draw a line in code using CoreGraphics' CAShapeLayers.
Every UIView has a CALayer, so draw the line and add it to the views CALayer.
You can do this either in a custom UIView's drawRect or in your view controller:
(Make sure to add Quartz framework to your project)
UIBezierPath *linePath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0,self.view.frame.size.width, 1)];
//shape layer for the line
CAShapeLayer *line = [CAShapeLayer layer];
line.path = [linePath CGPath];
line.fillColor = [[UIColor blackColor] CGColor];
line.frame = CGRectMake(xPosition, yPosition, self.view.frame.size.width,1);
[self.view.layer addSublayer:line];
In place of view, why not just use a label and set the appropriate background color?
I used a view and made it narrow & changed the color to make it look like a line. But my issue is I am using the line on a vertical scrollview and the lines also get scrolled.
Interface Builder does not allow you to draw the shadows essential for an inset line. If you work with Photoshop you know this.
The following code will draw an "inset" if the line is in front of a white/beige Background.
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 1.0f)];
line.backgroundColor = [UIColor colorWithRed:(200.0f/255.0f) green:(200.0f/255.0f) blue:(200.0f/255.0f) alpha:1.0f];
line.layer.shadowColor = [UIColor darkGrayColor].CGColor;
line.layer.shadowOffset = CGSizeMake(0.0f, 1.0f);
line.layer.shadowRadius = 0.5f;
line.layer.shadowOpacity = 0.4f;
line.layer.masksToBounds =NO;
[Background addSubview:line];
Remember to import < QuartzCore/QuartzCore.h>.
As an alliterative - in Interface Builder, add a view who's height is set to 2 points. Wire up a IBOutlet to that view and set its layer border color and width:
self.mySeparatorLine.layer.borderWidth = 1.0f;
self.mySeparatorLine.layer.borderColor = [UIColor lightGrayColor].CGColor;
You can use Progress View as an option for a horizontal line. Just change the tint color and progress to 1 which is 100%.

Changing color of small portion of UIView?

I have a UIView whose color is black and opacity is 0.9 or something like that. What I want to do is to fill the UIView with black portion, but a specified rectangular area should not get black. i.e. that particular rectangular area remains with clear color...
Any kind of help will be appreciated.
regards,
Imran
You can subclass UIView and override - (void)drawRect:(CGRect)rect
And do something of the following (untested, but used something similar myself);
- (void)drawRect:(CGRect)rect {
// fill the whole UIView with a color
[[UIColor colorWithRed:1 green:1 blue:1 0.9] setFill];
UIRectFill( rect );
// draw a rect
CGRect rectIntersection = CGRectIntersection(theRectIWantToDrawIn, rect);
[[UIColor clearColor] setFill];
UIRectFill( rectIntersection );
}
The code above draws a black view with a simulated clearColor hole in it at a certain position. You could, of course, alter this behavior to your liking.
This is quite fast.
UPDATE: Do note that I set the UIView on which I want to draw the rect to UIClear color (I added it to a xib and set those properties there) and unchecked 'Opaque'. That should make the hole see-through.
UPDATE 2: My answer was based on this answer (credit where credit is due): iPhone - Draw transparent rectangle on UIView to reveal view beneath
Add another view (subview) to that area. And set its to your desired color. Thats the easy solution with your current requirements.
Or you can use some quartz core functions.
You can create a small UIView in the main view by custom and set background clear color
UIView *View1 = [[UIView alloc] initWithFrame:CGRectMake(128.0f, 50.0f, 34.0f, 34.0f)];
[View1 setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:View1];
[View1 release];

How to set a margin in UITextView?

I'm currently developing a simple text-editing app for iPad.
I want to set left/right margins like the attached picture.
Just adding UITextView into another UIView with larger width won't work because a scroll indicator won't be properly located.
Instead of UIView, I added UITextView into UIScrollView, and it works almost fine. But they sometimes show strange behaviors, and UITextViewDelegate doesn't work with my UIViewController.
Is there any way to set left/right margins only using UITextView?
Thank you.
You can use the property textContainerInset
Following the example of George Green:
myTextView.textContainerInset = UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f);
UITextView is a subclass of UIScrollView. I haven't tried it but you could try something like:
myTextView.contentInset = UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f);
UIEdgeInsetsMake() is as follows:
UIEdgeInsets UIEdgeInsetsMake (
CGFloat top,
CGFloat left,
CGFloat bottom,
CGFloat right
);
So you should be able to inset your textView content.
Hope this helps, let me know if it works!! :)
I wanted to do the same thing, but textview.contentInset didn't work.
I put UITextView with a narrow width on UIView, then move the scrollview indicator of textview to the right side, so I got what I wanted really well.
textView.clipsToBounds = NO;
textView.scrollIndicatorInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, -20.0f);
This answer might help.
Is there a way to put UITextView's scroll indicator to outside UITextView?
You can set the scroller right inset value of the UITextView to negative value and disable the clip subview option to achieve your require. No other scrollview is needed.
In code it would be
textView.clipsToBounds = NO;
textView.scrollIndicatorInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, -50.0f);