延续上一篇iOS |知识点整理(4)
设置subview是否继承superview的opactity
当把alpha的值设置成0以后:
1、IOS alpha property is inherited by its subviews . If we are setting alpha 0.3 for red view then both subview will have the alpha = 0.3. There is no way to stop subview to inherit alpha value from its super view .
The solution might be . You can set the colour of Red view with alpha 0.3. Color property will not inhered by its subview. Yor can use below code
[redView setBackgroundColor:[UIColor colorWithHue:238.0f/255.0f saturation:24.0f/255.0f brightness:24.0f/255.0f alpha:0.3]];
2.Check out the possible UIKit keys for Info.plist, specifically UIViewGroupOpacity.
UIViewGroupOpacity (Boolean - iOS) specifies whether Core Animation sublayers inherit the opacity of their superlayer.
3.To elaborate on Mark's answer: If you set UIViewGroupOpacity in the Info.plist, it will change the behavior for all views in your app, if you are interested in only fixing the rendering of this particular view, you could also use this snippet:
redContainerView.layer.shouldRasterize = YES; // No setting rasterizationScale, will cause blurry images on retina. redContainerView.layer.rasterizationScale = [[UIScreen mainScreen] scale]; ref:stackoverflow.com/questions/8…
使用systemLayoutSizeFittingSize来实现cell的自适应
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.prototypeCell)
{
self.prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
}
//注意这里是在单纯的计算高度,要与正常给表格加载数据区分开来,比如正常加载时,需要KVO,而这里
只是计算高度,而不需要KVO.这两点要区分开来.
[self configureCell:self.prototypeCell forIndexPath:indexPath isForOffscreenUse:YES];
[self.prototypeCell layoutIfNeeded];
CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height;
}
In this method, I’m creating a cell by dequeuing one from the table view, then calling a method to customise the cell. I do the same thing in cellForRowAtIndexPath:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];;
[self configureCell:cell forIndexPath:indexPath isForOffscreenUse:NO];
return cell;
}
Looking back at heightForRowAtIndexPath:, what’s going on after we have a prototype cell?
首先调用layoutIfNeeded,然后调用systemLayoutSizeFittingSize,获取能包含所有内容的最小size.
First we tell out cell to layoutIfNeeded. Then we ask it for systemLayoutSizeFittingSize:UILayoutFittingCompressedSize. This means we’re asking the layout system for the smallest size possible that will contain all the content.
同时要注意,上面计算高度只是返回了contentView的高度,如果有分隔线的话,还需要再加1
The one pixel height difference is not an error. It's because you didn't take into account the 1 pixel height of the separator. Remember, you are calling systemLayoutFittingSize on the contentView only, which returns the right size for that view. However, you need to return the height for the entire cell. The cell's height is composed of a ContentView, and a Separator (which is 1px). Therefore, once you get the height back from that method, you need to add 1px to it in heightForCellAtIndex. It's not right to add it in the UILabel subclass, and you can get rid of that class entirely.
同时还要注意,子view的约束无法决定父view的高度时. 一般来说,子view需要贴边约束,这样父view好判断出
其子view内容的大小
The problem is that your constraints are not determinative of the height of the cell. You have not pinned the top of the image view or the bottom of the image view to its superview (the contentView). So the cell has nothing internal to keep it from collapsing all the way to zero, as it were, when you call systemLayoutSizeFittingSize.
To put it another way: the way systemLayoutSizeFittingSize works is by treating something's internal constraints as struts that give it a minimum (or maximum) size. You have no struts.
ref:Using auto-layout to calculate table cell height
串行队列并不一定只对应着一个线程
串行队列只保证所有的任务的开始结束的先后顺序.
Serial queues are monogamous, but uncommitted. If you give a bunch of tasks to each serial queue, it will run them one at a time, using only one thread at a time. The uncommitted aspect is that serial queues may switch to a different thread between tasks. Serial queues always wait for a task to finish before going to the next one. Thus tasks are completed in FIFO order. You can make as many serial queues as you need with dispatch_queue_create.
- Dispatch Groups // coordinate groups of queues
- Semaphores // traditional counting Semaphores
- Barriers // synchronize tasks in a given concurrent queue
- Dispatch Sources // event handling for low-level events
- Dispatch I/O // file descriptor–based operations
- Dispatch Data Buffers // memory-based data buffer ref:amattn.com/p/grand_cen…
NSString *path = [myURL absoluteString]和
NSString *path = [myURL path]的区别
Question 1:
What is the actual difference between these methods?
Let's analyze this writing 6 lines of code - 3 for a local and 3 for http URL - and playing around with them a little bit. Let's create an NSURL using the file:// scheme. If you ask yourself why there are 3 / after file: you should remember that a complete URL exists of a scheme (file:// and absolute or relative path (you can find more information on creating URLs in RFC 1808 on page 3). We use an absolute path which starts with a / so that we end up with ///.
NSURL *aLocalURL = [NSURL URLWithString:@"file:///Users/dennis/Desktop/"];
NSLog(@"absolute string: %@", aLocalURL.absoluteString);
NSLog(@"path: %@", aLocalURL.path);
Output:
absolute string: file:///Users/dennis/Desktop/
path: /Users/dennis/Desktop
So we see that absoluteString still knows its scheme whereas path doesn't have this information anymore.
Note: path is a file (directory) URL and as the docs state, the trailing slash it is stripped.
Now let's take a look at remote URLs. With these type of URLs most people are more familiar. We create it using the same procedure as for local URLs. Our scheme is now http:// and our pathis www.apple.com/.
NSURL *anHTTPURL = [NSURL URLWithString:@"http://www.apple.com/"];
NSLog(@"absolute string: %@", anHTTPURL.absoluteString);
NSLog(@"path: %@", anHTTPURL.path);
Output:
absolute string: http://www.apple.com/
path: /
Again, we see that the absolute string still knows its scheme but path is now /. So path seems to be not an appropriate way when working with remote URLs.
However, when we have an URL like www.apple.com/index.html we get
absolute string: http://www.apple.com/index.html
path: /index.html
Reading the docs helps here, too:
Per RFC 3986, the leading slash after the authority (host name and port) portion is treated as part of the path.
So the path is everything beginning (and including) at the slash after the authority which is www.apple.com in our case.
Question 2
Is there a time when one should be used over the other?
From the docs: (method: path)
If this URL object contains a file URL (as determined with isFileURL), the return value of this method is suitable for input into methods of NSFileManager or NSPathUtilities.
In my opinion that sentence states clearly that you should use path when you work with NSFileManager or NSPathUtilities.
Conclusion:
When you work with remote URLs you (generally) use absoluteString, otherwise the result is not what you (generally) want. When you work with local URLs use path.
Sources:
http://www.ietf.org/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc3986.txt
NSURL Class Reference
关于Intrinsic Content Size,preferredMaxLayoutWidth
Intrinsic Content Size
Leaf-level views such as buttons typically know more about what size they should be than does the code that is positioning them. This is communicated through the intrinsic content size, which tells the layout system that a view contains some content that it doesn’t natively understand, and indicates how large that content is, intrinsically.
preferredMaxLayoutWidth
This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines, thereby increasing the height of the label.
sizeThatFits:
Asks the view to calculate and return the size that best fits the specified size.
Return Value
A new size that fits the receiver’s subviews.
The default implementation of this method returns the existing size of the view. Subclasses can override this method to return a custom value based on the desired layout of any subviews. For example, a UISwitch object returns a fixed size value that represents the standard size of a switch view, and a UIImageView object returns the size of the image it is currently displaying.
sizeToFit
calls sizeThatFits: with current view bounds and changes bounds size.
首先说intrinsicContentSize,它的最主要作用是告诉auto layout system的一些信息,可以认为它是后者的回调方法,auto layout system在对view进行布局时会参考这个回调方法的返回值;一般很少像CGSize size = [view intrinsicContentSize]
去使用intrinsicContentSize
API。
再来看sizeThatFits:
和systemLayoutSizeFittingSize:
,它们俩非常相似,都是为开发者直接服务的API(而不是回调方法)。所不同的是,sizeThatFits:
是auto layout之前就存在的,一般在leaf-level views中用得比较多,在计算size过程中,它可不会考虑constraints神马的;对于systemLayoutSizeFittingSize:
,它是随着auto layout(iOS 6)引入的,用于在view完成布局前获取size值,如果view的constraints确保了完整性和正确性,通常它的返回值就是view完成布局之后的view.frame.size的值。
它们之前存在相互调用的关系吗?经过测试发现,三者之前没有直接的调用关系。但是能得出这样的结论:intrinsicContentSize
的返回值会直接影响systemLayoutSizeFittingSize:
的返回值。至于底层是如何处理的不得而知。
ref:zhangbuhuai.com/2015/07/16/…
关于NSNotificationCenter相关的内存管理
"Does the NSNotification retain the object ? (in a similar fashion to NSMutableDictionary or Array) ... meaning I can release the object after posting the notification"
I'm not sure if the object and userInfo parameters are retained by that method or not, but in practice, it shouldn't really matter.
I think you may be envisioning that NSNotificationCenter is creating these notifications and broadcasting them in an asynchronous manner, but that isn't the case. As stated in the documentation for NSNotificationCenter (see NSNotificationCenter Class Reference), notifications are posted synchronously:
A notification center delivers notifications to observers synchronously. In other words, thepostNotification: methods do not return until all observers have received and processed the notification. To send notifications asynchronously use NSNotificationQueue. In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
So, in your code, the notification center creates the notification and then broadcasts it through the default center. Any objects which have registered for this combination of notification name and object will receive the notification and then perform the selector they specified when they registered for that notification. Afterwards, the control returns to the class that posted the notification.
In other words, by the time your code gets to the [teamDictCopy release] line, the teamDictCopywill already have been "used" by all of the interested parties. So, there shouldn't be any danger in releasing it.
Just a note on conventions. Generally, the object: parameter is meant to be the object that is posting the notification, and the userInfo: parameter is meant for an NSDictionary of extra information. So, normally, you would handle the notification like follows:
NSMutableDictionary *teamDictCopy = [self.teamDict mutableCopy];
[teamDictCopy setObject: [NSNumber numberWithInt:self.scrollViewIndex] forKey:@"imageIndex"];
if([self.statusButton.title isEqualToString:@"Completed"]){
[[NSNotificationCenter defaultCenter] postNotificationName:@"UnComplete"
object:self userInfo:teamDictCopy];
}
[teamDictCopy release];
ref:stackoverflow.com/questions/5…
关于view的contentMode属性
注意contentMode只是影响view绘制其自身的内容,它并不会影响子view的布局.
From the documentation:
The content mode specifies how the cached bitmap of the view’s layer is adjusted when the view’s bounds change.
- For an image view, this is talking about the image.
- For a view that draws its content, this is talking about the drawn content.
It does not affect the layout of subviews
.
关于UIContainerView
在storyboard上使用container view,可以方便将view controller嵌入到另一个container中
ref:blog.sina.com.cn/s/blog_5a6e…
关于clearsContextBeforeDrawing
static int count = 0;
@interface BView()
@end
@implementation BView
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(test) userInfo:nil repeats:YES];
} return self;
}
-(void)drawRect:(CGRect)rect {
[[UIColor greenColor] setFill];
[[NSString stringWithFormat:@"%d",count] drawInRect:self.bounds withFont:[UIFont systemFontOfSize:30]];
}
-(void) test {
count++;
[self setNeedsDisplay];
}
@end
相应的controller中的代码:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIView* v=[[BView alloc] initWithFrame:CGRectMake(10, 50, 200, 100)];
v.opaque=NO;
v.clearsContextBeforeDrawing=NO;
[self.view addSubview:v];
}
@end
显示结果为:
解释:
UIView 有个属性opaque, 默认为 YES
UIView 还有个属性clearsContextBeforeDrawing, 默认为 YES
* 当opaque=YES时, 系统调用-drawRect:前,不会清除以前内容
* 当opaque= NO时, 系统调用-drawRect:前,会根据clearsContextBeforeDrawing属性做不同行为
* clearsContextBeforeDrawing = YES, 则清除内容,以透明像素填充
* clearsContextBeforeDrawing = NO, 则不清除内容
以上是context清理,之后是backgroundColor填充context,默认为nil,相当于不做任何操作;
当你指定一个颜色后,系统会用backgroundColor填充context, 自然就擦除了你之前的内容。
输入视图管理
输入视图是指当对象为 firstResponder 对象时,显示另外一个视图用来处理当前对象的信息输入,如UITextView 和 UITextField 两个对象,在 UITextField 成为 firstResponder 对象时,会显示一个系统键盘,用来输入信息。这个键盘视图就是一个输入视图了。一共有两个相关的输入视图,一个是 inputView, 另一个是inputAccessoryView,这两个视图显示的关系如下图:
从图中可以看到, 如果 inputView 和 inputAccessoryView 两个属性都指定了相应的视图,则inputAccessoryView 对象显示在 inputView 对象的上面。 与输入相关的还有一个 reloadInputViews 方法用来重新载入输入视图。
[event allTouches] 和 [touches allObjects]区别
@implementation TView
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"touches.allObjects:%ld event.allTouches:%ld",(long)touches.allObjects.count,event.allTouches.count);
}
@end
[event allTouches]代表当前window所有的touch. Even the touches currently not active (not moving not starting not ending and not being canceled).
[touches allObjects]代表当前正在发生或正在变化的touch.
To my understanding it is as follows:
[event allTouches]
returns all touches that are part of the event. Some of those touches might be meant for another UIResponder.
For instance you might click in two view at the same time and the responder associated with each view will get called with all the touches of the event.
[touches allObject]
only contains touches ment for this responder. And is thus in most cases what you are after.
The event gives access to all the touches through allTouches
. Even the touches currently not active (not moving not starting not ending and not being canceled).
for (UITouch* touch in [[event allTouches] allObjects]) //loops through the list of all the current touches
touches
is the list of all the touches that have changed and are eligible for the current event.
for (UITouch* touch in [touches allObjects]) //loops through the list of all changed touches for this event.
So for touchesBegan:withEvent:
- If one finger touches the screen
touches
and[event allTouches]
will have the same content. - If a second finger touches the screen
touches
will provide the UITouch associated with this finger and[event allTouches]
will provide the UITouch for this finger and the one already touching the screen. - If 2 additional fingers touch the screen at the "same" time
touches
will provide the UITouch for the 2 additional fingers and[event allTouches]
will provide the 4 UITouch instances.
Now in the case of touchesEnded:withEvent:
- If one finger is lifted,
touches
will give access to the UITouch instance associated with that finger while[event allTouches]
will provide the 4 UITouch instances, even the one of the ending touch. ref: stackoverflow.com/questions/3…
pathsForResourcesOfType: inDirectory:用法
NSBundle* mb=[NSBundle mainBundle];
NSArray* arr=[mb pathsForResourcesOfType:@"png" inDirectory:@"PNG.bundle"];
NSLog(@"%@",arr);
输出上面的四个文件:
2015-12-22 13:12:54.869 TEST_Bundle_SubPath[18177:60b] (
"/var/mobile/Applications/A9307604-A67C-4203-8BBF-91A708CB2858/TEST_Bundle_SubPath.app/PNG.bundle/map_bus.png",
"/var/mobile/Applications/A9307604-A67C-4203-8BBF-91A708CB2858/TEST_Bundle_SubPath.app/PNG.bundle/map_drive.png",
"/var/mobile/Applications/A9307604-A67C-4203-8BBF-91A708CB2858/TEST_Bundle_SubPath.app/PNG.bundle/map_hospital.png",
"/var/mobile/Applications/A9307604-A67C-4203-8BBF-91A708CB2858/TEST_Bundle_SubPath.app/PNG.bundle/map_locate.png"
)
也就是说在打包成APP文件之后,所有资源文件会被放在根目录,但是.bundle以及.mmod 除外. Assets.car是Xcode的图片集(Images.xcassets)打包后生成的
把图片打包时bundle
Answer is stupidly simple Make a folder in finder, add files to it, rename it to bundlename.bundle drag into Xcode - success! to access, use the form of PathToMainBundle+"/bundlename.bundle"
代码访问:
NSString* imgFilePath=[@"WHUNoDataView.bundle" stringByAppendingPathComponent:@"nodataimg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imgFilePath]];
加载本地html
copy bundle resource只要加目录就行了。。。
一个异步问题
怎么保证顺序?
限制1还是不行啊
每个线程上传的时机不定啊
上传在另外一个进程中,已不在自己的控制之中
navigationbar的自动隐藏效果
实现如下效果:
-(void) scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView.contentOffset.y > 120)
{
[self showNavigationController:YES];
[self setTitle:self.infoGroup.infoGroupTitle];
}
else
{
[self showNavigationController:NO];
[self setTitle:@""];
}
}
-(void) showNavigationController:(BOOL)bShow{
if (bShow)
{
[self.navigationController.navigationBar setBackgroundImage:nil
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = nil;
self.navigationController.navigationBar.translucent = YES;
}
else
{
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
}
}
关于UIBezierPath及CGPath的bounds
UIBezier* mainPath=[UIBezierPath bezierPath];
//对mainPath进行操作......
CGRect t=mainPath.bounds;
CAShapeLayer* shape=[CAShapeLayer layer];
shape.path=mainPath.CGPath;
shape.lineWidth=1;
shape.strokeColor=_selectedColor.CGColor;
shape.strokeStart=0.0f;
shape.strokeEnd=1.0f;
//注意这里得到bounds可能形如:(origin = (x = 4.05025244, y = 2.05025244), size = (width = 9.89949417, height = 4.94974756)) ,这里的x,y并不为零
shape.bounds=mainPath.bounds; //注意这里得设置bounds,这样相应的origin信息才不会丢失
shape.masksToBounds=YES;
1. 也可以通过CGPathGetPathBoundingBox(mainPath.CGPath)来得到路径的bounds.
2. 通常我们进行如下设置的时候,要注意bounds的origin. aview.frame=bview.bounds
疑问: 对于CGPath的bounds之origin,不为(0,0),这意味着什么?
关于CALayer的bounds与frame的关系.
对于CALayer,设置其rect的最好方式设置其 Bounds + Position
The following is a quote from the CALayer documentation:
The frame rectangle is position and size of the layer specified in the superlayer’s coordinate space. For layers, the frame rectangle is a computed property that is derived from the values in the bounds, anchorPoint and position properties. When you assign a new value to this property, the layer changes its position and bounds properties to match the rectangle you specified. The values of each coordinate in the rectangle are measured in points.
It looks like with the CAShapeLayer when setting the frame by itself it does't keep the origin values from the assigned CGRect, only the size. When you set the bounds the origin is kept and therefore displays in the proper location. You also need to set the position value to the center point of where you want you shape to be displayed:
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, NULL, rect.size.width/2, rect.size.height/2, 100, (0), (M_PI_2), NO);
CGPathAddArc(path, NULL, rect.size.width/2, rect.size.height/2, 100-50, (M_PI_2), (0), YES);
CGPathCloseSubpath(path);
CAShapeLayer* arcLayer = [CAShapeLayer layer];
arcLayer.path = path;
CGRect pathRect = CGPathGetPathBoundingBox(path);
arcLayer.bounds = pathRect;
arcLayer.position = CGPointMake(CGRectGetMidX(pathRect), CGRectGetMidY(pathRect));
[self.layer addSublayer:arcLayer];
重要的评论:
In general with layers I think you get the best results by setting bounds + position and not frame. But for CAShapeLayer, I don't think bounds is important, unless you want to add a translation to the contents. However this doesn't explain why the path isn't being drawn does it?
ref:stackoverflow.com/questions/1…
关于UILabel的大于等于约束
给一个Label设置约束,其字体是15 ,高度是11 ,那么当我设置其约束为靠左靠上,宽度固定,高度大于等于11的时候,它的高度会自动变成18.
我估计是自适应到了,这个UILable的intrinsicContentSize了, 如果设置高度大于等于的话. 如果初始高度小于instrinicContentSize 的话
关于约束的层级关系
注意下面的subview可以添加宽度等于scrollview的约束.
NSDictionary* viewDic=@{@“scroll”:scrollview,@“subview”:subview}
[scrollview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview(==scroll)]" options:0 metrics:nil views:viewDic]];
注意上面约束VFL中的|,依然是指的是其父视图,但是其宽度等于scrollview. 同时也要注意,这个约束,是被添加到了scrollview上.
创建PCH文件
pch文件被预编译好之的一,放在一个缓存当中,然后在编译期间,被自动的隐式的包含在每一个文件当中. pch文件是为了节省编译时间的. 如果把经常发生变化的头文件放在里面,反而会浪费更多的编译时间.
What it is?
Prefix.pch is a precompiled header. Precompiled headers were invented to make compiling faster. Rather than parsing the same header files over and over, these files get parsed once, ahead of time.
Xcode
In Xcode, you add imports of the header files you want in a “prefix header,” and enabling Precompile Prefix Header so they get precompiled. But the idea behind a prefix header is different from precompiling. A prefix header is implicitly included at the start of every source file. It’s like each source file adds
#import "Prefix.pch"
How to remove?
In Xcode, go to your target's build settings (Command-Option-E, build tab) and uncheck Precompile Prefix Header (GCC_PRECOMPILE_PREFIX_HEADER). You can also remove the value of the Prefix Header setting if you wish.
Impact of compile time
Prefix headers are compiled and stored in a cache, and then automatically included in every file during compilation. This can speed up compilation, and lets you include a file without adding an import statement to every file using it. They are not required, and actually slow compilation
Note: Precompiling the prefix header will be most effective if the contents of the prefix header or any file it includes change rarely. If the contents of the prefix header or any file it includes change frequently, there may be a negative impact to overall build time."
How to Add?
at the top of the file, before anything else.
You need to create own PCH file
Add New file -> Other-> PCH file
Then add the path of this PCH file to your build setting->prefix header->path
($(SRCROOT)/filename.pch)
stackoverflow.com/questions/2…
代码创建的storyboard为什么根控制器为null
用下面这段代码创建的storyboard为什么根控制器为null
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
//设置UIWindow根控制器
//第一种方法 从storyborad获取控制器
//1.1获取storyboard对象
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Test" bundle:nil];
//1.2获取storyboard的第一个控制器(箭头所指的控制器)
id obj = [storyboard instantiateInitialViewController];
NSLog(@"obj:%@",obj);//打印obj,结果为:null
[self.window makeKeyAndVisible];
return YES;
}
关于UIBezierPath的旋转
1.路径没有所谓的中心的概念,它只会沿着origin进行旋转
2.要先应用矩阵变换,然后再进行填充等操作.
下面的代码:
- (void)drawRect:(CGRect)rect {
// Drawing code
UIBezierPath *thirdBasePath = [UIBezierPath bezierPathWithRect:CGRectMake(2.0, 4.0, 17.0, 17.0)];
UIBezierPath *secondBasePath = [UIBezierPath bezierPathWithRect:CGRectMake((self.frame.size.width / 2.0) - 3.0, 2.0, 17.0, 17.0)];
UIBezierPath *firstBasePath = [UIBezierPath bezierPathWithRect:CGRectMake(self.frame.size.width - 15.0, 4.0, 17.0, 17.0)];
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
[firstBasePath applyTransform: transform];
[secondBasePath applyTransform: transform];
[thirdBasePath applyTransform: transform];
[[UIColor redColor] setFill];
[firstBasePath fill];
[[UIColor blueColor] setFill];
[secondBasePath fill];
[[UIColor yellowColor] setFill];
[thirdBasePath fill];
}
stackoverflow.com/questions/2…
关于UIScrollview的一个不正确的用法
其实导致下面问题的根本,主要还是没有按正常的套路,给UIScrollview设置autolayout
虽然它设置了,scrollview的滚动内容高度:
self.editScrollView.contentSize = CGSizeMake(ScrrenWidth, 160+self.goodViewHeight.constant+self.good1ViewHeight.constant);
这样,是可以正常滚动了,但导致了goodview1或goodview超出父视图的部分无法响应触摸. 关于视图剪切的说明,如果子视图有部分超出了父视图,那么超出部分同样会被绘制,除非父视图设置了clipsToBounds属性;同时,无论如何,子视图超出父视图的那一部分,都不会响应该子视图的触碰事件。
关于UIView与CALayer的关系
由于UIView为其内部对应CALayer的代理,所以可以重写- drawLayer: inContext:
来进行一些绘制操作,但要注意在这个方法内部,要先调用一下父类的- drawLayer: inContext:
,这时,它会调用UIView的drawRect
方法.
- (void)drawRect:(CGRect)rect {
CGContextRef context=UIGraphicsGetCurrentContext();
CGMutablePathRef paths=CGPathCreateMutable();
CGRect b=self.bounds;
CGFloat radius=25;
CGPathAddArc(paths, NULL, CGRectGetMaxX(b)-radius, CGRectGetMinY(b)+radius,radius ,-M_PI_2,0,0);
CGPathAddArc(paths, NULL, CGRectGetMaxX(b)-radius, CGRectGetMaxY(b)-radius,radius ,0,M_PI_2,0);
CGPathAddArc(paths, NULL, CGRectGetMinX(b)+radius, CGRectGetMaxY(b)-radius,radius ,M_PI_2,M_PI,0);
CGPathAddArc(paths, NULL, CGRectGetMinX(b)+radius, CGRectGetMinY(b)+radius,radius ,M_PI,-M_PI_2,0);
CGContextAddPath(context, paths);
[[UIColor redColor] setFill];
CGContextFillPath(context);
CGPathRelease(paths);
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
[super drawLayer:layer inContext:ctx];
UIGraphicsPushContext(ctx);
UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
UIColor *color = [UIColor blackColor];
NSMutableParagraphStyle *style = [NSMutableParagraphStyle new];
[style setAlignment:NSTextAlignmentCenter];
NSDictionary *attribs = @{NSFontAttributeName: font,
NSForegroundColorAttributeName: color,
NSParagraphStyleAttributeName: style};
NSAttributedString *
text = [[NSAttributedString alloc] initWithString:@"孙悟空"
attributes:attribs];
[text drawInRect:CGRectMake(0, 0, 100, 20)];
UIGraphicsPopContext();
}
CALayer用完之后,要记得清除,否则会崩溃
这里在一个UIViewController中设置为一个layer的代理,那么要在该UIViewController中的ViewWillDisappear方法中将添加的layer从其父layer中删除. 否则在退出该viewController的时候,会造成app的异常崩溃,崩溃原因是[YourViewController isKindOfClass],向一个已经释放的对象发送了消息.
- (void)viewDidLoad {
[super viewDidLoad];
CALayer* layer=[CALayer layer];
layer.frame=self.view.bounds;
_subLayer=layer;
[self.view.layer addSublayer:layer];
layer.delegate=self;
[layer setNeedsDisplay];
}
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
UIGraphicsPushContext(ctx);
UIBezierPath* path=[UIBezierPath bezierPathWithArcCenter:self.view.center radius:self.view.center.x-1 startAngle:0 endAngle:M_PI*2 clockwise:YES];
[[UIColor redColor] setStroke];
path.lineWidth=1;
[path stroke];
UIGraphicsPopContext();
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[_subLayer removeFromSuperlayer];
}
CALayer 中的anchorPoint和position
1.这个属性其实代表是同一个点. anchorPoint是该点在CALayer内坐标系统的值. 而position是该点在CALayer的父视图坐标系统的值.
2.这两个属性可以被分别的改变. 如果只修改了anchorPoint那么,而position属性值没有改变. 为了让它们两个值都对应着同一个点,那么就只有frame发生变化了,来挪动一下CALayer的位置.
3.anchorPoint决定着CALayer身上的哪个点会在position所指定的位置上
CALayer 隐式动画属性
每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根层)。
- 当对非Root Layer的部分属性进行相应的修改时,默认会自动产生一些动画效果,这些属性称为Animatable Properties(可动画属性)。
- 列举几个常见的Animatable Properties:
- bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画
- backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画
- position:用于设置CALayer的位置。修改这个属性会产生平移动画
- (void)viewDidLoad {
[super viewDidLoad];
CALayer* layer=[CALayer layer];
layer.backgroundColor=[UIColor redColor].CGColor;
layer.frame=CGRectMake(50, 50, 100, 100);
layer.speed=0.1; //这是隐式动画的速度
self.mlay=layer;
[self.view.layer addSublayer:layer];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.mlay.position=CGPointMake(100, 500); //在这里改变position会产生动画效果.
}
CALayer Basic
为什么CALayer中使用CGColorRef和CGImageRef这2种数据类型,而不用UIColor和UIImage?
首先要知道:CALayer是定义在QuartzCore框架中的;CGImageRef、CGColorRef两种数据类型是定义在CoreGraphics框架中的;UIColor、UIImage是定义在UIKit框架中的
其次,QuartzCore框架和CoreGraphics框架是可以跨平台使用的,在iOS和Mac OS X上都能使用,但是UIKit只能在iOS中使用
因此,为了保证可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef
不过很多情况下,可以通过UIKit对象的特定方法,得到CoreGraphics对象,比如UIImage的CGImage方法可以返回一个CGImageRef
UIView和CALayer的其他关系
UIView可以通过subviews属性访问所有的子视图,类似地,CALayer也可以通过sublayers属性访问所有的子层
UIView可以通过superview属性访问父视图,类似地,CALayer也可以通过superlayer属性访问父层 如果两个UIView是父子关系,那么它们内部的CALayer也是父子关系。也就是说一个视图内CALayer的层级关系和这个视图内的层级关系是相同的.
CALayer与UIView
1.定义CALayer的子类
@implementation MJLayer
#pragma mark 绘制一个实心三角形
- (void)drawInContext:(CGContextRef)ctx {
// 设置为蓝色
CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
// 设置起点
CGContextMoveToPoint(ctx, 50, 0);
// 从(50, 0)连线到(0, 100)
CGContextAddLineToPoint(ctx, 0, 100);
// 从(0, 100)连线到(100, 100)
CGContextAddLineToPoint(ctx, 100, 100);
// 合并路径,连接起点和终点
CGContextClosePath(ctx);
// 绘制路径
CGContextFillPath(ctx);
}
@end
需要调用setNeedsDisplay
这个方法,才会触发drawInContext:
方法的调用,然后进行绘图
2.自定义层的方法
方法描述:设置CALayer的delegate,然后让delegate实现 drawLayer:inContext: 方法,当CALayer需要绘图时,会调用delegate的 drawLayer:inContext: 方法进行绘图。
- 这里要注意的是:不能再将某个UIView设置为CALayer的delegate,因为UIView对象已经是它内部根层的delegate,再次设置为其他层的delegate就会出问题。UIView和它内部CALayer的默认关系图:
#pragma mark 画一个矩形框
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
// 设置蓝色
CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);
// 设置边框宽度
CGContextSetLineWidth(ctx, 10);
// 添加一个跟层一样大的矩形到路径中
CGContextAddRect(ctx, layer.bounds);
// 绘制路径
CGContextStrokePath(ctx);
}
3.UIView的详细显示过程
当UIView需要显示时,它内部的层会准备好一个CGContextRef(图形上下文),然后调用delegate(这里就是UIView)的drawLayer:inContext:方法,并且传入已经准备好的CGContextRef对象。而UIView在drawLayer:inContext:方法中又会调用自己的drawRect:方法
平时在drawRect:中通过UIGraphicsGetCurrentContext()获取的就是由层传入的CGContextRef对象,在drawRect:中完成的所有绘图都会填入层的CGContextRef中,然后被拷贝至屏幕 ref:www.cnblogs.com/mjios/archi…
使用定位服务时的设置: 这样设置了,在启用定位时,才会有相应的提示
在使用predicateWithFormat时的注意事项
//得到空的NSArray,非预期
NSArray *filtered2 = [m filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"%@=%@",@"name",s1]];
//结果正常
NSString* filterFormater=[NSString stringWithFormat:@"%@=%%@",@"name"];
NSArray *filtered4 = [m filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:filterFormater,s1]]; //结果正常 NSArray *filtered3 = [m filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name=%@",s1]];
让非静态的UITableView实现固定header section的效果
大体的原理,是通过操作contentInset来动态调整可滚动区域.
//plain style tableview with fixed section header
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat sectionHeaderHeight = 40;
if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
} else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
}
}
ref: stackoverflow.com/questions/6…
tableview首次,不用调用reloadData,也会加载表格数据一次. tableview首次,不用调用reloadData,也会加载表格数据一次.
宽度固定的情况下,让UILabel根据字数的多少,自动调用字体
titleLabel.adjustsFontSizeToFitWidth=YES;
titleLabel.minimumScaleFactor
使用NSDecimalNumberHandler来对浮点数进行各种近似操作.
+(NSString *)notRounding:(float)price afterPoint:(int)position{
NSDecimalNumberHandler* roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundUp scale:position raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
NSDecimalNumber *ouncesDecimal;
NSDecimalNumber *roundedOunces;
ouncesDecimal = [[NSDecimalNumber alloc] initWithFloat:price];
roundedOunces = [ouncesDecimal decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
[ouncesDecimal release];
return [NSString stringWithFormat:@"%@",roundedOunces];
}
对于同一个数据,下面两个表达式的值是有细微差别的,在精确度要求高的场合要注意区分.
[NSNumber floatValue]
与[NSNumber doubleValue]
是有差别的.
还有对浮点的处理,可以使用下列API,选择相应的behavior,可以设置不同的四舍五入模式:
NSDecimalNumberHandler* roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundUp scale:position raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
NSDecimalNumber *ouncesDecimal;
NSDecimalNumber *roundedOunces;
ouncesDecimal = [[NSDecimalNumber alloc] initWithFloat:price];
roundedOunces = [ouncesDecimal decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
在使用autolayout过程中,出现有关UIView-Encapsulated-Layout-Width之类的错误的记录,及解决方法和原因.
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
UITableViewHeaderFooterView* v=[[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:@"section"];
v.translatesAutoresizingMaskIntoConstraints=NO;
v.contentView.backgroundColor=[UIColor whiteColor];
UILabel* lbl=[[UILabel alloc] init];
lbl.text=self.sectionArray[section];
lbl.translatesAutoresizingMaskIntoConstraints=NO;
lbl.textAlignment=NSTextAlignmentCenter;
[v.contentView addSubview:lbl];
UILabel* line=[[UILabel alloc] init];
line.translatesAutoresizingMaskIntoConstraints=NO;
line.backgroundColor=[UIColor lightGrayColor];
[v.contentView addSubview:line];
NSDictionary* viewDic=@{@"lbl":lbl,@"line":line};
[v.contentView addConstraint:[NSLayoutConstraint constraintWithItem:lbl attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:v.contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[v.contentView addConstraint:[NSLayoutConstraint constraintWithItem:lbl attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:v.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
[v.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[line]-|" options:0 metrics:nil views:viewDic]];
[v.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[line(==1)]|" options:0 metrics:nil views:viewDic]];
return v;
}
出现如下错误:
2015-06-04 14:09:00.107 [6451:1929782] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don’t want. Try this: (1) look at each constraint and try to figure out which you don’t expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you’re seeing NSAutoresizingMaskLayoutConstraints that you don’t understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
“<NSLayoutConstraint:0x183a59b0 UILabel:0x183a4d50.leading == _UITableViewHeaderFooterContentView:0x183a47d0.leadingMargin>”,
“<NSLayoutConstraint:0x183a59f0 _UITableViewHeaderFooterContentView:0x183a47d0.trailingMargin == UILabel:0x183a4d50.trailing>”,
“<NSLayoutConstraint:0x183a7760 'UIView-Encapsulated-Layout-Width' H:[_UITableViewHeaderFooterContentView:0x183a47d0(0)]>”
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x183a59f0 _UITableViewHeaderFooterContentView:0x183a47d0.trailingMargin == UILabel:0x183a4d50.trailing>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
解决方法: 改为:
//降低出现问题约束的优先级. [v.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(20@999)-[line]-(20@999)-|" options:0 metrics:nil views:viewDic]]; 或
//让它和所期望的约束一至
[v.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[line]|" options:0 metrics:nil views:viewDic]];
**问题解析: **
Based on a ton of observation I believe (but cannot know for certain) that the constraints named UIView-Encapsulated-Layout-Width and UIView-Encapsulated-Layout-Height are created by UICollectionView and friends, and exist to enforce the size returned by the sizeForItemAtIndexPath delegate method. I guess it’s there to ensure that the UICollectionViewCell set up by cellForItemAtIndexPath ends up the size that it was told it would be. Which answers my initial question here. A second question is why were the constraints unsatisfiable? The cell’s intrinsic height should have been the same as UIView-Encapsulated-Layout-Height. Again, I don’t know for certain, but I suspect it was a rounding error (i.e. intrinsic height came to 200.1 pixels, the UIView-Encapsulated-Layout-Height maybe rounded to 200. The fix I came up with was to just lower the priority of the relevant cell constraint to allow UIView-Encapsulated-Layout-Height to have the last word.
ref: stackoverflow.com/questions/2…
- (void)viewDidLoad {
[super viewDidLoad];
UIView* v=[[UIView alloc] init];
[self.view addSubview:v];
v.backgroundColor=[UIColor lightGrayColor];
v.translatesAutoresizingMaskIntoConstraints=NO;
NSDictionary* viewDic=@{@"v":v};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(50)-[v]-(50)-|" options:0 metrics:nil views:viewDic]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(21)-[v]-(300)-|" options:0 metrics:nil views:viewDic]];
}
上面的约束在iphone4上会出现问题的:
2016-07-04 09:51:08.094 TEST_TestView[26337:98011] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x7bea2700 H:|-(21)-[UIView:0x7be9ff00] (Names: '|':UIView:0x7be97ab0 )>",
"<NSLayoutConstraint:0x7bea2730 H:[UIView:0x7be9ff00]-(300)-| (Names: '|':UIView:0x7be97ab0 )>",
"<NSLayoutConstraint:0x7d9620b0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7be97ab0(320)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7bea2730 H:[UIView:0x7be9ff00]-(300)-| (Names: '|':UIView:0x7be97ab0 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
主要是由于上面的约束,在iphone4上,计算出view的宽度为负值,而这是不允许的,那么解决方法:
方法1:改变一下相关的约束,使其不为负
方法2:降低出现问题的约束的优先级, [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(21)-[v]-(300@999)-|" options:0 metrics:nil views:viewDic]];
UILable中使用约束的注意事项:
- preferredMaxLayoutWidth的使用.
@property(nonatomic) CGFloat preferredMaxLayoutWidth This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines, thereby increasing the height of the label.
- 直接计算出高度,注意在给UILabel添加约束的时候,要使用>=
self.itemValueLbl=[[UILabel alloc] init];
self.itemValueLbl.text=value;
self.itemValueLbl.textAlignment=NSTextAlignmentLeft;
self.itemValueLbl.font=[UIFont systemFontOfSize:15];
self.itemValueLbl.translatesAutoresizingMaskIntoConstraints=NO;
self.itemValueLbl.lineBreakMode=NSLineBreakByCharWrapping;
self.itemValueLbl.numberOfLines=0;
[self.contentView addSubview:self.itemValueLbl];
NSDictionary* viewDic=@{@"name":self.itemNameLbl,@"value":self.itemValueLbl};
//计算高度是为了适配IOS6. IOS7,8可不用高度约束,
CGSize s1=[value sizeWithFont:[UIFont systemFontOfSize:15.0f] constrainedToSize:CGSizeMake(self.contentView.bounds.size.width*0.7, 1000) lineBreakMode:NSLineBreakByCharWrapping];
NSDictionary* metrics=@{@"height":@(s1.height)};
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[name]-(10)-[value]" options:0 metrics:nil views:viewDic]];
//这里的高度约束大于等于很重要!
self.nameLblHeightCts=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[value(>=height)]" options:0 metrics:metrics views:viewDic];
ref: stackoverflow.com/questions/1…
如何比较两个NSNull值.
if (myArray != (id)[NSNull null])
OR
if(![myArray isKindOfClass:[NSNull class]])
ref:stackoverflow.com/questions/1…
使用下面的VFL并不能达以view居中的效果
[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=20)-[view(==200)]-(>=20)-|"
options: NSLayoutFormatAlignAllCenterX | NSLayoutFormatAlignAllCenterY
metrics:nil
views:@{@"view" : view}];
要使用VFL来实现居中,得使用一些hack技巧:
UILabel* label=[[UILabel alloc] init];
label.translatesAutoresizingMaskIntoConstraints=NO;
label.text=@"Test Center";
label.backgroundColor=[UIColor redColor];
[self.view addSubview:label];
UIView* superview=self.view;
NSDictionary* viewDic=NSDictionaryOfVariableBindings(label,superview);
//不用|,直接使用superview来引用父视图.
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[superview]-(<=1)-[label]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:viewDic]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[superview]-(<=1)-[label]" options:NSLayoutFormatAlignAllCenterY metrics:nil views:viewDic]];
//下面代码让Label水平居中,并距底边50
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[superview]-(<=1)-[label]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:viewDic]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[label]-(==50)-|" options:0 metrics:nil views:viewDic]];
The original code uses a trick (or a hack).
AlignAllCenterY was not meant to center views within the container. The options are there to specify the relative position of the subviews - for example, if you have 3 labels in the same container, you can make them all top aligned or center aligned between themselves - not with the container (implicitly specified by |).
The trick is that when you specify the superview explicitly, the framework doesn't realize it a adds the constraints.
The correct way to center a view in its container is the following:
let centerX = NSLayoutConstraint(item: label,
attribute: .CenterX,
relatedBy: .Equal,
toItem: view,
attribute: .CenterX,
multiplier: 1.0,
constant: 0.0);
view.addConstraint(centerX);
let centerY = NSLayoutConstraint(item: label,
attribute: .centerY,
relatedBy: .Equal,
toItem: view,
attribute: .centerY,
multiplier: 1.0,
constant: 0.0);
view.addConstraint(centerY);
注意VFL只有<=,>=,==运算符.
让UIView响应touch up和 touch douwn.
-
iOS Detect tap down and touch up of a UIView A Gesture Recognizer is probably overkill for what you want.
-
You probably just want to use a combination of -touchesBegan:withEvent: and -touchesEnded:withEvent:.
This is flawed, but it should give you and idea of what you want to do.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.touchDown = YES;
self.backgroundColor = [UIColor redColor];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// Triggered when touch is released
if (self.isTouchDown) {
self.backgroundColor = [UIColor whiteColor];
self.touchDown = NO;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// Triggered if touch leaves view
if (self.isTouchDown) {
self.backgroundColor = [UIColor whiteColor];
self.touchDown = NO;
}
}
stackoverflow.com/questions/1…
UIControl 默认情况下不会将自己捕获的事件传给 superview
在开发一个 iPad 应用过程中,我在一个 tableViewCell 的 contentView 里添加了自定义的一些视图,一开始我是将它继承自 UIControl 的,并让它实现了拖动, 可以从 tableView 中拖出来放到其它地方,没有问题。 后来,我想让它好看点,加上背景,于是继承自 UIImageView ,然后在拖动时出问题了!tableView 跟着一些动了,我检查了 touchesBegan 等方法,应该都没有问 题,已经是当时没出问题时的代码了。最后突然想起,我改了它的基类!改回去后,一切正常! 于是测试发现,UIControl 默认情况下不会将自己捕获的事件传给 superview,而 UIView 是会的,我想是因为 UIView 设计之初就不是用来处理事件的,所以将事件 传给了 superview
。同时 UIControl 和 UIImageView 都是继承自 UIView。 另外,UIControl 比较智能的一点是,当快迅滑动时会将事件传给 superview,所以在 tableView 中,慢点动,可以将它拖出来(我自己实现的),来快迅拖则是滚动 tableView
在loadView中为UIViewController加载自定义视图
Apple gives us four concise steps to follow and even a code example:
- (void)loadView
{
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColor blackColor];
self.view = contentView;
levelView = [[LevelView alloc] initWithFrame:applicationFrame viewController:self];
[self.view addSubview:levelView];
}
viewWithTage会查找当前视图,以及其所包含的所有视图(子视图,孙视图…等等).
- (UIView *)viewWithTag:(NSInteger)tag
Returns the view whose tag matches the specified value.
This method searches the current view and all of its subviews for the specified
递归搜索是从父视图开始搜索
递归搜索是深度优先算法——优先进入子视图搜索,再搜索同级视图
关于-sizeThatFits
-sizeToFit
pretty much calls-sizeThatFits:
(probably with the view’s current size as the argument), and the default implementation of -sizeThatFits: does almost nothing (it just returns its argument).sizeToFit:
is always the method that you should override, it’s the designated initializer of sizing methods. A great use for this method is to allow users to initialize your class with a zero sized rect while still maintaining a proper frame.
3.-(CGSize)sizeThatFits:(CGSize)size
is the unsung hero of custom UIView subclasses. This method can be used to set minimum sizes, maximum sizes, and optimal sizes.
sizethatfit 不会对控制做改变,只会计算返回CGSize数值
ref:jimkubicek.com/blog/2012/1…
使用localizedStandardCompare:来对常见的对象进行排序
//任何时候当你在为面向用户的字符串排序时,一定要加入localizedStandardCompare:
选择器,它将根据当前语言环境的语言规则进行排序(语言环境可能会根据大小写,变音符号等等的顺序而发生改变)。
// NSSortDescriptor *firstNameSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"firstName" ascending:YES selector:@selector(localizedStandardCompare:)];
浮点数的精确位数计算.
+(NSString *)rounding:(double)price afterPoint:(int)position{
NSDecimalNumberHandler* roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:position raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
NSDecimalNumber *ouncesDecimal;
NSDecimalNumber *roundedOunces;
ouncesDecimal = [[NSDecimalNumber alloc] initWithDouble:price];
roundedOunces = [ouncesDecimal decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
[ouncesDecimal release];
NSString* formatStr=[NSString stringWithFormat:@"%%.%df",position];
return [NSString stringWithFormat:formatStr,roundedOunces.doubleValue];
}
设置表格分隔线的inset
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[tableView setLayoutMargins:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
用分类作扩展更好
A note on cancelsTouchesInView
In using tap gesture recognizer, you might want to disable cancelsTouchesInView (set to NO), so that it pass the touch event to other views (eg table view cell). chuan The default is YES, which means touch event will be consumed and not passed on. This is a checkbox if you are using storyboard. just highlight UITableViewCell during touch down.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
对数组进行多重排序
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSSortDescriptor *descriptor1 = [[NSSortDescriptor alloc] initWithKey:@"endCalYear" ascending:YES];
NSSortDescriptor *descriptor2 = [[NSSortDescriptor alloc] initWithKey:@"endMonth" ascending:YES];
NSSortDescriptor *descriptor3 = [[NSSortDescriptor alloc] initWithKey:@"periodLength" ascending:YES];
NSArray *sortDescriptors = @[descriptor1, descriptor2, descriptor3];
[fetchRequest setSortDescriptors:sortDescriptors];
关于layoutSubviews
-(void)layoutSubviews{
//This is where the framework updates the layout based on the constraints.
[super layoutSubviews];
//在_bottomScrollView根据约束布局完成之后,我可以在这里修改它的frame. 最终会得到我们想要的结果.
CGRect r= _bottomScrollView.frame;
r.origin.x+=300;
_bottomScrollView.frame=r;
}