iOS 实现快速切换主题详细教程(附上源码)
前言
iOS 实现主题切换,相信在未来的app里也是会频繁出现的,尽管现在只是出现在主流的APP,如(QQ、新浪微博、酷狗音乐、网易云音乐等),但是现在是看颜值、追求个性的年代,所以根据用户喜好自定义/切换主题也是未来app的必备功能了。
实现思路
为了降低耦合度,决定采用的方案是使用NSObject的分类来实现主题设置,有些读者可能会想为何不使用UIView的分类而是使用NSObject的分类?建议这部分读者看一下UIBarItem父类,然后仔细思考一下,就会理解了。
设置主题色

PYThemeColor.png
创建主题色池
将需要设置主题色的控件及其对应属性/方法添加到主题色池中
调用设置主题色方法时,遍历主题色池中的控件,使用KVC设置对应属性或调用对应的方法来实现主题色的设置
代码实现
建议读者在理解思路以后先下载源码大概看一下(纵观全局)再阅读以下内容:
源码地址:https://github.com/iphone5solo/PYTheme
1. 创建主题色池
由于是在NSObject的分类里面创建,为了方便管理,设置全局变量_themeColorPool,并通过懒加载完成_themeColorPool的实例化。数组中的对象采用为NSDictionary的原因见下一步就会理解了
|
1
2
3
4
5
6
7
8
9
10
11
|
/** 主题颜色池 */static NSMutableArray *_themeColorPool;#pragma mark - 懒加载- (NSMutableArray *)themeColorPool{ if (!_themeColorPool) { _themeColorPool = [NSMutableArray array]; } return _themeColorPool;} |
2. 添加控件到主题色池中
由于颜色设置有的可以直接通过属性设置也有的需要通过调用方法才可设置。以UIButton为例,设置背景色可通过属性button.backgroundColor设置,设置选中状态时的字体颜色则要调用setTitleColor:forState:方法才可设置,于是,就得提供两个方法供使用者调用,如下
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * 添加到主题色池 * selector : 执行方法 * objects : 方法参数数组 * 注意:方法参数必须按顺序一一对应,如果涉及到的主题色设置使用 PYTHEME_THEME_COLOR 宏定义代替 * 如果数组中某个参数为nil,需包装为 [NSNull null] 对象再添加到数组中 */- (void)py_addToThemeColorPoolWithSelector:(SEL)selector objects:(NSArray *)objects;/** * 添加到主题色池 * propertyName : 属性名 */- (void)py_addToThemeColorPool:(NSString *)propertyName; |
实现如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
#pragma mark - Theme Color/** * 添加到主题色池 * selector : 执行方法 * objects : 方法参数数组 * 注意:方法参数必须按顺序一一对应,如果涉及到的主题色设置使用 PYTHEME_THEME_COLOR 宏定义代替 * 如果数组中某个参数为nil,需包装为 [NSNull null] 对象再添加到数组中 */- (void)py_addToThemeColorPoolWithSelector:(SEL)selector objects:(NSArray *)objects{ // 判断参数是否为空 if (!objects) return; Class appearanceClass = NSClassFromString(@"_UIAppearance"); // 如果对象为_UIAppearance,直接返回 if ([self isMemberOfClass:appearanceClass]) return; // 键:对象地址+方法名 值:对象 NSString *pointSelectorString = [NSString stringWithFormat:@"%p%@", self, NSStringFromSelector(selector)]; NSDictionary *dic = @{ pointSelectorString : self, PYTHEME_COLOR_ARGS_KEY : objects }; // 判断是否已经在主题色池中 if (![[self themeColorPool] containsObject:dic]) { // 不在主题色池中 [[self themeColorPool] addObject:dic]; if (_currentThemeColor) { // 已经设置主题色,直接设置 [self py_performSelector:selector withObjects:objects]; } }}/** * 添加到主题色池 * propertyName : 属性名 */- (void)py_addToThemeColorPool:(NSString *)propertyName{ // 如果对象为_UIAppearance,直接返回 Class appearanceClass = NSClassFromString(@"_UIAppearance"); if ([self isMemberOfClass:appearanceClass]) return; // 键:对象地址+属性名 值:对象 NSString *pointString = [NSString stringWithFormat:@"%p%@", self, propertyName]; NSDictionary *dic = @{ pointString : self }; // 判断是否已经在主题色中 if (![[self themeColorPool] containsObject:dic]) { // 不在主题色池中 [[self themeColorPool] addObject:dic]; if (_currentThemeColor) { // 已经设置主题色,直接设置 [self setValue:_currentThemeColor forKey:propertyName]; } } // 遍历主题色池(移除应该被回收的对象) for (NSDictionary *dict in [[self themeColorPool] copy]) { // 取出key NSString *objectKey = nil; for (NSString *key in [dict allKeys]) { if (![key isEqualToString:PYTHEME_COLOR_ARGS_KEY]) { objectKey = key; break; } } // 取出对象 id object = [dict valueForKey:objectKey]; // 取出对象的引用计数 NSInteger retainCount = [[object valueForKey:@"retainCount"] integerValue]; if (retainCount == 2) { // 对象应该被回收了 [[self themeColorPool] removeObject:dict]; } }} |
为了满足个别需求,所以还是提供一下从主题色池中移除控件的方法
|
1
2
3
4
5
6
7
8
9
10
|
/** * 从主题色池移除 * propertyName : 属性名 */- (void)py_removeFromThemeColorPool:(NSString *)propertyName;/** * 从主题色池移除 * selector : 方法选择器 */- (void)py_removeFromThemeColorPoolWithSelector:(SEL)selector; |
实现如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
/** * 从主题色池移除 * propertyName : 属性名 */- (void)py_removeFromThemeColorPool:(NSString *)propertyName{ // 如果对象为_UIAppearance,直接返回 Class appearanceClass = NSClassFromString(@"_UIAppearance"); if ([self isMemberOfClass:appearanceClass]) return; // 键:对象地址+属性名 值:对象 NSString *pointString = [NSString stringWithFormat:@"%p%@", self, propertyName]; NSDictionary *dic = @{ pointString : self }; // 判断是否已经在主题色池中 if ([[self themeColorPool] containsObject:dic]) { // 在主题色池中 [[self themeColorPool] removeObject:dic]; }}/** * 从主题色池移除 * selector : 方法选择器 */- (void)py_removeFromThemeColorPoolWithSelector:(SEL)selector{ // 如果对象为_UIAppearance,直接返回 Class appearanceClass = NSClassFromString(@"_UIAppearance"); if ([self isMemberOfClass:appearanceClass]) return; // 键:对象地址+方法名 NSString *pointSelectorString = [NSString stringWithFormat:@"%p%@", self, NSStringFromSelector(selector)]; // 遍历主题色池(移除应该被回收的对象) for (NSDictionary *dict in [[self themeColorPool] copy]) { for (NSString *key in [dict allKeys]) { if ([key isEqualToString:pointSelectorString]) { // 存在,移除 [[self themeColorPool] removeObject:dict]; return; } } }} |
3. 设置主题色
实现如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/** * 设置主题色 * color : 主题色 */- (void)py_setThemeColor:(UIColor *)color{ _currentThemeColor = color; // 遍历缓主题池,设置统一主题色 for (NSDictionary *dict in [_themeColorPool copy]) { // 取出key NSString *objectKey = nil; for (NSString *key in [dict allKeys]) { if (![key isEqualToString:PYTHEME_COLOR_ARGS_KEY]) { objectKey = key; break; } } // 取出对象 id object = [dict valueForKey:objectKey]; if ([objectKey containsString:@":"]) { // 方法 // 取出参数 NSArray *args = dict[PYTHEME_COLOR_ARGS_KEY]; // 取出方法 NSString *selectorName = [objectKey substringFromIndex:[[NSString stringWithFormat:@"%p", object] length]]; SEL selector = NSSelectorFromString(selectorName); // 调用方法,设置属性 [object py_performSelector:selector withObjects:args]; } else { // 成员属性 // 取出属性值 NSString *propertyName = [objectKey substringFromIndex:[[NSString stringWithFormat:@"%p", object] length]]; // 给对象的对应属性赋值(使用KVC) [object setValue:color forKeyPath:propertyName]; } }} |
使用
假设有个需求:UINavigationBar的背景颜色和UIButton选中时的字体颜色会随着主题颜色的变化而变化,实现如下:
将navigationBar的background和UIButton的setTitleColor:forState:方法添加到主题池中,方法参数中如果是设置为主题色的参数则用PYTHEME_THEME_COLOR占位,如果参数为nil,则使用[NSNull null]代替
|
1
2
3
4
5
6
7
8
9
|
// 创建导航栏UINavigationBar *navigationBar = [[UINavigationBar alloc] init];// 添加到主题色池中[navigationBar py_addToThemeColorPool:@"barTintColor"];// 创建按钮UIButton *button = [[UIButton alloc] init];// 添加到主题色中[button py_addToThemeColorPoolWithSelector:@selector(setTitleColor:forState:) objects:@[PYTHEME_THEME_COLOR, @(UIControlStateSelected)]]; |
设置主题色
|
1
2
|
// 设置主题色为红色[self py_setThemeColor:[UIColor redColor]]; |
这里有一点注意的是[object py_performSelector:selector withObjects:args];这是自己实现的performSelector 多参调用关于这方面的网上已经有很多教程了,这里就不多介绍了。直接附上的我实现(内部方法,主要考虑到自己的使用):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#pragma mark - performSelector 多参调用- (id)py_performSelector:(SEL)selector withObjects:(const NSArray *)objects{ // 1. 创建方法签名 // 根据方法来初始化NSMethodSignature NSMethodSignature *methodSignate = [[self class] instanceMethodSignatureForSelector:selector]; if (!methodSignate) { // 没有该方法 return self; } // 2. 创建invocation对象(包装方法) NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignate]; // 3. 设置相关属性 // 调用者 invocation.target = self; // 调用方法 invocation.selector = selector; // 获取除self、_cmd的参数个数 NSInteger paramsCount = methodSignate.numberOfArguments - 2; // 取最少的,防止越界 NSInteger count = MIN(paramsCount, objects.count); // 用于dictionary的拷贝(用于保住objCopy,避免非法内存访问) NSMutableDictionary *objCopy = nil; // 设置参数 for (int i = 0; i < count; i++) { // 取出参数对象 id obj = objects[i]; // 如果是主题颜色参数颜色,则设置 if ([obj isKindOfClass:[NSString class]] && [obj isEqualToString:PYTHEME_THEME_COLOR]) { obj = _currentThemeColor; } // 判断需要设置的参数是否是NSNull, 如果是就设置为nil if ([obj isKindOfClass:[NSNull class]]) { obj = nil; } // 获取参数类型 const char *argumentType = [methodSignate getArgumentTypeAtIndex:i + 2]; // 判断参数类型 根据类型转化数据类型(如果有必要) NSString *argumentTypeString = [NSString stringWithUTF8String:argumentType]; if ([argumentTypeString isEqualToString:@"@"]) { // id // 如果是dictionary,可能存在 PYTHEME_THEME_COLOR if ([obj isKindOfClass:[NSDictionary class]]) { // NSDictionary objCopy = [obj mutableCopy]; // 取出所有键 NSArray *keys = [objCopy allKeys]; for (NSString *key in keys) { // 取出值 id value = objCopy[key]; if ([value isKindOfClass:[NSString class]] && [value isEqualToString:PYTHEME_THEME_COLOR]) { // 替换成颜色 [objCopy setValue:_currentThemeColor forKey:key]; } } [invocation setArgument:&objCopy atIndex:i + 2]; } else { // 其他 [invocation setArgument:&obj atIndex:i + 2]; } } else if ([argumentTypeString isEqualToString:@"B"]) { // bool bool objVaule = [obj boolValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"f"]) { // float float objVaule = [obj floatValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"d"]) { // double double objVaule = [obj doubleValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"c"]) { // char char objVaule = [obj charValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"i"]) { // int int objVaule = [obj intValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"I"]) { // unsigned int unsigned int objVaule = [obj unsignedIntValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"S"]) { // unsigned short unsigned short objVaule = [obj unsignedShortValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"L"]) { // unsigned long unsigned long objVaule = [obj unsignedLongValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"s"]) { // shrot short objVaule = [obj shortValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"l"]) { // long long objVaule = [obj longValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"q"]) { // long long long long objVaule = [obj longLongValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"C"]) { // unsigned char unsigned char objVaule = [obj unsignedCharValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"Q"]) { // unsigned long long unsigned long long objVaule = [obj unsignedLongLongValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"{CGRect={CGPoint=dd}{CGSize=dd}}"]) { // CGRect CGRect objVaule = [obj CGRectValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } else if ([argumentTypeString isEqualToString:@"{UIEdgeInsets=dddd}"]) { // UIEdgeInsets UIEdgeInsets objVaule = [obj UIEdgeInsetsValue]; [invocation setArgument:&objVaule atIndex:i + 2]; } } // 4.调用方法 [invocation invoke]; // 5. 设置返回值 id returnValue = nil; if (methodSignate.methodReturnLength != 0) { // 有返回值 // 将返回值赋值给returnValue [invocation getReturnValue:&returnValue]; } return returnValue;} |
细节处理
1. 设置主题色的方式
通过属性直接设置主题色
通过调用方法并以主题色为参数来设置主题色
通过调用方法但主题色被封装后(如:NSDictionary)作为参数设置主题色
2. 自动管理内存管理
当对象应该被释放后,下一次当主题色池有新元素添加时,会遍历主题色池,根据对象的引用计数来决定是否移除对象(实现自动管理内存),因此:主题色池中最多可能会残留一个对象,这对内存几乎没有任何影响,如果要及时释放对象本人认为可以采用KVO监听对象的引用计数(未尝试),但是耗能高,不建议这么做!
3. 当对象为_UIAppearance类时,不添加到主题色池
了解UIAppearance的读者应该可以理解,而且使用UIAppearance的目的也为为了设置全局色,所以为了避免冲突,如果使用了该“技术”就不添加到主题色池
设置主题图片
观察了新浪微博、酷狗音乐等app,发现设置主题图片还是很有必要的,而且发现每套主题皮肤/图片都有对应的主题色,所以在设计接口的时候都考虑了这方面的需求。先看一下设置主题图片的基本原理,如下:
创建一个主题图片池(使用懒加载)
将相关控件对象直接添加到主题图片池中
设置主题图片时,通过block把主题图片池中的所有对象传递给用户,用户实现block,在block中获得对象,并根据需求设置相关属性完成主题图片的设置
代码实现:
1. 创建一个主题图片池(使用懒加载)
|
1
2
3
4
5
6
7
8
9
10
|
/** 主题图片池 */static NSMutableArray(id) *_themeImagePool;(此处圆括号代替尖括号)- (NSMutableArray *)themeImagePool{ if (!_themeImagePool) { _themeImagePool = [NSMutableArray array]; } return _themeImagePool;} |
2. 添加相关控件到主题图片池中
因为在设置图片是,比较复杂,如UITabBar上面的UIBarItem的图片、字体颜色等,所以为了满足大部分用户的需求,决定采用的是直接存储控件对象
|
1
2
3
4
5
|
/** 添加到主题图片池 */- (void)py_addToThemeImagePool;/** 从主题图片池中移除 */- (void)py_removeFromThemeImagePoo |
实现如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#pragma mark - Theme Image/** 添加到主题图片池 */- (void)py_addToThemeImagePool{ // 如果对象为_UIAppearance,直接返回 Class appearanceClass = NSClassFromString(@"_UIAppearance"); if ([self isMemberOfClass:appearanceClass]) return; if ([self isKindOfClass:[UITabBarItem class]]) { // 如果是UITabBarItem,判断是否有设置图片 UITabBarItem *item = (UITabBarItem *)self; if (!item.image) { // 没有设置图片 item.image = [[UIImage alloc] init]; } if (!item.selectedImage) { // 没有设置图片 item.selectedImage = [[UIImage alloc] init]; } } // 判断是否已经在主题图片池中 if (![[self themeImagePool] containsObject:self]) { // 不在主题图片池中 [[self themeImagePool] addObject:self]; } // 遍历主题图片池(移除应该被回收的对象) for (id object in [self themeImagePool]) { NSInteger retainCount = [[object valueForKey:@"retainCount"] integerValue]; if (retainCount == 2) { // 对象应该被回收了 [[self themeImagePool] removeObject:self]; } }}/** 从主题图片池中移除 */- (void)py_removeFromThemeImagePool{ // 如果对象为_UIAppearance,直接返回 Class appearanceClass = NSClassFromString(@"_UIAppearance"); if ([self isMemberOfClass:appearanceClass]) return; // 判断是否已经在图片池中 if ([[self themeImagePool] containsObject:self]) { // 在主题图片池中 [[self themeImagePool] removeObject:self]; }} |
3. 设置主题图片和相关配色
当设置图片时,会通过block将主题图片池里面的所有控件传递给用户,用户根据需求进行相关设置,如果提供了配色,就会采用上面设置主题色功能来设置主题色
|
1
2
3
4
5
6
|
/** * 重新加载主题图片 * themeColor : 主题色 * block : 设置主题图片时调用的block */- (void)py_reloadThemeImageWithThemeColor:(UIColor *)themeColor setting:(PYThemeImageSettingBlock)block; |
实现如下:
|
1
2
3
4
5
6
7
8
9
10
11
|
/** 重新加载主题图片 */- (void)py_reloadThemeImageWithThemeColor:(UIColor *)themeColor setting:(PYThemeImageSettingBlock)block{ if (themeColor) { // 有主题色,设置主题色 [self py_setThemeColor:themeColor]; } if (block) { // 存在block,直接调用 block([self themeImagePool]); }} |
使用
假设现在有这么一个需求:更换主题图片时,更换UITabBarItem的图片
1.将UITabBarItem添加到图片池
|
1
2
|
// UITabBarItem[childController.tabBarItem py_addToThemeImagePool]; |
2.切换主题图片并设置配色为红色
|
1
2
3
4
|
// 重新加载主题图片,并设置主题色为红色[self py_reloadThemeImageWithThemeColor:[UIColor redColor] setting:^(const NSArray *objects) { // 根据控件类型完成相关设置} |
总结
篇幅可能有点大,能耐心读到这里的读者相信会有不少收获的,希望读者在阅读此教程的时候,千万不要学习代码实现,而是要多思考:为什么要这样实现?那样实现有什么不好?多学学接口为什么要这样设计,那样设计是不是更合理?当你带着这些问题再回过头来去看看源码时,希望你会有更多的收货!当然,这里只是提供了一种思路,你也可以在此基础上实现夜间模式的切换等。期待你们的实现!
期望
当然如果您有更多的想法想表达或者交流的话,欢迎到留言/评论!因为本人比较喜欢活跃在GitHub社区,所以,如果您有什么想反馈的也可以issuse me,在这也鼓励大家去多多发现优秀源码,并且共享给大家。毕竟分享是双方获利的,何乐而不为?
源码地址:https://github.com/iphone5solo/PYTheme
iOS 实现快速切换主题详细教程(附上源码)的更多相关文章
- PHP PC端微信扫码支付【模式二】详细教程-附带源码(转)
博主写这破玩意儿的时候花了大概快两天时间才整体的弄懂逻辑,考虑了一下~还是把所有代码都放出来给大家~抱着开源大无私的精神!谁叫我擅长拍黄片呢?同时也感谢我刚入行时候那些无私帮过我的程序员们! 首先还是 ...
- easyUI整合富文本编辑器KindEditor详细教程(附源码)
原因 在今年4月份的时候写过一篇关于easyui整合UEditor的文章Spring+SpringMVC+MyBatis+easyUI整合优化篇(六)easyUI与富文本编辑器UEditor整合,从那 ...
- 史上最详细的IDEA优雅整合Maven+SSM框架(详细思路+附带源码)
目录 前言: 1. 搭建整合环境 2.Spring框架代码的编写 3.SpringMVC框架代码的编写 4. Spring整合SpringMVC的框架 5.MyBatis框架代码的编写 6. Spri ...
- LIRE教程之源码分析 | LIRE Tutorial of Analysis of the Source Code
LIRE教程之源码分析 |LIRE Tutorial of Analysis of the Source Code 最近在做地理图像识别和检索的研究,发现了一个很好用的框架LIRE,遂研究了一通.网上 ...
- 使用 IDEA 创建 SpringBoot 项目(详细介绍)+ 源码案例实现
使用 IDEA 创建 SpringBoot 项目 一.SpringBoot 案例实现源码 二.SpringBoot 相关配置 1. 快速创建 SpringBoot 项目 1.1 新建项目 1.2 填写 ...
- PHP简单的长文章分页教程 附源码
PHP简单的长文章分页教程 附源码.本文将content.txt里的内容分割成3页,这样浏览起来用户体验很好. 根据分页参数ipage,获取对应文章内容 include('page.class.php ...
- GEF入门实例_总结_01_教程、源码、开发环境准备
一.前言 最近在学Eclipse插件开发,发现了一个比较好的GEF入门教程,并且按照教程上的操作,一步步实现了一个入门Demo,在此感谢作者的贡献. 好记性不如烂笔头,故决定总结一下这段时间的学习心得 ...
- SpringBoot 项目搭建(详细介绍+案例源码)
SpringBoot 项目搭建 SpringBoot 项目整合源码 SpringBoot 项目整合 一.项目准备 1.1 快速创建 SpringBoot 项目 1.2 标准项目结构图如下 1.3 添加 ...
- vim一个快速切换主题的插件(change-colorscheme,原创)
概述 有时候我们想快速浏览主题并找到一款合适的主题,change-colorscheme将会满足我们的要求. 安装 git https://github.com/chxuan/change-color ...
随机推荐
- 导航VC的左右item代码
代码控制左右item: UIButton *btnCancel = [UIButton buttonWithType:UIButtonTypeCustom]; btnCancel.frame= ...
- Linux下oracle11gR2系统安装到数据库建立配置及最后oracle的dmp文件导入一站式操作记录
简介 之前也在linux下安装过oralce,可每次都是迷迷糊糊的,因为大脑一片空白,网上随便看见一个文档就直接复制,最后搞了乱七八糟,虽然装上了,却乱得很,现在记录下来,希望能给其他网上朋友遇到问题 ...
- c# 高效读写文件
一.同步读写文件(在并发情况下不会发生文件被占用异常) static void Main(string[] args) { Parallel.For(0, 10000, e => { strin ...
- Dynamic CRM 2013学习笔记(三十九)流程2 - 业务流程(Business Process Flows)用法详解
业务流程(Business Process Flows)是CRM 2013 里一个新的流程,它提供了可视化的流程表现.业务人员创建有效.流线型的业务流程让最终用户知道当前在哪.下一步要做什么,用户可以 ...
- StarUML建模软件
这星期本人进行了UML建模语言的初步学习,简单地将上学期所建立的数据库模型在该软件中实现了出来.
- 客户端缓存 HTML + 远程数据 JS 的思路。
移动客户端,采用客户端集成 WebBrowser 的方式 ,加载远程网页的优化方案. 1. 远程 HTML版本 v1.2 一次性加载到客户端 2. 手机端打开时,检测HTML版本. 如果有新版,先更新 ...
- Flex开发一周年感悟
优点: 1.Flex上手简单,与html和js很像,是一种web前端语言,对于简单的界面.图表.交互都有不错的封装.它能够让新手在短时间内开发出比较有模样的项目. 2.有很多第三方api可以使用,如a ...
- 清爽绿色格调图文box通用样式
今天是端午节,小菜献上一款剽窃的box样式,祝大家端午快乐! 此box样式以绿色为主要色调,清新自然,适合大多数设计场景. 此box算是比较高级的了,box中的列表是图文列表,可以显示一张小图片,然后 ...
- JQuery高性能优化
使用JQuery时,你可以使用多种选择器,选择同一个元素,各种方法之间的性能是不一样的,有时候差异会特别大. 通常比较常用的选择器有以下几个: ID选择器 $("#id") 标签选 ...
- 酷派大神F2系列使用QPST进行nv备份和恢复,解决无信号问题(附备份文件)
测试机器: 大神F2联通版 8675_W00 系统COOLUI55 写贴原因: 自己无意间刷错了包,结果手机无信号,进入工程模式怎么设置都没有用.尝试过系统还原(备份过).刷新的ROM.线刷, ...