drawRect not called when subclassing UIView and adding it in the interface builder - ios

I am trying to subclass UIView. Code like so:
import UIKit
class CustomView: UIView {
override func drawRect(rect: CGRect) {
// Drawing code
let circlePath = UIBezierPath(ovalInRect: rect)
UIColor.blueColor().setFill()
circlePath.fill()
}
}
I have dragged a UIView onto a UIViewController and set the class to CustomView however the circle doesn't appear (I have set the constraints correctly). Any ideas what I might be doing wrong here? I'm not trying to preview it. Just want to see it when I run the app. Seems I am getting an error in the console too: Unknown class _TtC9MyProject15CustomView in Interface Builder file.

It is likely that the Target Membership for your CustomView.swift file is not set for your app.
In the Project Navigator on the far left, select your file CustomView.swift. Then in the File Navigator on the far right under Target Membership, make sure the box to the left of your app name is checked.

Related

Interface Builder cannot find intrinsicContentSize defined in a custom view

Interface Builder cannot find intrinsicContentSize of a custom view.
For this given view code,
import Foundation
import UIKit
#IBDesignable
final class CustomView1: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: 100, height: 100)
}
}
I put a UIView instance and set its class to CustomView1.
It works at first, but if I close and re-open the storyboard, IB sometimes(not always) shows an error.
IB cannot find width of the view.
And this error disappears if I force Update Frames.
It looks like a bug. Or am I missing something important? What's your opinion? Any workaround?
Xcode 11 has intrinsic size option in Size inspector. as below

I can not get this UIView round

This is the final result of the code below:
This is my code:
view.layer.cornerRadius = 0.5 * view.bounds.size.width
view.layer.masksToBounds = true
view.clipsToBounds = true
view is the red UIView. This code is placed in viewWillLayoutSubviews and viewDidLayoutSubviews (not together, but I both tested them).
Besides this SO is not clear about using masksToBounds OR clipsToBounds. I am not sure what to use and when to use one of them above. I also tested it apart.
The green UIView has also clipsToBounds active and rounded corners, but if I remove them both, I still get the same effect... I hope someone can help. This only occurs when I place a UIView, inside another UIView. If the UIView does not has a parent, it works (I get the UIView rounded).
Edit: GitHub link: https://github.com/Jasperav/tests
The problem lies with when the auto-layout engine actually finishes all the layout calculations.
If you move your code to viewDidAppear you will see properly "rounded" corners.
This is a very common case for using a custom view though. In fact, it's easily used as an "IBDesignable" class, so you can see it rendered in Interface Builder.
Create a new file named "RoundedView.swift" with this code:
import UIKit
#IBDesignable
class RoundView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = 0.5 * self.bounds.size.height
}
}
Then assign that class to the View you want to be round. Xcode will build your new class, and it will show up in Interface Builder like so:

How should I subclass this?

So I am new to programming and have a quick question. I need to subclass UIlabel in order to override draw rect in order to create some padding for my text.
How would I go about doing this? I seen answer of the subclass file but I don't know where to put it.
Should I create a brand new file in Xcode to put this class in there? I don't see anywhere else in my project where to put this.
Here is sample code from a previous answers
override func drawTextInRect(rect: CGRect) {
var insets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 5.0, bottom: 0.0, right: 5.0)
super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
}
If you're going to reuse the subclass a lot, creating a new swift file would be the right way to go about it.
In Xcode, right-click on your project and choose New File. From the window that appears, choose "iOS" and "Source" on the left, then Cocoa Touch Class on the right. Now click Next. For "Subclass of" enter UILabel, then give your new subclass a name, e.g. "MyCustomLabel", and click Next then Create to create the file.
Xcode will open your new file for editing, and it will look something like this:
import UIKit
class MyCustomLabel: UILabel {
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
}
As you can see, there's already an example drawRect() method in there waiting for you to upload. Put your code where that is, making sure to remove the comments as you go. Once it stops being green, it's live code.

Live Xcode's Interface Builder UIView subclass (IB_DESIGNABLE) without drawRect:

