I'm trying to do a UIView category for drawing inside drawRect: method without subclassing. To do this, I created a block to simplify this task.
Here's the code:
UIView+DrawRectBlock.h
#import <UIKit/UIKit.h>
// DrawRect block
typedef void(^DrawRectBlock)(UIView *drawRectView, CGRect rect);
#interface UIView (DrawRectBlock)
- (void)drawInside:(DrawRectBlock)block;
#end
UIView+DrawRectBlock.m
#import "UIView+DrawRectBlock.h"
#import <objc/runtime.h>
#interface UIView ()
#pragma mark - Private properties
#property DrawRectBlock drawBlock;
#end
#implementation UIView (DrawRectBlock)
- (void)drawInside:(DrawRectBlock)block {
if ((self.drawBlock = [block copy])) {
[self setNeedsDisplay];
}
}
- (void)drawRect:(CGRect)rect {
if (self.drawBlock) {
self.drawBlock(self, rect);
}
}
- (void)dealloc {
self.drawBlock = nil;
}
#pragma mark - Others
- (void)setDrawBlock:(DrawRectBlock)drawBlock {
objc_setAssociatedObject(self, #"block", drawBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (DrawRectBlock)drawBlock {
return objc_getAssociatedObject(self, #"block");
}
#end
Finally, I call block as follows:
[_testView drawInside:^(UIView *drawRectView, CGRect rect) {
NSLog(#"DrawReeeeeeect!!!!");
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, 5.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0, 0.0); //start at this point
CGContextAddLineToPoint(context, 100.0, 100.0); //draw to this point
CGContextStrokePath(context);
}];
But "drawRect:" is never called.
Any idea?
Thanks!!
Finally I made a mix of subclass and category and works great!
https://github.com/mhergon/SimpleBlockDrawing
Related
This question already has answers here:
How to change the tint color of the clear button on a UITextField
(25 answers)
Closed 6 years ago.
I want to change Color of the UITextField's Clear Button, As I Know I can achieve the same with accessing the RightView Property of the TextField as Well as also I can use an Image to do the same.
But No, I want to change the colour of that button only.
Can Someone help me with the same?
The Below represents the code which I wrote to access the clear button of the UITextField.
for (UIView *aSubview in self.view.subviews) {
for (UIView *bSubview in aSubview.subviews) {
if ([bSubview isKindOfClass:[UITextField class]]){
for(UIView *v in bSubview.subviews)
{
if([v isKindOfClass:[UIButton class]])
{
}
}
}
}
}
From all your answers, I come to this conclusion,
UIButton *btnClear = [self.txtEmail valueForKey:#"_clearButton"];
UIImage *imageNormal = [btnClear imageForState:UIControlStateNormal];
UIGraphicsBeginImageContextWithOptions(imageNormal.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = (CGRect){ CGPointZero, imageNormal.size };
CGContextSetBlendMode(context, kCGBlendModeNormal);
[imageNormal drawInRect:rect];
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[[UIColor whiteColor] setFill];
CGContextFillRect(context, rect);
UIImage *imageTinted = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[btnClear setImage:imageTinted forState:UIControlStateNormal];
I am new in iOS app development.But i will try.please refer following code.
.h file:
#import <UIKit/UIKit.h>
#interface TextFieldTint : UITextField
-(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted;
-(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal;
#end
.m file:
#import "TextFieldTint.h"
#interface TextFieldTint()
#property (nonatomic,strong) UIColor *colorButtonClearHighlighted;
#property (nonatomic,strong) UIColor *colorButtonClearNormal;
#property (nonatomic,strong) UIImage *imageButtonClearHighlighted;
#property (nonatomic,strong) UIImage *imageButtonClearNormal;
#end
#implementation TextFieldTint
-(void) layoutSubviews
{
[super layoutSubviews];
[self tintButtonClear];
}
-(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted
{
_colorButtonClearHighlighted = colorButtonClearHighlighted;
}
-(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal
{
_colorButtonClearNormal = colorButtonClearNormal;
}
-(UIButton *) buttonClear
{
for(UIView *v in self.subviews)
{
if([v isKindOfClass:[UIButton class]])
{
UIButton *buttonClear = (UIButton *) v;
return buttonClear;
}
}
return nil;
}
-(void) tintButtonClear
{
UIButton *buttonClear = [self buttonClear];
if(self.colorButtonClearNormal && self.colorButtonClearHighlighted && buttonClear)
{
if(!self.imageButtonClearHighlighted)
{
UIImage *imageHighlighted = [buttonClear imageForState:UIControlStateHighlighted];
self.imageButtonClearHighlighted = [[self class] imageWithImage:imageHighlighted
tintColor:self.colorButtonClearHighlighted];
}
if(!self.imageButtonClearNormal)
{
UIImage *imageNormal = [buttonClear imageForState:UIControlStateNormal];
self.imageButtonClearNormal = [[self class] imageWithImage:imageNormal
tintColor:self.colorButtonClearNormal];
}
if(self.imageButtonClearHighlighted && self.imageButtonClearNormal)
{
[buttonClear setImage:self.imageButtonClearHighlighted forState:UIControlStateHighlighted];
[buttonClear setImage:self.imageButtonClearNormal forState:UIControlStateNormal];
}
}
}
+ (UIImage *) imageWithImage:(UIImage *)image tintColor:(UIColor *)tintColor
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = (CGRect){ CGPointZero, image.size };
CGContextSetBlendMode(context, kCGBlendModeNormal);
[image drawInRect:rect];
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);
UIImage *imageTinted = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return imageTinted;
}
#end
I'm having issues with overriding the UIButton class and customising it.
I have a block class which uses the UIButton class:
#import "Block.h"
#implementation Block
-(id)initWithWidth:(int)width withHeight:(int)height withXPos:(double)x withYPos:(double)y{
_width=width;
_height=height;
_x=x;
_y=y;
self = [super initWithFrame:[self createRect]];
return self;
}
- (CGRect)createRect{
CGRect background= CGRectMake(_x, _y, _width, _height);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, background);
return background;
}
#end
All i'm trying to do is then add an instance of the Block class to my view:
#import "ViewController.h"
#import "Block.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
Block* b = [[Block alloc]initWithWidth:200 withHeight:200 withXPos:0 withYPos:200];
[self.view addSubview:b];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Really confused as to why this doesn't work!
Thanks in advance.
Where do you call createRect? That is not a UIView method and will never get called on its own. Did you mean to use drawRect: instead?
Also, is there a reason you made a custom initializer and didn't just override initWithFrame:? You are seemingly accomplishing the same thing in a needlessly complicated way.
EDIT: I see what is happening now. You are calling it when calling the super initializer. Have you tried converting it to drawRect: Instead? As it is now you are attempting to perform drawing before the view is even on the screen.
Here is an example that should work just fine:
#import "Block.h"
#implementation Block
-(id)initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame])
{
// put any extra customization here, although your example doesn't require any
}
return self;
}
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, rect);
}
#end
I am trying to change a line stroke with UISlider, but it doesn't work. The slider value is okay but nothing is changed.
The slider is on the display and runs and give a value back on a label. I think the function is drawed on the first load and than it stops. But i don't know how fix that problem.
My .h file:
#import <UIKit/UIKit.h>
#interface Draw : UIView {
IBOutlet UISlider *slider;
IBOutlet UILabel *label;
}
- (IBAction)sliderValueChanged:(id)sender;
#end
My .m file:
#import "Draw.h"
#implementation Draw
- (IBAction) sliderValueChanged:(UISlider *)sender {
label.text = [NSString stringWithFormat:#"%.1f", slider.value];
NSLog(#"slider value = %f", sender.value);
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawRect:(CGRect)rect;
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0.0, 1.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 50.0, 50.0);
CGContextAddLineToPoint(context, 250.0, 100.0);
CGContextAddLineToPoint(context, 250.0, 350.0);
CGContextAddLineToPoint(context, 50.0, 350.0);
CGContextClosePath(context);
CGContextSetLineWidth(context, slider.value );
CGContextStrokePath(context);
}
#end
In your method - (IBAction) sliderValueChanged:(UISlider *)sender you should call [self setNeedsDisplay] to inform the view that the contents need to be redrawn.
You need to tell the UI that it needs to be redrawn with the -[UIView setNeedsDisplay] message. Otherwise, it doesn't know that anything related to how the view is drawn has changed
- (IBAction) sliderValueChanged:(UISlider *)sender {
label.text = [NSString stringWithFormat:#"%.1f", slider.value];
NSLog(#"slider value = %f", sender.value);
[self setNeedsDisplay];
}
I have custom view Chart and view controller for that view GraphViewController.
I'm implementing simple graph.
Here is code for Chart.h
#import
#interface Chart : UIView {
BOOL hideChart;
}
#property BOOL hideChart;
- (void) drawAxesInContext:(CGContextRef)context;
- (void) drawUserChartinContext:(CGContextRef)context;
#end
Chart.m
- (void)drawRect:(CGRect)rect
{
CGContextRef ctxt = UIGraphicsGetCurrentContext();
[self drawAxesInContext:ctxt];
[self drawUserChartinContext:ctxt];
}
- (void) drawAxesInContext:(CGContextRef)context {
CGContextTranslateCTM(context, nullX, nullY);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetLineWidth(context, 3);
CGContextBeginPath(context);
for (int i=0; i
As you can see on screenshot I have uibutton "hide". I want to hide graph (not axes) by pressing this button.
In viewController I created ibaction
- (IBAction) hideAndShow {
self.chart.hideChart = YES;
}
and in view u can see
if (hideChart) {
[[UIColor blackColor] setStroke];
[self setNeedsDisplay];
NSLog(#"hide");
}
But it not works, do you any ideas how can I make this?
http://dl.dropbox.com/u/866144/Voila_Capture7.png
I suggest adding a custom setter for hideChart, something like this
- (void)setHideChart:(BOOL)isHidden {
self.isHidden = isHidden;
}
I have a UIView subclass that draws a simple rectangle with this code:
- (void)drawRect:(CGRect)rect {
//Get the CGContext from this view
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef myColor = [UIColor colorWithHue:0 saturation:1 brightness:0.61 alpha:1].CGColor;
//Draw a rectangle
CGContextSetFillColorWithColor(context, myColor);
//Define a rectangle
CGContextAddRect(context, CGRectMake(0, 0, 95.0, 110.0));
//Draw it
CGContextFillPath(context);
}
then, I have a separate UIViewController that has a UISlider in it
-(IBAction) sliderChanged:(id) sender{
UISlider *slider = (UISlider *)sender;
int sliderValue = (int)[slider value];
float sliderFloat = (float) sliderValue;
NSLog(#"sliderValue ... %d",sliderValue);
NSLog(#"sliderFloat ... %.1f",sliderFloat / 100);
}
here, in sliderChanged, I would like to be able to dynamically change the background color of the rectangle being drawn in the UIView subclass. how should i go about implementing this ?
thank you!
Create a property of your UIView-Subclass which holds a UIColor (or CGColor) value:
In the header:
#interface MySub : UIView {
NSColor* rectColor;
}
#property (retain) NSColor* rectColor;
#end
In the implementation file:
#implementation MySub
#synthesize rectColor
#end
You can now set the color with myViewInstance.rectColor = SomeNSColor;
After you've set the color, you have to redraw the view in order to draw the rect with the new background color:
[myViewInstance setNeedsDisplay];