Set background color for only part of UIView
Asked Answered
P

6

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 );
}
Photomural answered 5/8, 2013 at 17:27 Comment(2)
You Need to create a UIView Subclass in order to override the drawRect method.Jonathanjonathon
Please approve an answer if it helped.Unshackle
H
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.

Horace answered 5/8, 2013 at 17:33 Comment(3)
When I put your code into my .m file, nothing happens. drawRect is automatically called, right?Photomural
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?Horace
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 viewHorace
C
5

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
Cultured answered 21/8, 2017 at 12:47 Comment(1)
Which one is better #1 or #2?Pacifica
E
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

Escapism answered 5/8, 2013 at 17:56 Comment(1)
your theory is clear ,but give some code it will help full for me.Lunde
S
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

Simony answered 5/8, 2013 at 18:35 Comment(0)
C
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

Capet answered 5/8, 2013 at 17:31 Comment(0)
J
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.

Jonathanjonathon answered 5/8, 2013 at 17:47 Comment(6)
When I implement your code, I get an error that the "property 'frame' not found on object type [myUIView]"...Photomural
Are you subclassing a UIView? If so then you should have access to the frame property.Jonathanjonathon
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.Moderator
@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.Jonathanjonathon
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.Moderator
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.Jonathanjonathon

© 2022 - 2024 — McMap. All rights reserved.