Is it possible to create a UIView subclass that renders live in Xcode (by adding the IB_DESIGNABLE attribute as explained here) but doesn't have a custom drawRect: method?
We have a custom UIView subclass that uses some CAShapeLayers which are added to self.layer for drawing (hence, there's no need to override drawRect:). This class works fine on the App, but won't render on Xcode.
If we replicate the code in drawRect: it works, but we'd prefer to keep the drawing to happen automatically on the layers.
Can this be done?
I also tried doing
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(currentContext, self.myLayer1.frame.origin.x, self.myLayer1.frame.origin.y);
[self.myLayer1 renderInContext:currentContext];
CGContextMoveToPoint(currentContext, self.myLayer1.frame.origin.x, self.myLayer1.frame.origin.y);
[self.myLayer2 renderInContext:currentContext];
}
which seems to work on the device but not on Xcode's IB.
You can preview UIView subclasses in IB (with the IB_DESIGNABLE macro) even if the drawRect: isn't overridden.
I added your code in XCode 6.1 and added a OEProgressIndicator into a xib file. Then I debugged it (using menu Editor / Debug Selected View ) by setting a breakpoint in your commonProgressIndicatorInit selector.
Here's why you don't see anything in the preview with your current code: when the commonProgressIndicatorInit is invoked (from the initWithFrame:(CGRect)frame constructor), the frame is equal to CGRectZero (x:0 y:0 width:0 height:0) so that your center variable is actually equal to (0, 0) and radius is -1.
On the device, depending on the way the class is used, you may be directly invoked with the proper frame, that's why it may work on the device but not in IB.
To fix this, I would implement the layoutSubviews selector (override it from UIView) to organise properly the sublayers. This selector is going to be invoked when the frame is going to change from CGRectZero to the proper values set in Interface Builder.
I've been using the method - (void)prepareForInterfaceBuilder in order to tell IB to live render a view.
See here: Creating a Live View of a Custom Object
Also, you guys are right that this feature is also available for Objective-C.
You don't necessarily need to use drawRect, you can try using - (void)layoutSubviews, it seems to work. The problem with leaving code in places like - (void)layoutSubviews just for the sake of live rendering is that it may be less performant, etc (for instance you can do a lot of stuff in - (void)awakeFromNib, but that method does not get called from Live Rendering, so just make sure that you do all your set up in - (void)prepareForInterfaceBuilder as well.
Without seeing all your code, it's hard to see what the source of the problem is, but to answer your question, yes, you can use IBInspectable / IBDesignable without needing to implement any other specific method. I have done this for a view that uses many layers and does not do any drawing (uses the nested layers for that).
For a quick test example snippet with rounded corners:
#IBDesignable
class MyView : UIView {
#IBInspectable var cornerRadius:CGFloat {
get { return self.layer.cornerRadius }
set { self.layer.cornerRadius = newValue }
}
#IBInspectable var borderWidth:CGFloat {
get { return self.layer.borderWidth }
set { self.layer.borderWidth = newValue }
}
#IBInspectable var borderColor:UIColor {
get { return UIColor(CGColor: self.layer.borderColor) }
set { self.layer.borderColor = newValue.CGColor }
}
}
For a simple example that does gradients, see this post.
For an explanation on how to debug the live views, refer to WWDC ยง411 at about the 22 minute mark.
The only limitation that I have seen so far is that you can add inspectable properties in class extensions, but they only render properly on the device.

Draw Rect Monotouch PaintCode

I'm trying to make a better UI for my application but I'm stuck in this. My designing skills aren't good so I'm trying PaintCode.
I want to make a Login Screen with this shadow beneath the group of username and password.
I can't use a UIView so I made the same but in PaintCode using a Rect.
var context = UIGraphics.GetCurrentContext();
//// Shadow Declarations
var shadow = UIColor.DarkGray.ColorWithAlpha(0.71f).CGColor;
var shadowOffset = new SizeF(6.1f, 4.1f);
var shadowBlurRadius = 5.0f;
//// Rectangle Drawing
UIBezierPath rectanglePath = new UIBezierPath();
rectanglePath.MoveTo(new PointF(18.0f, 239.0f));
rectanglePath.AddLineTo(new PointF(383.0f, 239.0f));
rectanglePath.AddLineTo(new PointF(383.0f, 13.0f));
rectanglePath.AddLineTo(new PointF(18.0f, 13.0f));
rectanglePath.AddLineTo(new PointF(18.0f, 239.0f));
rectanglePath.ClosePath();
context.SaveState();
context.SetShadowWithColor(shadowOffset, shadowBlurRadius, shadow);
UIColor.White.SetFill();
rectanglePath.Fill();
context.RestoreState();
Now I don't know what to do with that code. In the tutorials and documentation they usually make a UIView so they just subclass a UIView and add it in Interface Builder, that way you can always know exactly where the object is going to end in your final app. I don't know what to subclass and how to make the rect I draw beneath my username and password boxes.
Create a custom class inheriting from UIView, then override Draw function and put your custom code there.
[Register("DrawView")]
public class DrawView : UIView
{
public override void Draw(System.Drawing.RectangleF rect)
{
In the above sample the Register attribute is necessary if you want to use your control from XCode designer (or Xamarin Storyboard designer).

Resources