UIProgressView scaling issue - objective-c

I'm having this odd issue with UIProgressView. This video will explain better than I can with words...
https://vimeo.com/45399884 password: stackoverflow
But basically, I have a UIProgressView that uses iOS5's new setProgress:animated method. I'm animating it but when it animates, the slider part of the control is being scaled from the view's bounds 0,0 to bounds.size.max,bounds.size.max. It animates from left to right properly (with one exception), but scales at the same time. So basically it looks like a diagonal slide.
This is every bit of my progress view code.
progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 11)];
[self.view addSubview:progressView];
[progressView setProgressViewStyle:UIProgressViewStyleBar];
[progressView setProgress:refreshInterval animated:YES];
Any tips or advice is appreciated. Thanks.

The designated initializer for UIProgressView is -initWithProgressViewStyle:. You're not supposed to modify the height of a progress bar, and while the height of the bar-style progress bar is 11, there are probably some effects being initialized in -initWithProgressViewStyle: that you're missing since the default height for the control is 9.

The designated initializer for a UIProgressView appears to be -initWithProgressBarStyle:. Try creating it using that method.

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

Why NSView leaves an image on superview on where it was when I move it?

I am working on a small application on Mac that I need to create customed cursor and move it. I used NSImageView to implement it. However when I call setFrameOrigin (the same to setFrame) it will leaves images on the previous place.
Here is my code:
#property (nonatomic, strong) NSImageView *eraserView;
this is the define
_eraserView = [[NSImageView alloc] initWithFrame:CGRectMake(100, 100, 32, 32)];
_eraserView.image = [NSImage imageNamed:#"EraserCursor"];
[self.view addSubview:_eraserView];
[_eraserView setHidden:YES];
here is the initialization. Everything goes well until now but:
- (void)setImageatPoint:(NSPoint)point
{
[_eraserView setFrameOrigin:point];
}
- (void)hidePenImage
{
[_eraserView setHidden:YES];
}
- (void)unhidePenImage: (BOOL)isEraser
{
[_eraserView setHidden:NO];
}
These are methods I use to change the state of the NSImageView. They will be called by another class using delegate when corresponding events of trackpad occurs.
However every time I change the state of the NSImageView, it seems like it is drawn on the superview.
I debugged it and found there was no extra subviews. And when I use setHidden it has no effect on those tracks. I think it somehow did something to the CALayer, but I have no idea how to fix it.
Screenshots would help but in general if you move a view or change the area of the view that is drawn, you need to redraw.
To do this it kind of depends on how your drawing happens. Calling setNeedsDisplay may not be enough if your implementation of drawRect only draws a sub rect of the view bounds. Cocoa only draws what it is told to draw.
You can erase sections of the view that should be empty by drawing (filling) where it should be empty. That means drawing a color ( NSColor clearColor if nothing else) in the area that was previously drawn.

Draw Over Image

I'm working on some drawing code. I have that portion working great.
I want to draw over an image, but I want to still be able to see the detail of the image, the black lines, etc.
What I am working on is making a transparent UIImageView that holds the image.
I'm not sure how to get this set up properly though.
Should this be added above the other UIImageView that I color on or below it?
Here's what I have so far:
- (void)viewDidLoad
{
[super viewDidLoad];
topImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 46, 320, 370)];
[topImageView setImage:[UIImage imageNamed:#"imagesmall.png"]];
topImageView.alpha = 1.0;
topImageView.layer.opacity = 1.0;
topImageView.layer.opaque = NO;
[self.view addSubview:topImageView];
[topImageView release];
}
Thoughts anyone?
Yes, you can draw views over other views. They are drawn in the order that they're added as subviews, unless you reorder them after that.
You may need to set the opaque property for some views (this is distinct from and overrides their layer opacity), and set their backgroundColor to nil. UIImageView seems to be transparent by default, as long as its image is; some other UIView subclasses are not.
So, just what is your overlay going to be? If you just need to display one image over another, what you have here seems to work already. If you need to draw some lines programmatically, you'll need to do this:
Create a subclass of UIView.
Implement its drawRect method to display the content you need.
When you add your custom view on top of the background image, make sure it is not opaque and has no backgroundColor.
A common problem here is to find that your foreground is working, but the background isn't being loaded properly. To make sure the background is there, set the alpha of the foreground view to 0.5. You won't want to do that in production, but it will allow you to verify that both views exist.

Overriding layoutSubViews: causes "CGAffineTransformInvert: singular matrix" randomly

I'm overriding layoutSubViews: in a UIScrollView and from time to time I get "CGAffineTransformInvert: singular matrix" for every subview I reposition. The layout looks totally okay however.
The app does not crash either.
Does anybody know what causes this?
I once had this error cause by mistake was setting a font with size 0 when using
[UIFont fontWithName:size:]
for a UILabel.
In case anyone else is struggling with this (and in case it's not because of setting the label font size to 0), "CGAffineTransformInvert: singular matrix" seems to come up when layoutSubViews: runs on a view (such as UIScrollView or UILabel) that has a frame of size (0,0).
Took me forever to figure out because if your container view (e.g. the scroll view) is not set up to clip subviews, the layout will still look fine.
I was seeing this problem too when I added a UIWebView to my self.view.
The offending code was:
UIWebView *wv = [[UIWebView alloc]init];
and the solution is:
UIWebView *wv = [[UIWebView alloc]initwithFrame:[[UIScreen mainScreen]bounds]];
or any framesize except 0.0.
In my application I got this error as I forget to call the -layoutSubViews of the superClass in the overridden -layoutSubViews method,
so make a call [super layoutSubViews] at any point in your overridden method

How do you position a larger NSImage inside of a smaller NSImageView programmatically?

Let's say I have an NSImage that's 100x100. I also have an NSImageView that's 50x50. Is there a way I can place the NSImage at coordinates inside the NSImageView, so I can control which part of it shows? It didn't seem like NSImage had an initWithFrame method...
I did this in my NSImageView subclass, as Andrew suggested.
- (void)drawRect:(NSRect)rect
{
[super drawRect:rect];
NSRect cropRect = NSMakeRect(x, y, w, h);
[image drawAtPoint:NSZeroPoint
fromRect:cropRect
operation:NSCompositeCopy
fraction:1];
}
I don't believe so, but it's trivial to roll your own NSImageView equivalent that supports center/stretch options by drawing the image yourself.
Make your imageview as big as the image, and put it inside a scrollview. Hide the scrollers if you want. No need for subclassing in this case.
NSImageView has a method -setImageAlignment: which lets you control how the image is aligned within the image view. Unfortunately, if you want to display part of the image that doesn't correspond to any of the NSImageAlignment values, you're going to have to draw the image programmatically.
Depends on what your eventual goal is but the easiest thing to me seems to put your NSImageView inside an NSView (or a subclass – doesn't have to be NSScrollView as "#NSResponder" user suggests but this should work well too), set its imageScaling to NSImageScaleProportionallyUpOrDown and its frameSize to image's size. Then you can move your NSImageView freely around the upper view using setFrame:myDesiredFrame. No subclassing, no manual redrawing, etc.