Adding a vertical rule (border) between two UIScrollViews - iphone

I have two UIScrollView instances and I want to draw a vertical line between them (not 100% height, more like 80%). How can I achieve this?

Use Core Graphics. Nest the two UIScrollViews inside another view and override the drawRect method on the parent. See Apple's UIView documentation for drawRect for more detail and the Core Graphics Context Reference for more information about drawing.
- (void) drawRect: (CGRect) rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw divider
UIGraphicsPushContext(context);
// Fill the background, this must happen if the view is not opaque.
if (self.opaque)
{
[[UIColor whiteColor ] set];
CGContextFillRect(context, rect);
}
[[UIColor grayColor] set];
CGContextSetLineWidth(context, 1);
CGContextBeginPath(context);
CGContextMoveToPoint(context, rect.size.width * 0.5, 0.1 * rect.size.height);
CGContextAddLineToPoint(context, rect.size.width * 0.5, 0.9 * rect.size.height);
CGContextStrokePath(context);
UIGraphicsPopContext();
}
edit
To address my oversight, there is no simple way that I know of to draw on top of subviews.
This behavior can be simulated using the same basic view hierarchy as above. Subclass UIView to create a completely transparent view that does not accept any touch events. Place the drawing code (I added a conditional for opacity in the code above) in the custom view and then insert an instance of the custom view at the front of the view hierarchy.

A vertical line between your views could also just be a thin, tall UIView (on top of the scroll views) with, say, a solid background color. This would mean you don't need to worry about custom drawing code. This also lets you lay it out in Interface Builder, use autosizing, etc.

Related

Core Graphics Transparent Overlay

I'm replacing the background view of a UITableViewCell with my own custom subclass of UIView, in which I override the drawRect method with my own, which creates a multi-colored and changing background.
The problem is that when the TableViewCell is selected, the graphics under are completely hidden and it looks odd. I need to create a custom selectedBackgroundView in order to fix this. The problem is that that view needs to create a blue gradient tint over the graphics already there, and I don't know how to draw a CGRect or something similar that is partially transparent.
// Write this In your - (void)drawRect:(CGRect)rect
// To draw semi transparent Square
// Create Current Context To Draw
CGContextRef context = UIGraphicsGetCurrentContext();
UIBezierPath *square = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)];
// following method will fill red color with alpha 0.4 last one in parameter list
// first 3 are Red, Green and Blue Respectively.
CGContextSetRGBFillColor(context, 1, 0, 0, 0.4);
[square fill];
[square stroke];

Animate custom UIView

I have a simple custom UIView (a rectangle) that is implemented with drawRect.
The view is drawn from two values; currentValue and maxValue
From drawRect:
The height of the rect represents how much currentValue is of maxValue:
if(currentValue > maxValue)
currentValue = maxValue;
float scale = currentValue/maxValue;
//Draw the rect
CGContextBeginPath(context);
CGContextMoveToPoint(context, self.bounds.origin.x, self.bounds.size.height);
CGContextAddLineToPoint(context, self.bounds.size.width, self.bounds.size.height);
CGContextAddLineToPoint(context, self.bounds.size.width, self.bounds.size.height-(self.bounds.size.height*scale));
CGContextAddLineToPoint(context, self.bounds.origin.x, self.bounds.size.height-(self.bounds.size.height*scale));
CGContextClosePath(context);
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextFillPath(context);
CGContextStrokePath(context);
I've setup a ViewController with a UISlider that changes the currentValue and each time it's changed setNeedsDisplay gets called. This part works just fine. The rect changes height when the slider is used, exactly as planned.
My question is.. I would like this transition between heights to be animated. What's the best way to do it?
Thanks
Instead of having UIView with custom drawing your can add CAShapeLayer object to your view's layer. CAShapeLayer class allows to specify path to draw and draw attributes - and also changes for those properties are easily animatable.
If your view is just a rect filled with solid color as in question your second option is either adjust view's frame or set appropriate affine transform to get required heights - both those properties are also easily animatable using animation methods in UIView class.
If you really just want a simple shape that can be drawn by a Core Animation layer (like CAShapeLayer or CAGradientLayer), you should just use a Core Animation layer and a CABasicAnimation to animate the layer's frame.
If you plan to draw something more complex, and you want to animate changes to the shape, then you need to do more work. You need to give your object properties or instance variables to store the current and final values, and maybe to store the velocity of the value. You need to create a CADisplayLink object and use it to drive calls to your animation method. Your animation method should update the current value based on how much time has passed and then call setNeedsDisplay.
You'll probably want to do this with Core Animation. The relevant docs are on Apple's developer site. There is also a good source of links on Core Animation with iOS on this other SO question.

Problem in drawing square in sample app

