Reputation: 6359
I have a UIView
that I create in xib file and integrated in my storyboard. This view is like a tab you can drag to make it appear.
I would like to add a little rectangle on the top edge so that when my UIView
is hidden, there is only the little rectangle visible and I can pull my UIView
by dragging this little rectangle.
To do that I override the drawRect
method of my UIView
override func drawRect(rect: CGRect) {
super.drawRect(rect)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor.purpleColor().CGColor)
CGContextMoveToPoint(context, rect.width / 2 - 20, 0)
CGContextAddLineToPoint(context, rect.width / 2 - 20, -20)
CGContextAddLineToPoint(context, rect.width / 2 + 20, -20)
CGContextAddLineToPoint(context, rect.width / 2 + 20, 0)
CGContextFillPath(context)
}
And when I run it, I don't see anything, not even in the view hierarchy...
Did I do something wrong?
Upvotes: 0
Views: 317
Reputation: 104082
The rectangle that you drag has to be inside the view (or a separate view) because touches are not received by views that fall outside the bounds of their superview. The way I would do this is to use a CAShapeLayer as a mask for your view, and have it start 20 points from the top of the view, then go up to the top of the view at half the width minus 20, etc. You would give the view a background color, but it would only show through where the mask is, elsewhere, it would be transparent. In this scenario, you would place your view so that top 20 points were on the bottom of the screen with the rest being below. Only the rectangle where the mask sticks up to the top of the view would the color show. Here is the code for the view class,
class RDPullTabView: UIView {
let upSwiper = UISwipeGestureRecognizer()
let downSwiper = UISwipeGestureRecognizer()
let shapeLayer = CAShapeLayer()
let bez = UIBezierPath()
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.backgroundColor = UIColor.purpleColor()
self.layer.mask = shapeLayer
upSwiper.direction = .Up
downSwiper.direction = .Down
self.addGestureRecognizer(upSwiper)
self.addGestureRecognizer(downSwiper)
}
override func layoutSubviews() {
super.layoutSubviews()
bez.moveToPoint(CGPoint(x: 0, y: 20))
bez.addLineToPoint(CGPoint(x: self.bounds.size.width/2 - 20, y: 20))
bez.addLineToPoint(CGPoint(x: self.bounds.size.width/2 - 20, y: 0))
bez.addLineToPoint(CGPoint(x: self.bounds.size.width/2 + 20, y: 0))
bez.addLineToPoint(CGPoint(x: self.bounds.size.width/2 + 20, y: 20))
bez.addLineToPoint(CGPoint(x: self.bounds.size.width, y: 20))
bez.addLineToPoint(CGPoint(x: self.bounds.size.width, y: self.bounds.size.height))
bez.addLineToPoint(CGPoint(x: 0, y: self.bounds.size.height))
bez.closePath()
shapeLayer.path = bez.CGPath
}
}
I made a constraint from the top of this view to the bottom of the controller's self.view with a constant of 20. The code in the controller is like this,
class ViewController: UIViewController {
@IBOutlet weak var pullTabView: RDPullTabView!
@IBOutlet weak var bottomCon: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
pullTabView.upSwiper.addTarget(self, action: "handleSwipe:")
pullTabView.downSwiper.addTarget(self, action: "handleSwipe:")
}
func handleSwipe(swiper: UISwipeGestureRecognizer) {
var point = swiper.locationInView(swiper.view)
if pullTabView.bez.containsPoint(point) {
if swiper.direction == UISwipeGestureRecognizerDirection.Up {
bottomCon.constant = 200 // 200 is the height of the pullTabView
}else{
bottomCon.constant = 20;
}
UIView.animateWithDuration(0.3){ self.view.layoutIfNeeded()}
}
}
}
Upvotes: 1
Reputation: 5722
You need to begin & close your path before stroking/filling it. The code below draws a rect in the middle (the origin point for drawRect calls):
override func drawRect(rect: CGRect)
{
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor.purpleColor().CGColor)
CGContextBeginPath(context);
CGContextMoveToPoint(context, rect.width / 2 - 20, rect.height / 2 + 20)
CGContextAddLineToPoint(context, rect.width / 2 - 20, rect.height / 2 - 20)
CGContextAddLineToPoint(context, rect.width / 2 + 20, rect.height / 2 - 20)
CGContextAddLineToPoint(context, rect.width / 2 + 20, rect.height / 2 + 20)
CGContextClosePath(context); // close path
CGContextFillPath(context)
}
If you still don't see anything, I would suggest that your next stop is figuring out the autolayout of your view constraints with the superview/controller.
Upvotes: 0
Reputation: 2724
Would it not be simpler to add a UIView
with backgroundColor
as a subview?
let aView = UIView(frame:
CGRect(x: 0, y: 0, width: 200, height: 200))
let subView = UIView(frame:
CGRect(x: 0, y: aView.frame.height + 20, width: 20, height: 20))
subView.backgroundColor = UIColor.purpleColor()
aView.addSubview(subView)
// Subview will move relative, and 20 points should still be visible
aView.frame.origin.y = -200
Upvotes: 0