I am making a project on touch moved I want to change the alpha or visibility (whatever possible) of the image at the point where it is touched. Lets say Unhidethat particular point of image..
PS I already know how to erase the image. I am looking for unerase
I think this project does exactly what you're looking for : https://github.com/SebastienThiebaud/STScratchView
You have 2 images where one is the hidden image and the other one is the one that you scratch off.
Or even this project : http://www.cocoacontrols.com/platforms/ios/controls/scratch-n-see
I'm sorry for not having a good format for the code, for they are copied from my blog.
It takes me a lot to edit.
1 To hide the part that you touch on.
When your finger moves, erase some parts :
- (UIImage *)erasePartsMoved {
UIImage *image = nil;
UIColor *color = [UIColor whiteColor];
CGFloat width = 5.0f;
CGSize imageContextSize = self.imageView.frame.size;
UIGraphicsBeginImageContext(imageContextSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, width);
CGContextSetStrokeColorWithColor(context, [color CGColor]);
CGContextMoveToPoint(context, self.touchStartPoint.x, self.touchStartPoint.y);
//Do something needed.
CGContextAddLineToPoint(context, self.touchEndPoint.x, self.touchEndPoint.y);
CGContextStrokePath(context);
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;}
2 Your image is not visible at first, for example, transparent.
Get the point touched, then calculate a circle with the touched point, and finally change the alpha of the pixels in the circle:
typedef struct _singleRGBA{
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char alpha;} RGBA;
To change the pixel's alpha :
void filterOpacity(UInt8 *pixelBuf, UInt32 offset, void *context){
double val = *((double*)context);
int a = offset+3;
int alpha = pixelBuf[a];
pixelBuf[a] = SAFECOLOR(alpha * val);}
I hope the above would do a favor.
Funny question, I would like to do a runnable demo later.
I believe alpha is the property of the entire view so all you can do is draw on that particular point... refer this may be this is what you are trying to achieve.
- (void)viewDidLoad
{
//load super view
[super viewDidLoad];
//to decrease alpha.
UISwipeGestureRecognizer *swiperight=[[UISwipeGestureRecognizer alloc]
initWithTarget:self action: #selector(setalpha_decrease:)];
[swiperight setDirection:UISwipeGestureRecognizerDirectionRight];
[self.view addGestureRecognizer:swiperight];
//to increase alpha.
UISwipeGestureRecognizer *swipeleft=[[UISwipeGestureRecognizer alloc]
initWithTarget:self action: #selector(setalpha_increase:)];
[swipeleft setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.view addGestureRecognizer:swipeleft];
}
-(void) setalpha_decrease:(UIPanGestureRecognizer *) gestureRecognizer {
imgview.alpha= imgtomove.alpha-(imgtomove.alpha/10);
}
-(void) setalpha_increase:(UIPanGestureRecognizer *) gestureRecognizer {
imgview.alpha= imgtomove.alpha+(imgtomove.alpha/10);
}
Why don't you put an empty view on top which is filled with a colour or texture and then using #AnkitSrivastava answer let the touch rub away parts of the view's background, revealing the hidden image behind.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [[touches allObjects] objectAtIndex:0];
float alpha = [t locationInView:self.view].x / self.view.frame.size.width;
_img.alpha = alpha;
}
Related
I want to increase and decrease a circle size in uislider with value change..
here my code
draw.m
- (id)initWithFrame:(CGRect)frame value:(float )x
{
value=x;
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawRect:(CGRect)rect{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(6,17,value,value);
CGContextAddEllipseInRect(context, rectangle);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillPath(context);
}
and ViewController.m
#implementation ViewController
#synthesize mySlider,colorLabel;
- (void)viewDidLoad
{ [super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)sliderValue:(UISlider*)sender
{
float r=[[NSString stringWithFormat:#"%.0f",mySlider.value] floatValue];
NSLog(#"value...%f",r);
CGRect positionFrame = CGRectMake(10,100,200,100);
circle = [[draw alloc] initWithFrame:positionFrame value:r];
circle.backgroundColor=[UIColor clearColor];
[self.view addSubview:circle];
}
in this code, circle size has increase but not decrease and another problem is circle look ,
output is .
Ok, your code works, it just doesn't look like it. Add
[circle removeFromSuperview];
circle = nil;
right above
circle = [[draw alloc] initWithFrame:positionFrame value:r];
You keep drawing new circles on top of the previous ones so it takes that odd shape and also doesn't look like it's decreasing.
EDIT
To redraw your circle instead of creating a new one everytime, as #Larme pointed out, you would have to change your 'draw' object to contain a public method which reassigns your 'draw' circle objects diameter.
-(void) setDiameterWithFloat: (float)x{
value = x;
}
Then in your sliderValue IBAction, call this new method to assign the new diameter based on your slider and redraw the circle with setNeedsDisplay:
[circle setDiameterWithFloat:mySlider.value];
[circle setNeedsDisplay];
This allows you to move your initialization of the object to viewDidLoad in your ViewController, where it will be created and loaded only one time along with the rest of the view.
In the iPhone calendar app if you have 2 tiles overlaying ontop of each other the text from the bottom tile gets cut off and cannot be seen through the top transparent tile. How would I be able to keep the tiles transparent but not have the text from the bottom tiles show through to the top tiles?
Here is my code
APCalendarDayTile *tile = (APCalendarDayTile *)view;
CGFloat startPos = [APCalendarCurrentDayView yAxisForTime:[APCalendarCurrentDayView minutesToTime:tile.appointment.startDate]];
CGFloat endPos = [APCalendarCurrentDayView yAxisForTime:[APCalendarCurrentDayView minutesToTime:tile.appointment.endDate]];
tile.frame = CGRectMake(kLeftSideBuffer, startPos, (self.bounds.size.width - kLeftSideBuffer - kRightSideBuffer) , endPos - startPos);
tile.backgroundColor = [UIColor colorWithHexString:tile.appointment.appointmentColor]; <-- This also sets the alpha that makes it transparent.
tile.layer.borderColor = [UIColor colorWithHexString:tile.appointment.appointmentColor alpha:1.0].CGColor;
tile.layer.borderWidth = 1.0f;
Tile code
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CALayer *layer = [self layer];
[layer setMasksToBounds:YES];
[layer setCornerRadius:kCornerRadius];
}
return self;
}
- (id)init
{
if (self = [super init]) {
self.clipsToBounds = YES;
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
tileTitle = [[UILabel alloc] init];
tileTitle.textColor = [UIColor blackColor];
tileTitle.backgroundColor = [UIColor clearColor];
tileTitle.font = [UIFont boldSystemFontOfSize:13.0f];
[tileTitle setAutoresizesSubviews:YES];
[tileTitle setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
tileDescription = [[UILabel alloc] init];
tileDescription.textColor = [UIColor blackColor];
tileDescription.backgroundColor = [UIColor clearColor];
tileDescription.font = [UIFont systemFontOfSize:11.0f];
tileDescription.lineBreakMode = UILineBreakModeTailTruncation;
[tileDescription setAutoresizesSubviews:YES];
[tileDescription setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self setAutoresizesSubviews:YES];
[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self addSubview:tileTitle];
[self addSubview:tileDescription];
}
return self;
}
- (void)layoutSubviews
{
CGRect myBounds = self.bounds;
CGSize stringSize = [tileTitle.text sizeWithFont:tileTitle.font];
if (myBounds.size.height <= 22.0) {
tileTitle.frame = CGRectMake(3, 0, myBounds.size.width, stringSize.height);
tileDescription.frame = CGRectMake(stringSize.width + 6, -1, myBounds.size.width, 14);
} else {
tileTitle.frame = CGRectMake(3, 0, myBounds.size.width, stringSize.height);
tileDescription.frame = CGRectMake(5, tileTitle.frame.size.height, myBounds.size.width, 14);
}
}
I would like the text in this photo to not show in the front tiles like the second photo.
#user1272965 is right insofar as each tile needs to know what tiles are above it, then you can get the text effect you're looking for by making the tile views a custom subclass and implementing their drawing manually:
Each tile will need access to tiles that are above it (or their frames at least):
NSInteger tileCount = [tilesAboveMine count];
CGRect framesAboveMine[tileCount];
for (int i=0; i<tileCount; i++) {
framesAboveMine[i] = [tilesAboveMine objectAtIndex:i].frame;
}
In drawRect of your tile view, draw the tile, and then draw the text clipped by the views above it:
// draw aspects of the tile not to be clipped, like the background image.
// the setup for clipping:
CGContextClipToRects(context, framesAboveMine, tileCount);
then draw the text, which will be clipped by the frames above
[myCalendarString drawAtPoint:CGPointMake(10,10)];
What about adding a UIView in between the two boxes? This middle UIView would cover up the letters (and have the same background color as the rear event), which solves your problem: no text coming through, but you'll see the color behind the other label!
You might be able to create the frame for this UIView using the frame attribute of the UILabel as well as the frame attribute of the frontmost calendar appointment.
I think the native calendar app squeezes tiles that occur at the very same start time as you do, but it also squeezes tiles whose times overlap, i.e. if the start time of the later tile is between the start and end time of the earlier tile.
But if you need your UI to draw these tiles overlapping, then there's no way around it: the obscured tile needs to know that it's underneath (starting after and overlapping), and it needs to either hide its labels, or reduce their alpha level.
I'm trying to develop a chess game on the iPhone, and have become stuck on an otherwise insignificant detail but can not seem to get past it. Can anybody see the piece that's missing?
Here's the problem. When a user clicks on a square, it should highlight in some faded color. What actually is happening though, is it just draws black, totally regardless of what color I set it to.
Here's an image of what I get. The black circle should be red, or any color.
Here, notice the UIView I'm drawing to is behind the pieces view. Doubt it matters, but I want to be complete.
Finally, the code for the layer:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
rowSelected = 0;
colSelected = 0;
}
return self;
}
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
CGContextSetRGBStrokeColor(context, 255.0, 0.0, 0.0, 1.0);
if (rowSelected && colSelected)
{
int gridsize = (self.frame.size.width / 8);
int sx = (colSelected-1) * gridsize;
int sy = (rowSelected-1) * gridsize;
int ex = gridsize;
int ey = gridsize;
CGContextFillEllipseInRect(context, CGRectMake(sx,sy,ex,ey));
}
}
// Handles the start of a touch
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
int gridsize = (self.frame.size.width / 8);
// Position of touch in view
UITouch *touch = [[event allTouches] anyObject];
CGPoint loc = [touch locationInView:self.superview];
int x = loc.x / gridsize;
int y = loc.y / gridsize;
rowSelected = y + 1;
colSelected = x + 1;
[self setNeedsDisplay];
}
I have tried a number of things, using a value of 1 rather than 255, playing with the alpha, etc, but I can't get anything other than a solid black.
EDIT:
Also, here's the code of this view's superview:
#implementation ChessBoard
-(id)initWithFrame:(CGRect)frame
{
if (self != [super initWithFrame:frame])
return self;
int SQUARE_SIZE = frame.size.width / 8;
currentSet = BW;
UIImage *img = [UIImage imageNamed:#"board.png"];
background = [[UIImageView alloc] initWithImage:img];
[background setFrame:frame];
[self addSubview:background];
overlay = [[ChessBoardOverlay alloc] initWithFrame:frame];
[self addSubview:overlay];
In the function CGContextSetRGBStrokeColor color compontent values (red, green,blue, alpha) need to be between 0 and 1. Since you are assuming that 255 is the maximum for a color you need to divide all of your color component values by 255.0f.
CGContextSetRGBStrokeColor(context, 255.0f/255.0f, 0.0/255.0f, 0.0/255.0f, 1.0);
You say you're drawing to a layer... but a CALayer doesn't have a drawRect: method, it has drawInContext:
I would guess by trying to call drawRect: in your instance of a CALayer that the true context hasn't been built correctly, or it has but you're not tying in to it.
Maybe you should state your color this way:
CGContextSetRGBStrokeColor(context, 255.0/255.0f, 0.0/255.0f, 0.0/255.0f, 1.0f);
This happened to me once using:
[UIColor colorWithRed:12.0/255.0f green:78.0/255.0f blue:149.0/255.0f alpha:1.0f];
until I added the /255.0f so that may work.
I can't figure out how i can save my drawn path to an UIImage?
I know that I have to use UIGraphicsBeginImageContext and something like [drawImage drawInRect:CGRectMake(0, 0, drawImage.size.width, drawImage.size.height)];
But I don't know where to put it in my touch functions.
I need to save every path to the image, because I want to be able to change the color and alpha values after each drawn line.
With this code, all the lines will be adjusted in color and width at the same time when I change the values.
- (id) initWithFrame:(CGRect)frame andImage: (UIImageView*) image
{
...
paths = [[NSMutableArray alloc]init];
drawImage = image;
self.backgroundColor=[UIColor clearColor];
[self addSubview:drawImage];
}
- (void)drawRect:(CGRect)rect
{
[brushPattern setStroke];
[myPath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
// Drawing code
//[myPath stroke];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
myPath=[[UIBezierPath alloc]init];
[myPath moveToPoint:[mytouch locationInView:self]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[paths addObject:myPath];
[myPath release];
}
Based on your earlier question, I am assuming that the image view is a subview of this custom view object. You will need to maintain a mutable array of paths in this class. Initialize it at touchesBegan:withEvent: and close the path at touchesEnded:withEvent:. Push the path into the array. At every touch event (began, moved, ended), call a method that updates the image view's image after adding the touch point to the path.
Updating the image will involve creating an empty image context and then iterating over all paths in your array and the current path while stroking them. Once you're done drawing, generate the image object from the context and set it to the image. Pretty straightforward until we notice that each path might differ in attributes. To deal with this you should create a container class for the path which will hold the attributes about the path. Push an object of this class for every path into the array rather than the path itself. This way you can maintain state for your view.
There is one way out and very simple infact , each time you draw a path object you can save it in an increamental image , just create it at a place where needed and then show this image in draw rect before drawing something else.
here is the sample code:
- (void)drawBitmap
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
[strokeColor setStroke];
if (!incrementalImage) // first time draw; paint background white by ...
{
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
[[UIColor colorWithPatternImage:[UIImage imageNamed:#"two.jpg"]] setFill];
//[[UIColor whiteColor] setFill];
[rectpath fill]; // filling it with white
NSLog(#"========== ... drawBitmap .. CALLED=======");
}
[incrementalImage drawAtPoint:CGPointZero];
for(NSDictionary *_pathDict in pathArray)
{
[((UIColor *)[_pathDict valueForKey:#"color"]) setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
[[_pathDict valueForKey:#"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
After that just call this increamental image in drawRect: , so that user has a illusion of continuous drawing and you can then save this image point of time:
- (void)drawRect:(CGRect)rect
{
[incrementalImage drawInRect:rect];
[[dict_path objectForKey:#"color"] setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
[[dict_path objectForKey:#"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
May be you need to modify some code according to your own need.Hope this help someone
I want to place some "handles" on a UIView I have on-screen.
So, I'm creating more UIViews, one at each corner of the UIView's frame rectangle, and I simply want to draw a circle that "fills" the rectangle that is the frame of the "handle" UIView.
Here's what I mean:
How I create the "HandleView":
CGPoint upperLeft = CGPointMake([[self viewToMove] frame].origin.x - 5, [[self viewToMove] frame].origin.y - 5);
HandleView *uL = [[HandleView alloc] initWithFrame:CGRectMake(upperLeft.x, upperLeft.y, 10, 10)];
[self setUpperLeftHandle:uL];
[uL release];
[[self view] addSubview:[self upperLeftHandle]];
drawRect: for HandleView:
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor orangeColor] set];
CGContextFillEllipseInRect(context, [self frame]);
}
What I'm getting is just a set of black rectangles where I place the HandleViews. I'm not sure why they're black, but I can change the color by changing the [HandleView backgroundColor] property. I cannot, though, get anything to DRAW on this view. Calling setNeedsDisplay doesn't seem to make any difference.
Also, the drawRect: method IS being called, so there's a problem with the code there, probably not anywhere else.
It's been a while since I've messed with custom drawing, but I don't remember it being this hard.
What am I missing?
Thanks!!!
Update:
Modified code to this:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 100, 100, 100, 1.0);
CGContextFillEllipseInRect(context, rect);
}
Now, I see the circle, but only where it overlays another view. Where it's just sitting on top of the "background" UIView, I get nothing I can see. Also, even though the color is (100, 100, 100), it shows up white/light-light-gray.
What's the deal?
This might work:
- (void)drawRect:(CGRect)rect {
// Drawing code
[[UIColor orangeColor] setFill];
[[UIBezierPath bezierPathWithOvalInRect:rect] fill];
}
The problem is with the following line:
CGContextFillEllipseInRect(context, [self frame]);
You need to change this to the following:
CGContextFillEllipseInRect(context, [self bounds]);
Origin of frame is the left-top corner location of view in the parent. So, it can be any value within the limits of the size of parent view.
So, while drawing with frame, you will be offsetting Fillellipse rect location which happens to be beyond the visible rect of the handle view.
Hence, you were not able to see anything.
As for the color showing up as white, it's because CGContextSetRGBFillColor() expects values from 0.0 to 1.0 for the color component values (not 0-255). So, by passing 100, you were effectively passing 1.0, which was creating a white color.