Hi i am making a sample app in which i wanto create a square for which i used the following code
- (void)viewDidLoad {
[super viewDidLoad];
[self drawRect:CGRectMake(0, 0, 300, 200)];
[[self view] setNeedsDisplay];
}
- (void) drawRect:(CGRect)rect
{
NSLog(#"drawRect");
CGFloat centerx = rect.size.width/2;
CGFloat centery = rect.size.height/2;
CGFloat half = 100/2;
CGRect theRect = CGRectMake(-half, -half, 100, 100);
// Grab the drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
// like Processing pushMatrix
CGContextSaveGState(context);
CGContextTranslateCTM(context, centerx, centery);
// Uncomment to see the rotated square
//CGContextRotateCTM(context, rotation);
// Set red stroke
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
{
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 1.0);
}
// Draw a rect with a red stroke
CGContextFillRect(context, theRect);
CGContextStrokeRect(context, theRect);
// like Processing popMatrix
CGContextRestoreGState(context);
[[self view] setNeedsDisplay];
}
But nothing is drawn on screen , dont know wheres the issue is .When i debug it the CGContextRef context was always 0x0 , i dont know why its 0x0 always am i missing something in my code.
It looks like you're trying to draw in a subclass of UIViewController. You need to subclass UIView to override the drawRect: method, which is then called automatically with a valid graphics context in place. You almost never call this method yourself.
To quote the Apple docs:
"To draw to the screen in an iOS application, you set up a UIView object and implement its drawRect: method to perform drawing. The view’s drawRect: method is called when the view is visible onscreen and its contents need updating. Before calling your custom drawRect: method, the view object automatically configures its drawing environment so that your code can start drawing immediately. As part of this configuration, the UIView object creates a graphics context (a CGContextRef opaque type) for the current drawing environment. You obtain this graphics context in your drawRect: method by calling the UIKit function UIGraphicsGetCurrentContext."
So essentailly, your code is on track, you just need to get it in the right place. It needs to be in the View object.

How to use a CGBlendMode on a UIView that scrolls above a fixed background?

Our main UIView is a UIScrollView with a fixed background image (very common, obviously). In that scrollView, we have several UIViews that hold content and scroll up and down as the user scrolls (also common). Those UIViews each have their own background, a simple gradient from white to black.
The goal is to have the background gradient of those (inner) UIViews be partially opaque AND use a CGBlendMode other than "kCGBlendModeNormal" (specifically, "kCGBlendModeOverlay"). You should be able to see through to the "parent" scrollView’s fixed background image as the UIViews scroll up and down above it.
- (void)drawRect:(CGRect)rect {
gradientStart = [UIColor colorWithRed:1 green:1 blue:1 alpha:1.0];
gradientEnd = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[2] = { 0.0f, 1.0f };
NSArray *colors = [NSArray arrayWithObjects:(id)gradientStart.CGColor, (id)gradientEnd.CGColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)colors, locations);
CGColorSpaceRelease(colorSpace);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetAlpha(context, 0.50); //this works!
CGContextSetBlendMode(context, kCGBlendModeOverlay); //doesn’t seem to do anything!
CGContextClearRect(context, rect);
CGPoint startPoint, endPoint;
startPoint.x = 0.0;
startPoint.y = 0.0;
endPoint.x = 0.0;
endPoint.y = rect.size.height;
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient);
[super drawRect:rect];
}
Everything works as expected except the CGContextSetBlendMode, which is ignored. We can't seem to find a way to change the blendMode of a UIView relative to what is behind it, the same way you can with alpha. Please note that this is different than building up multiple layers in a SINGLE UIView; in that case, this technique does change the blendMode of the layers "on top". We want to see through to the parent scrollView's fixed background image (as we scroll the child view up and down above it), with both an alpha and an overlay blend applied.
Here's an image showing the issue: http://img2.sbck.us/blendmode.png
Thanks in advance for your help!
I believe what you want is not possible with your current setup. On iOS, it is simply not possible for the blend mode of a view to have an effect on the stuff that is drawn under the view. You would have to draw the scroll view's background and the gradients in the same view.
This is possible, at least with two image views. It might even be possible with more general views. The approach is to implement drawRect in the parent view, and do as follows:
Determine the rect for the foreground view.
Convert the rect in the foreground view to a rect in the background view.
Begin a new graphics context.
Draw the background with the proper blend mode.
Draw the foreground with the proper blend mode.
Extract the image from the graphics context.
End the graphics context.
Use the extracted image accordingly.
This allows a foreground image to blend with a background image.
Seems like you could do this by setting the 'compositingFilter' property of your view's CALayer. The comment in CALayer.h says "A filter object used to composite the layer with its (possibly filtered) background. Default value is nil, which implies source-over compositing."
Alas, CoreImage which provides the filters is not (officially) available on iOS.
I guess your other alternative would be to use OpenGL. You could still use UIView with OpenGL after a fashion by rendering your UIView's into images which could then be used a textures.

iphone sdk- UIGraphics - how to select a superview as current drawing context

i'm trying to draw a line from the originate point of an image view to its destination point.
my problem is (i guess) how to set the superview as current drawing context (from the image view).
can someone help please.
this is the code i'm using in image view..
//UIGraphicsPopContext();
CGContextRef context = UIGraphicsGetCurrentContext(); //(problem here????????)
CGContextSetLineWidth(context, 5.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, startLocationInView.x, startLocationInView.y);
CGContextAddLineToPoint(context, destinationPositionInView.x, destinationPositionInView.y);
CGContextStrokePath(context);
You cannot draw in other views. What you should do is expand your view's bounds to cover the whole area in which you want to draw.
Alternatively, you could add a new CALayer to your view's layer to cover areas that are outside of your view's bounds.