12

I want the bottom (not quite half) of my UIView to be a different color than the top.

I'm wondering if I should create a CGRect and then color that? Is this along the right track?

- (void)drawRect:(CGRect)rect { 

    CGRect aRect = CGRectMake(x, y, width, height);

    // Fill the rectangle with grey
    [[UIColor greyColor] setFill];
    UIRectFill( rect );
}
AllieCat
  • 3,890
  • 10
  • 31
  • 45

6 Answers6

10

Yes, as you are already overriding drawRect method, this will do.

- (void)drawRect:(CGRect)rect { 

    CGRect topRect = CGRectMake(0, 0, rect.size.width, rect.size.height/2.0);
    // Fill the rectangle with grey
    [[UIColor greyColor] setFill];
    UIRectFill( topRect );

    CGRect bottomRect = CGRectMake(0, rect.size.height/2.0, rect.size.width, rect.size.height/2.0);
    [[UIColor redColor] setFill];
    UIRectFill( bottomRect );

}

Change the values inside the frames as you wish.

Lucas Eduardo
  • 11,525
  • 5
  • 44
  • 49
  • When I put your code into my .m file, nothing happens. drawRect is automatically called, right? – AllieCat Aug 05 '13 at 17:51
  • In which .m file are you putting this in? Yes, it's automatically called, but drawRect is a method of UIView class. Are you really overriding a UIView? – Lucas Eduardo Aug 05 '13 at 17:54
  • Like I said, drawRect is a method of UIView's class. You have to create a class that overrides UIView, and add it as subview of your viewcontroller's main view – Lucas Eduardo Aug 05 '13 at 17:58
4

With Swift 5.1 and iOS 13, you may choose one of the two following ways in order to solve your problem.


#1. Draw and fill a specified CGRect instance with a UIColor instance inside a UIView subclass using UIRectFill(_:) function

UIKit provides a UIRectFill(_:) function. UIRectFill(_:) has the following declaration:

func UIRectFill(_ rect: CGRect)

Fills the specified rectangle with the current color.

The following Playground code shows how to use UIRectFill(_:):

import UIKit
import PlaygroundSupport

class CustomView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.green
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        let bottomRect = CGRect(
            origin: CGPoint(x: rect.origin.x, y: rect.height / 2),
            size: CGSize(width: rect.size.width, height: rect.size.height / 2)
        )
        UIColor.red.set()
        UIRectFill(bottomRect)
    }

}

let view = CustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
PlaygroundPage.current.liveView = view

#2. Draw and fill a specified CGRect instance with a UIColor instance inside a UIView subclass using CGContext's fill(_:) method

CGContext has a method called fill(_:). fill(_:) has the following declaration:

func fill(_ rect: CGRect)

Paints the area contained within the provided rectangle, using the fill color in the current graphics state.

The following Playground code shows how to use fill(_:):

import UIKit
import PlaygroundSupport

class CustomView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = UIColor.green
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        let bottomRect = CGRect(
            origin: CGPoint(x: rect.origin.x, y: rect.height / 2),
            size: CGSize(width: rect.size.width, height: rect.size.height / 2)
        )
        UIColor.red.set()
        guard let context = UIGraphicsGetCurrentContext() else { return }
        context.fill(bottomRect)
    }

}

let view = CustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
PlaygroundPage.current.liveView = view
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
1

You can also add an CALayer as a sub layer to your view. Include CoreGraphics and QuartzCore frameworks and create a CGRect with the desired form factor in your drawRect method. Instantiate a CALayer with the rect and add it to the view's layer using [self.layer addSublayer:theLayer]. Before adding it use the CALayer's -setBackgroundColor: method.

If this is inside of a View Controller instead of a View subclass, do exactly the same in the viewDidLoad method.

Bryan

bmeulmeester
  • 1,117
  • 12
  • 26
1

You can use this code. Please change the CGRect according to your desire.

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect topView = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height / 2);
    CGRect bottomView = CGRectMake(0, [UIScreen mainScreen].bounds.size.height / 2, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height / 2);

    UIColor * grayColor = [UIColor colorWithRed:230.0/255.0 green:230.0/255.0 blue:230.0/255.0 alpha:1.0];

    CGContextSetFillColorWithColor(context, grayColor.CGColor);
    CGContextFillRect(context, bottomView);

    CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
    CGContextFillRect(context, topView);
}

The following link may help you more. http://www.raywenderlich.com/32925/core-graphics-tutorial-shadows-and-gloss

Lucas Eduardo
  • 11,525
  • 5
  • 44
  • 49
shuvo
  • 705
  • 5
  • 15
0

You can do a CGRect and clip a part of a portion to fill.

But why won't try two different UIViews placed next to each other?

Bharath

slysid
  • 5,236
  • 7
  • 36
  • 59
0

Override the drawRect method of your UIView Subclass. The following code will make the top half of your view black and the bottom half of your view red.

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Top View
    CGRect topRect = {CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds)};
    [[UIColor blackColor] setFill];
    UIRectFill(topRect);

    // Bottom View
    CGRect bottomRect = {CGRectGetMinX(self.bounds), CGRectGetMidY(self.bounds), CGRectGetMaxX(self.bounds), CGRectGetMidY(self.bounds)};
    [[UIColor redColor] setFill];
    UIRectFill(bottomRect);
}

NOTE: Also you can only override the drawRect: method when you subclass a UIView. Based on your comment view I have a feeling this is not what you are doing.

dana0550
  • 1,125
  • 1
  • 9
  • 16
  • When I implement your code, I get an error that the "property 'frame' not found on object type [myUIView]"... – AllieCat Aug 05 '13 at 17:50
  • Are you subclassing a UIView? If so then you should have access to the frame property. – dana0550 Aug 05 '13 at 17:52
  • Also, I believe the code that is posted is incorrect. You want to define topRect and bottomRect in terms of `self.bounds`, not `self.frame`, because `frame` is in terms of the superview’s coordinate space, while `bounds` is in terms of the view’s coordinate space, and that’s the one you want for custom drawing. – Zev Eisenberg Aug 05 '13 at 17:55
  • @ZevEisenberg It is not incorrect, bounds is useful in certain cases. But in this case when the UIView subclass is instantiated the frame is set to its superview. – dana0550 Aug 05 '13 at 18:08
  • Using `frame` here is incorrect any time the origin of the view is not at {0,0} in its superview’s coordinate space, or when there is a transform on the view that could cause the `frame` and `bounds` to be different. – Zev Eisenberg Aug 05 '13 at 18:25
  • If it works it is not incorrect. Frame and bounds both have their use cases. Again in this case the frame of the subclass is the same as the bounds since he is setting the UIView Subclass to fill the view frame... Bounds is useful when you have a smaller child UIView of the parent view. In this case it make no difference. – dana0550 Aug 05 '13 at 18:29