I want to make my tableViewCell with rounded corner. It is work fine upto iOS6. But in iOS7 rounded corners are not shown.
I used
((UIView*)[self viewWithTag:200]).layer.cornerRadius = 8;
((UIView*)[self viewWithTag:200]).layer.masksToBounds = YES;
Please help me.
Thanks.
Try this category. For me it is working for all iOS.
- (void)setRoundedBorder:(float) radius borderWidth:(float)borderWidth color:(UIColor*)color
{
CALayer * l = [self layer];
[l setMasksToBounds:YES];
[l setCornerRadius:radius];
// You can even add a border
[l setBorderWidth:borderWidth];
[l setBorderColor:[color CGColor]];
}
iOS 7 does not support rounded corners in grouped tables anymore.
iOS 7 is a major overhaul of the whole GUI. Many things have changed, including the appearance of the UITableViews.
You can try to create a custom cell which draws a rounded rect. You have to identifiy the first and last cell in your TableView and only draw the custom View, Background, whatever for those cells.
Here is a link that may help you, although it is targeted for iOS 6:
changing corner radius of uitableview grouped in iOS6
Related
I'm playing with NSGestureRecognizer(s) in Objective-C.
I have a simple Custom View in the XIB canvas to which I applied the press, pan, magnify, and rotate gesture recognisers. From each one I have created an action in AppDelegate.m and then added code to it. They all work to some extent but the way magnify and rotate behave does not satisfy me.
Here is the code for both of them:
- (IBAction)magnifyView:(NSMagnificationGestureRecognizer *)sender {
CGFloat magnification = sender.magnification + 1.0;
NSView *view = sender.view;
CGAffineTransform transform = CGAffineTransformMakeScale(magnification, magnification);
[[view layer] setAffineTransform:transform];
sender.magnification = 0;
}
and ...
- (IBAction)rotateView:(NSRotationGestureRecognizer *)sender {
CGFloat rotation = sender.rotation;
NSView *view = sender.view;
CGAffineTransform transform = CGAffineTransformMakeRotation(rotation);
[[view layer] setAffineTransform:transform];
sender.rotation = 0;
}
I'm using a 2016 MBP with macOS 12.4 and Xcode 13.4.1 to realise this and, using the trackpad for the gestures, I see that magnifyView seems to stutter unless I strongly open my fingers in an "unpinch" gesture—which risks triggering the macOS show desktop, while rotateView only rotates of a few degrees before coming back.
The whole project can be found here, if you feel like giving it a look. It doesn't contain much else anyway, it's an experiment.
Could you please give it a look (or even just at the methods above) and tell me what I could do to improve it?
Thank you!
I work on dynamically, programmatically layout a view for 3.5" devices as well as for 4" devices.
As such that works fine.
But I want rounded corners so that my images appear like playing cards.
And I get rounded corners nicely displayed in 3,5 inch devices on the simulator for simulated iOS 6.1 and 7 alike.
But when I choose iPhone retina 4 inch on 6.1 or 7, then the UIImage in the UIImageView is fully displayed.
It works nicely on simulated iPad devices (in iPhone simulation mode - it is an iPhone only app).
As for today, I do not have any 4" device with me to test it. I can test on a device during the upcoming week.
Hiere is the relevant code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.imageV.image = self.image; // The image property was set by the caller.
// Layout imageV within self.view with a margin of MARGIN
self.imageV.frame = CGRectMake(self.view.frame.origin.x + MARGIN, self.view.frame.origin.y + MARGIN, self.view.frame.size.width - 2 * MARGIN, self.view.frame.size.height - 2 * MARGIN);
// set the raidus and the mask to follow the rounded corners.
self.imageV.layer.cornerRadius = CORNER_RADIUS;
self.imageV.layer.masksToBounds = YES;
}
BTW: CORNER_RADIUS is 18 and MARGIN is 15. Changing these values has no effect on the issue.
UPDATE: Thanks to Matt I figured out that the problem disappears when I create the UIImageView programmatically. That is some really nice workaround plus it points into the right diretion, I guess, but it is not a solution. Any ideas what setting in the storyboard editor might have caused the problem?
As far as I can see, auto layout is disabled for all view controllers in this storyboard.
The answer is simple. The code did work. It did add round corners to the UIImageView object and the maskToBounds worked well.
But the actual image displayed is smaller. I used AspectFit as mode to ensure that the actual image is not squeesed but displayed in its original aspect ration. Because of the longer layout of the iPhone5 dimensions the image only filled a part of its owning UIImageView. I changed the background color to gray for the screenshot and now it gets clear.
So the solution will be that I'll have to calculate the proper size of the image view so that it matches exactly the size of the scaled image. Then it should work.
(I'll update this answer when it is done).
Update: this is what I finally did: I removed the UIImageView from the Storyboard and deal with it programmatically.
Don't get confused by the complexity. I added another view just to throw a shadow, although this is not related to the original question. The shadow I wanted to add anyway. And it turned out that CALayer's shadow and masksToBounds=YES don't really agree on. That is why I added a regular UIView which lies in between the card view and the background view.
Finally this is so much of a hassle for displaying a simple rectangle image, that I think, just subclassing UIView and drawing everything with openGL or so directly into the CALayer would be probably much easier. :-)
Anyway, this is my code:
- (void)viewDidLoad {
[super viewDidLoad];
self.state = #0;
// Create an image view to carry the image with round rects
// and create a regular view to create the shadow.
// Add the shadow view first so that it appears behind
// the actual image view.
// Explanation: We need a separate view for the shadow with the same
// dimenstions as the imageView. This is because the imageView's image
// is rectangular and will only be clipped to round rects when the
// property masksToBounds is set to YES. But this setting will also
// clip away any shadow that the imageView's layer may have.
// Therfore we add a separate mainly empty UIView just behind the
// UIImageview to throw the shadow.
self.shadowV = [[UIView alloc] init];
self.imageV = [[UIImageView alloc] initWithImage:self.image];
[self.view addSubview:self.shadowV];
[self.shadowV addSubview:self.imageV];
// set the raidus and the mask to follow the rounded corners.
[self.imageV.layer setCornerRadius:CORNER_RADIUS];
[self.imageV.layer setMasksToBounds:YES];
[self.imageV setContentMode:UIViewContentModeScaleAspectFit];
// set the shadows properties
[self.shadowV.layer setShadowColor:[UIColor blackColor].CGColor];
[self.shadowV.layer setShadowOpacity:0.4];
[self.shadowV.layer setShadowRadius:3.0];
[self.shadowV.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];
[self.shadowV.layer setCornerRadius:CORNER_RADIUS];
[self.shadowV setBackgroundColor:[UIColor whiteColor]]; // The view needs to have some content. Otherwise it is not displayed at all, not even its shadow.
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Just to be save
if (!self.image) {
return;
}
self.imageV.image = self.image; // The image property was set by the caller.
// Layout imageV within self.view with a margin of MARGIN
self.imageV.frame = CGRectMake(MARGIN, MARGIN, self.view.bounds.size.width - 2 * MARGIN, self.view.bounds.size.height - 2 * MARGIN);
// Calculate the size and position of the image and set the image view to
// the same dimensions
// This works under the assumption, that the image content mode is aspectFit.
// Well, as we are doing so much of the layout manually, it would work with a number of content modes. :-)
float imageWidth, imageHeight;
float heightWidthRatioImageView = self.view.frame.size.height / self.view.frame.size.width;
float heightWidthRatioImage = self.image.size.height / self.image.size.width;
if (heightWidthRatioImageView > heightWidthRatioImage) {
// The ImageView is "higher" than the image itself.
// --> The image width is set to the imageView width and its height is scaled accordingly.
imageWidth = self.imageV.frame.size.width;
imageHeight = imageWidth * heightWidthRatioImage;
} else {
// The ImageView is "wider" than the image itself.
// --> The image height is set to the imageView height and its width is scaled accordingly.
imageHeight = self.imageV.frame.size.height;
imageWidth = imageHeight / heightWidthRatioImage;
}
// Layout imageView and ShadowView accordingly.
CGRect imageRect =CGRectMake((self.view.bounds.size.width - imageWidth) / 2,
(self.view.bounds.size.height - imageHeight) / 2,
imageWidth, imageHeight);
[self.shadowV setFrame:imageRect];
[self.imageV setFrame:CGRectMake(0.0f, 0.0f, imageWidth, imageHeight)]; // Origin is (0,0) because it overlaps its superview which just throws the shadow.
}
And this is how it finally looks like:
The problem is due to some issue with code or configuration you have not told us about. Proof: I ran the following and it works fine. Note that I create the image view in code (to avoid the auto layout problem) and fixed your frame/bounds confusion, and that I've skipped your self.image, but none of that is really relevant to the issue you are seeing:
#define CORNER_RADIUS 18
#define MARGIN 15
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.imageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"im"]];
[self.view addSubview:self.imageV];
// Layout imageV within self.view with a margin of MARGIN
self.imageV.frame = CGRectMake(self.view.bounds.origin.x + MARGIN, self.view.bounds.origin.y + MARGIN, self.view.bounds.size.width - 2 * MARGIN, self.view.bounds.size.height - 2 * MARGIN);
// set the raidus and the mask to follow the rounded corners.
self.imageV.layer.cornerRadius = CORNER_RADIUS;
self.imageV.layer.masksToBounds = YES;
}
It works fine (and you can prove that to yourself). Here is a screen shot of the 4-inch simulator:
Therefore the problem is outside the code that you quote in your question, and cannot be analyzed without further information.
As per my iPad app requirement, i've to show the UISlider vertically.
I'm using iOS7 compiler and deployment target is iOS6.
In the story board I added horizontal UISlider of width 600 pixels. I created IBOutlet in my view controller. I didn't set any auto layout constraints. I'm using the below code to rotate and make it vertical.
self.slider.transform = CGAffineTransformMakeRotation(M_PI_2);
After and before rotation I'm printing the frame size of the slider which is correct. But the slider is not looking proper. Its just showing only knob in the center. How can I rotate the UISlider?
I got a vertical slider working with iOS 8 and Xcode 6 with only 3 constraints in the storyboard and one line of code. Here's a cropped screencap of the interface:
There are 3 constraints between the vertical slider and the UIImageView next to it:
vSlider.Center Y = Image View.Center Y
vSlider.Width = Image View.Height
vSlider.Center X = Image View.Trailing + 16
And of course the one line of code is:
self.vSlider.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
It's easy to set up these constraints in the storyboard in Xcode 6, but I think it should be simple to write these constraints in code to support iOS 7 or 6.
I got it to work this way:
In viewDidLoad: I added
[self.slider removeConstraints:self.slider.constraints];
[self.slider setTranslatesAutoresizingMaskIntoConstraints:YES];
so that it's called before rotating the slider with
self.slider.transform=CGAffineTransformRotate(self.slider.transform,270.0/180*M_PI);
and there is no need to remove and re-add it to superview.
This is an old topic, but here is a Swift solution with autolayout constraints in storyboard and nothing else.
1/ You need to add rotation to the IBOutlet:
#IBOutlet weak var mySlider: UISlider! {
didSet {
mySlider.transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2)
} // didSet
} // IBOutlet
2/ Define in storyboard the constraints, keeping in mind that the Slider will be rotated around its center.
For instance if you want to locate mySlider on the left side of myView, you need three constraints.
myView.Leading = mySlider.CenterX - 20
mySlider.width = myView.Height (with a multiplier of 0.8 for instance)
mySlider.CenterY = myView.CenterY
mySlider will of course appear horizontal in storyboard, but will have the correct sizing, and the center will be correctly positioned.
Uncheck Auto-Layout on your ViewController, there is no other option under the SDK 7.0 to make it work vertically :(
There are so many possible solutions around about putting UISlider vertical. Here is my summary for iOS7 in XCode5 with autoLayout enabled(defaultly in storyboard):
in viewDidLoad add method
self.slider.transform = CGAffineTransformMakeRotation(M_PI_2);
define your autoLayout constraints about slider explicitly in storyboard as whatever you like
In your viewDidLoad, try:
UIView *superView = self.sizeSlider.superview;
[self.sizeSlider removeFromSuperview];
[self.sizeSlider removeConstraints:self.view.constraints];
self.sizeSlider.translatesAutoresizingMaskIntoConstraints = YES;
self.sizeSlider.transform = CGAffineTransformMakeRotation(M_PI_2);
[superView addSubview:self.sizeSlider];
It does not work with constraints, so the trick is to remove the constraints for your uislider.
You might have to resize it manually by setting its frame property.
You can't use storyboard to build up a UISlider.
Build up UISlider by coding.
slider = [[UISlider alloc] initWithFrame:CGRectMake(640, 150, 600, 400)];
[slider.layer setAnchorPoint:CGPointMake(0.0f, 0.0f)];
slider.transform = CGAffineTransformMakeRotation(M_PI/2);
[self.view addSubview:slider];
Try this :-
self.slider.transform=CGAffineTransformRotate(slideToUnlock.transform,-90.0/180*M_PI);
Try below code to Rotate the UISlider in Vertical Position..
//To rotate the slider in Vertical Position
CGAffineTransform sliderRotation = CGAffineTransformIdentity;
sliderRotation = CGAffineTransformRotate(sliderRotation, -(M_PI / 2));
sliderBrightness.transform=sliderRotation;
For me a two-step process worked best (incorporating some of the previous solutions)
Autolayout step)
I added a vertical view in IB and used autolayout to link it to neighboring views. Then I added a slider in the view and simply hooked it up to the center of the view. Then hooked up the width of the slider to the height of the view. Finally control-dragged the slider outlet to my ViewController code (as slider)
Code step)
Then simply added the to my viewWillAppear (swift-code):
let trans = CGAffineTransformMakeRotation(CGFloat(M_PI_2));
slider.transform = trans;
I'm integrating UIScrollView in my games and I notice the setContentSize seems like having some problem when I goes from iPhone to iPad.
Basically I scale the contentSize based on how many contents I have in the UIScrollView
CGSize newContentSize = CGSizeMake(0.0f, totalContent * contentHeight);
[scrollView setContentSize: newContentSize];
This codes work on iPhone retina, but when it goes to iPad, the contentSize has gone larger.
I check the value and it is correct (because in iPad the resolution has been doubled) Problem
is when I try to scroll until the bottom, it will display a lot of empty spaces after the last content.
Does anyone know what happen to this?
EDIT:
The complete codes are as below, it's not a normal app, it's using cocos2d game engine
CCSprite* image = [mImageArray objectAtIndex: 0];
CGSize newContentSize = mScrollView.contentSize;
newContentSize.height = mImageArray.count * image.contentSize.height;
[mScrollView setContentSize: newContentSize];
I have an iPad application that has a base image UIImageView (in this case a large building or site plan or diagram) and then multiple 'pins' can be added on top of the plan (visually similar to Google Maps). These pins are also UIImageViews and are added to the main view on tap gestures. The base image is also added to the main view on viewDidLoad.
I have the base image working with the pinch gesture for zooming but obviously when you zoom the base image all the pins stay in the same x and y coordinates of the main view and loose there relative positioning on the base image (whose x,y and width,height coordinates have changed).
So far i have this...
- (IBAction)planZoom:(UIPinchGestureRecognizer *) recognizer;
{
recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
recognizer.scale = 1;
for (ZonePin *pin in planContainer.subviews) {
if ([pin isKindOfClass:[ZonePin class]]){
CGRect pinFrame = pin.frame;
// ****************************************
// code to reposition the pins goes here...
// ****************************************
pin.frame = pinFrame;
}
}
}
I need help to calculate the math to reposition the pins x/y coordinates to retain there relative position on the zoomed in or out plan/diagram. The pins obviously do not want to be scaled/zoomed at all in terms of their width or height - they just need new x and y coordinates that are relative to there initial positions on the plan.
I have tried to work out the math myself but have struggled to work it through and unfortunately am not yet acquainted with the SDK enough to know if there is provision available built in to help or not.
Help with this math related problem would be really appreciated! :)
Many thanks,
Michael.
InNeedOfMathTuition.com
First, you might try embedding your UIImageView in a UIScrollView so zooming is largely accomplished for you. You can then set the max and min scale easily, and you can scroll around the zoomed image as desired (especially if your pins are subviews of the UIImageView or something else inside the UIScrollView).
As for scaling the locations of the pins, I think it would work to store the original x and y coordinates of each pin (i.e. when the view first loads, when they are first positioned, at scale 1.0). Then when the view is zoomed, set x = (originalX * zoomScale) and y = (originalY * zoomScale).
I had the same problem in an iOS app a couple of years ago, and if I recall correctly, that's how I accomplished it.
EDIT: Below is more detail about how I accomplished this (I'm looking my old code now).
I had a UIScrollView as a subview of my main view, and my UIImageView as a subview of that. My buttons were added to the scroll view, and I kept their original locations (at zoom 1.0) stored for reference.
In -(void)scrollViewDidScroll:(UIScrollView *)scrollView method:
for (id element in myButtons)
{
UIButton *theButton = (UIButton *)element;
CGPoint originalPoint = //get original location however you want
[theButton setFrame:CGRectMake(
(originalPoint.x - theButton.frame.size.width / 2) * scrollView.zoomScale,
(originalPoint.y - theButton.frame.size.height / 2) * scrollView.zoomScale,
theButton.frame.size.width, theButton.frame.size.height)];
}
For the -(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView method, I returned my UIImageView. My buttons scaled in size, but I didn't include that in the code above. If you're finding that the pins are scaling in size automatically, you might have to store their original sizes as well as original coordinates and use that in the setFrame call.
UPDATE...
Thanks to 'Mr. Jefferson' help in his answer above, albeit with a differing implementation, I was able to work this one through as follows...
I have a scrollView which has a plan/diagram image as a subview. The scrollView is setup for zooming/panning etc, this includes adding UIScrollViewDelegate to the ViewController.
On user double tapping on the plan/diagram a pin image is added as a subview to the scrollView at the touch point. The pin image is a custom 'ZonePin' class which inherits from UIImageView and has a couple of additional properties including 'baseX' and 'baseY'.
The code for adding the pins...
- (IBAction)planDoubleTap:(UITapGestureRecognizer *) recognizer;
{
UIImage *image = [UIImage imageNamed:#"Pin.png"];
ZonePin *newPin = [[ZonePin alloc] initWithImage:image];
CGPoint touchPoint = [recognizer locationInView:planContainer];
CGFloat placementX = touchPoint.x - (image.size.width / 2);
CGFloat placementY = touchPoint.y - image.size.height;
newPin.frame = CGRectMake(placementX, placementY, image.size.width, image.size.height);
newPin.zoneRef = [NSString stringWithFormat:#"%#%d", #"BF", pinSeq++];
newPin.baseX = placementX;
newPin.baseY = placementY;
[planContainer addSubview:newPin];
}
I then have two functions for handling the scrollView interaction and this handles the scaling/repositioning of the pins relative to the plan image. These methods are as follows...
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return planImage;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
for (ZonePin *pin in planContainer.subviews) {
if ([pin isKindOfClass:[ZonePin class]]){
CGFloat newX, newY;
newX = (pin.baseX * scrollView.zoomScale) + (((pin.frame.size.width * scrollView.zoomScale) - pin.frame.size.width) / 2);
newY = (pin.baseY * scrollView.zoomScale) + ((pin.frame.size.height * scrollView.zoomScale) - pin.frame.size.height);
CGRect pinFrame = pin.frame;
pinFrame.origin.x = newX;
pinFrame.origin.y = newY;
pin.frame = pinFrame;
}
}
}
For reference, the calculations for position the pins, by the nature of them being pins' centres the pin image on the x axis but has the y-axis bottom aligned.
The only thing left for me to do with this is to reverse the calculations used in the scrollViewDidScroll method when I add pins when zoomed in. The code for adding pins above will only work properly when the scrollView.zoomScale is 1.0.
Other than that, it now works great! :)