Changing Background Color of UIView - objective-c

See where that ugly yellow is? I need that color to be changing... a lot. Kind of like a trippy kalidascope thing, but with one color the entire time. A lot like the default OS X Spectrum screensaver. How should I go about doing this? Objective-C would seem like a huge CPU hog. Would it be possible for me to put an OpenGL background into something like this? Would love a push in the right direction.

Well you can schedule a function call for like half a second and then change the background color there like this
[NSTimer scheduledTimerWithTimeInterval:0.3f target:self selector:#selector(someMethod) userInfo:nil repeats:YES];
- (void)someMethod
{
self.view.backgroundColor = [UIColor redColor];
}
But this will change the color your background view to only red, so in order to change the color to something else you can declare a class variable or more than one to change the your background color. And in the selector method you can change their value to get some cool effects. You can do something like this.
self.view.backgroundColor = [UIColor colorWithRed:x green:y blue:z alpha:1.0f];
x += 0.01f;
y += 0.02f;
z += 0.04f;
if(x >= 1)
x = 0.01f;
if(y >= 1)
y = 0.02f;
if(z >= 1)
z = 0.04f;

Try the simplest thing first: just set the backgroundColor property on that view and then use performSelector:withObject:afterDelay: to change to the next color after a suitable delay.
Unless you're doing the whole screen with OpenGL, it's not likely to be any faster that way. The bottleneck is most likely compositing the "ball" image and text over the background rather than the creation of a solid-color background. Profile it, instead of guessing or relying on my guessing.

Let's assume the foreground material has transparency. Then we can have a solid view behind it that occupies the entire screen, and we see that view's color thru the foreground material. Then it suffices to change that background view's color. If you wish to animate this change in background color, change the view's layer's backgroundColor (to a CGColor); the effect will automatically be animated. You'll need to link to QuartzCore.framework and import <QuartzCore/QuartzCore.h>, and then you'll be able to say:
theView.layer.backgroundColor = [[UIColor redColor] CGColor];
You can modify this color animation; for example, you can dictate its duration (how fast or slow the color changes) by setting the animation duration for CATransaction (see the CATransaction class methods). I can imagine you'd have a repeating NSTimer, where every time the timer fires you'd do another color-change animation.

Related

Change height of a NSProgressIndicator programmatically

I cannot find a way to set the height of a NSProgressIndicator programmatically.
My try so far:
NSProgressIndicator *ind = [[NSProgressIndicator alloc] init];
[ind setStyle: NSProgressIndicatorBarStyle];
// Height does not change height of the actual indicator
[ind setFrame: NSMakeRect(0, 0, 100, 50)];
[ind setBounds: NSMakeRect(0, 0, 100, 50)];
//[ind setControlSize: 0]; does only make it smaller, not bigger
[view addSubview: ind];
I found NSProgressIndicatorBarStyle enumeration in the documentation, but I couldn't find a method to specify the thickness.
Here a screenshot describing my problem: (layer has a background of red for better understanding):
This also occurs when using the NSButton class. Is there a workaround for this?
in iOS You can't change the progress indicator height just changing its frame, due to framework restrictions. However you should be able to achieve the same result, playing with transform
_indicator.transform = CGAffineTransformMakeScale(1.0f, 0.6f);
EDIT: I just tried on Mac OS X
_indicator.layer.transform = CATransform3DMakeScale(1.0f, 0.6f, 0.0f);
and it doesn't work, so it is not like iOS, likely because of how it is implemented on Cocoa (like Ken suggested).
The only way I managed to change the height is using controlSize, but I don't think it will suit your needs (since it doesn't allow you to specify points).
[_indicator setControlSize:NSMiniControlSize]; // or NSSmallControlSize
You should be able to use an arbitrary frame by subclassing NSProgressIndicator, and overriding drawRect, at this point my recommendation would be to look around to find something that can be extended for your use, like this one
https://www.cocoacontrols.com/controls/lbprogressbar
in IB you can
select your NSProgressIndicator control
in the utilities view select the View Effects inspector
press + in Content Filters
select Lanczos Scale Transform filter
set the appropriate scale value in the Scale row
set the Aspect Ratio too if you need to change the height only
this can be added programmatically also, just google for it how to add Content Filters to NSView

How to have a tiled image for a portion of a window cocoa

I'm new to this and it's hard for me to even ask my question right because I don't know the right terminology. I've done some objective c coding so I'm a little bit beyond beginner except when it comes to working with UIs.
I would like to know the best practices to accomplish this - i.e. the right way.
I have a window with some buttons at the top of it. Below that is a region that will have an image or webview. This will be of variable size so to make it look nice I'd like to have the area behind it have a nice tiled pattern.
I've experimented with a few things that work but everything feels a bit hackish. Is there a control that automatically provides a tiled background and lets me put other controls inside of it? For that matter, is there any kind of control that allows putting other controls inside of it? (I'm used to this in GTK but it doesn't appear to be common in Cocoa)
Also, considering that the image can change sizes based on the buttons above, should I be using core animation and it's layers (I've read about them but not used them)?
One fairly simple way to do this is to use a custom NSView subclass for the background view. In its -drawRect: method, write code to take the image and draw it repeatedly to fill the bounds of the view. The algorithm to do this is pretty simple. Start at the top left (or any corner really), draw the image, then increment the x position by the width of the image, and draw again. When the x position exceeds the maximum x coordinate of the view, increment y by the height of the image and draw the next row, and so on until you've filled the whole thing. This should do the trick:
#interface TiledBackgroundView : NSView
#end
#implementation TiledBackgroundView
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds = [self bounds];
NSImage *image = ...
NSSize imageSize = [image size];
// start at max Y (top) so that resizing the window looks to be anchored at the top left
for ( float y = NSHeight(bounds) - imageSize.height; y >= -imageSize.height; y -= imageSize.height ) {
for ( float x = NSMinX(bounds); x < NSWidth(bounds); x += imageSize.width ) {
NSRect tileRect = NSMakeRect(x, y, imageSize.width, imageSize.height);
if ( NSIntersectsRect(tileRect, dirtyRect) ) {
NSRect destRect = NSIntersectionRect(tileRect, dirtyRect);
[image drawInRect:destRect
fromRect:NSOffsetRect(destRect, -x, -y)
operation:NSCompositeSourceOver
fraction:1.0];
}
}
}
}
#end
No control automatically tiles a background for you.
Remember that NSViews (usually subclasses) do all the drawing - so, for instance, that gray area would be a subclass of NSView and you could put the images inside of it.
To actually draw the tiled image (by the NSView subclass), Madsen's method is usable, but not the most convenient. The easiest way is something along the lines of:
NSColor *patternColor = [NSColor colorWithPatternImage:[NSImage imageNamed:#"imageName"]];
[patternColor setFill];
NSRectFill(rectToDraw);
which you should put in the -drawRect: method of your custom view class. It creates an NSColor which represents a tiled image. Note that it can also be a subclass of a scroll/clip view, etc.
I am not too familiar with Core Animation but it is useful for manipulating views, and might be a direction you want to look at concerning the view drawing the image (and that view only).

Add background shadow to UIButton

How can add a light gray shadow to a UIButton, I don't want a method to do this at the moment, it should be something like:
UIButton *button1... button1.layer.shadowOpacity = 0.8
etc, but that doesn't work, it only adds a shadow inside the button, but I need it on the outside. Thanks!
First you have to #import <QuartzCore/QuartzCore.h>. Then:
mybtn.layer.shadowColor = [UIColor blackColor].CGColor;
mybtn.layer.shadowOpacity = 0.5;
mybtn.layer.shadowRadius = 2;
mybtn.layer.shadowOffset = CGSizeMake(3.0f,3.0f);
You can also use –[UIButton setBackgroundImage:forState:] to set the background image for UIControlStateNormal to one with a shadow. E.g.:
[button setBackgroundImage:[UIImage imageNamed:#"ButtonBackgroundNormal"]
forState:UIControlStateNormal];
where ButtonBackgroundNormal.png has a shadow. Images often render faster than drawing with code. And, speed is important, especially if you're adding it to a UITableViewCell. In that case, to speed up scrolling speed, make sure the background image is completely opaque by designing it with the same background color of the UITableViewCell and saving it without transparency. Then, set button.opaque = YES.

UIView Composite mode

Is there any way to change the composite mode of a UIView background say to screen, overlay, or multiply?
The effect I am trying to go for is similar to what appears in the iOS notification centre where the cell background is much darker, however still translucent to the background. This looks to me like a multiply effect in photoshop.
I'm not 100% sure what your referring to but play around with the background colour and alpha
view.backgroundColor = [UIColor blackColor];
view.alpha = 0.4f; // Try changing this to suit
They may be using subtle gradients and other additional embellishments to really fine tune the look.
Update
I can get a fairly convincing reproduction using
backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.37f];
whitePixelLine = [UIColor colorWithWhite:0.8f alpha:0.4f];
darkPixelLine = [UIColor colorWithWhite:0.0f alpha:0.6f];
My graphic skills are terrible so this could be way off the mark

Repeat a semi-transparent NSImage

In a project I'm working on, I have 3 images: top, middle, and bottom. Top and bottom are fixed height, and middle should be repeated in between the two. (The window size will be changing.) They all are tinted with a color from the user preferences, then need to have their alpha set using a value from the preferences.
I can do pretty much everything. The part I get stuck at is drawing the middle. I decided using [NSColor +colorWithPaternImage:] would be the easiest thing to use. There's a lot of code that makes the actually images and colors, so just assume they exist and are not nil.
int problem; // just to help explain things
float alpha;
NSImage *middleTinted;
NSRect drawRect = [self bounds];
drawRect.size.height = self.bounds.size.height - topTinted.size.height - bottomTinted.size.height;
drawRect.origin.y = topTinted.size.height;
NSColor* colorOne = [NSColor colorWithPatternImage:middleTinted];
NSColor* colorTwo = [colorOne colorWithAlphaComponent:alpha];
if(problem == 1)
{
[colorOne set];
}
else if(problem == 2)
{
[colorTwo set];
}
[NSBezierPath fillRect:drawRect];
Assuming problem == 1, it draws the correct image, in the correct location and with the correct size, but no alpha. (Obviously, since I didn't specify one.)
When problem == 2, I'd expect it to do the same thing, but have the correct alpha value. Instead of this, I get a black box.
Is there a solution that will repeat the image with the correct alpha? I figure I could just draw the image manually in a loop, but I'd prefer a more reasonable solution if one exists.
I expect the problem is that pattern colors don't support -colorWithAlphaComponent:.
NSCell.h contains a method called NSDrawThreePartImage that does the work of drawing end caps and a tiled image in between. It also has an alphaFraction parameter that should meet your needs.
If that doesn't work for you, then you might get the pattern color approach to work by re-rendering your middleTinted image into a new NSImage, using the desired alpha value. (See NSImage's draw... methods.)