如何写UI及屏幕适配的一些技巧
总结一下关于UI布局及屏幕适配的一些实战技巧,尤其使用纯代码,会对提升效率及代码易于维护等方面有明显帮助,这里提到的没有使用任何Xib, 如果不是在外包公司,也推荐大家多使用甚至完全使用纯代码布局UI,优缺点下面会说明,本文布局使用masonry。
提纲:
1. 关于xib/storyboard 与 纯代码的对比
2. 一条规范(又提了一点关于命名的)
3. UI工厂类 与 代码块
4. 懒加载, View使用strong还是weak
5. 复杂界面要会分区,要会障眼法
6. masonry均布View,及其布局时约束依赖关系
7. 关于屏幕适配的一点技巧
1. 关于xib/storyboard 与 纯代码的对比
a、 xib快,纯代码慢,但是在纯代码熟练的情况下, 并不会慢很多;
b、 xib不易于修改,怎么修改,就是今天让一个View上的元素这么排布,明天就要换种排布方式,后天又要加些东西。。。;
c、 xib不灵活,什么叫灵活,一个View上有10个元素, 其中5个都是不一定出现的,并且它们不是集中的布局在哪个位置, 乱七八糟的,多一个少一个布局还都有点影响,这就知道灵活的重要性了;
d.、xib不利于屏幕适配,怎么适配,5s上一个View距左10像素,产品说6p上就要距左20才协调,xib上拖线布局怎么搞,约束拖出来改变它吗,复杂View有10个需要这样处理的地方呢。。。
e、 xib写多了纯代码手生,当然纯代码写多了,拖线也有点不熟练,这个不作为纯代码更好的原因。。。
f、但是!面试的时候如果你说我xib用的多,纯代码布局有点不熟练, 不好意思, 拜拜(本人经历过),你说我都是纯代码布局的, xib会,不熟,大多公司听到以前都是纯代码,那没问题,因为他们公司也不用xib。。。
2. 一条规范(又提了一点关于命名的)
“ .h 和 .m 的类扩展里面不要随便加东西,尤其 .h 里的东西一定要是必须放在这里,放在别处不行,实在有不太重要还必须放在这的,打好注释 ”
这个东西无数次在项目中见到过随意在这加东西的做法, 刚写完当时还好, 一个月以后再看, 瞬间懵逼。。。
这是什么鬼。。。
当时为啥要写这个量。。。
这怎么还有个没用过的量。。。
这个东西要不要传, 为啥A类用的时候穿了, B类就不传了。。。
再提一下另外一个规范, “名字不要随便起,弄个坑爹名字,自己隔天都不知道啥意思,是跟公司结了仇了还是怕泄露天机”
不算特别不规范的命名
为什么说这些命名不是特别不规范, 因为这里面虽然有些vBack啦, lbl啦, tbl啦, 不是那么容易理解, 但是好歹是lbl,都用lbl了,不过为啥非得把Label放前面,官方命名的时候比如btn.titleLabel,Label也是放在后面的啊, 也没缩写成什么lbl,我们就简简单单的叫nickNameLabel不行吗。。。
说到命名就再多说一点, 如果一个复杂View内部布局的时候需要分割成几部分,在能想出名字的情况下最好不要按位置命名,比如topView,midView之类,明天产品说把位置调一下,最下面的部分比较重要提到最上面,这怎么办, 尽量想一想这部分大概负责什么,要表达个什么意思
3. UI工厂类与代码块
UI工厂类: 其实代码很简单,就是把对Label, Button等控件的属性赋值封装一下, 做到一行代码就能创建一个View, 如下图, 虽然这一句代码有点长, 但是习惯之后写个View是真心快。
UI工厂类.h
UI工厂类.m
代码块: 代码块就是下图的东西。
代码块
这个东西不光是UI布局用, 很多位置都比较方便, 我常用的有这样几个
懒加载
masonry定义过的一部分
masonry填空模式
尤其是纯代码masonry布局, 这样的代码块会让你布局的速度直逼甚至超越拖线, 只需要打出make就会出现已经定义好的各种约束, 比如要布局高度, 打出makeh, 回车, 就直接进入填空模式,tab切换填空即可
4. 懒加载, View使用strong还是weak
为什么要用懒加载, 有一种说法是用到的时候在创建,节省内存开销,这种说法固然没问题,但是对于大部分UI来说,基本迟早都会被创建。
所以,主要优点不在这里,本着的做人原则,代码也该这样写,你既然是个View,那你就把自己解决好再来见我, 我要用你的时候只需要self.testView就可以了,下面两张图对比一下就会看到区别了,第二张为刚到公司时上一任的大作,这里选取了一种比较看的清的贴出来
弱引用懒加载 masonry布局
上图注意:masonry的block没有进行copy,即当前对象没有引用这个block,是局部的引用,不会形成循环引用的,可以不用weakSelf
混乱的还好的示例
对比一下即可看出来, 由于上图使用中的控件均使用懒加载, 所以布局方法里连addSubView都不用写了, 只需逐条布局即可, 下图中创建控件, 属性赋值, 添加到父视图的代码都混在一起, 并且还没有使用masonry, 用上之后只会更乱。。。
View使用strong还是weak: 关于这个问题,其实还是有很多可以说一下的地方
懒加载写法:
@interface ViewController () @property (nonatomic, weak) UIView *weakView;
@property (nonatomic, strong) UIView *strongView; @end @implementation ViewController /**
UI控件使用弱引用创建方法
1. UIView *weakView = [[UIView alloc] init]; 这句必须声明一个局部变量, 不能用_weakView,
因为用 _weakView = [[UIView alloc] init], 等号右侧创建了一个View之后,给了一个弱引用持有,相当于没有持有,直接就释放掉了
而 UIView *weakView = [[UIView alloc] init],等号左侧的weakView默认是一个强引用,会暂时持有保住它,但是生命周期就在这个懒加载的大括号内,所有会有其他代码配合, 使这个View存活下来, 不被释放 2. _weakView = weakView; 这句代码为属性赋值, 以后在其他位置不管通过self.weakView还是_weakView才能找到这个View,
基本作用可以说等同于强引用的 _strongView = [[UIView alloc] init]; 3. [self.view addSubview:weakView], 第一条注释中说了,UIView *weakView 的生命周期就是在这个{}内,那么如何保证出了括号依旧存在,就是要给这个View加到一个不会被释放的View(不一定强引用弱引用)上,即self.view, 这样就不会被释放掉了
*/
- (UIView *)weakView {
if (!_weakView) {
UIView *weakView = [[UIView alloc] init];
_weakView = weakView; weakView.backgroundColor = [UIColor redColor]; [self.view addSubview:weakView];
}
return _weakView;
} - (UIView *)strongView {
if (!_strongView) {
_strongView = [[UIView alloc] init];
_strongView.backgroundColor = [UIColor greenColor];
}
return _strongView;
}
布局时区别:
- (void)configView { WeakSelf(ws); //弱引用由于懒加载直接加到父视图上,所以点语法完了直接调用masonry布局方法即可
[self.weakView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(ws.view);
make.top.equalTo(ws.view).offset();
make.size.mas_equalTo(CGSizeMake(, ));
}]; [self.view addSubview:self.strongView];
[self.strongView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(ws.view);
make.bottom.equalTo(ws.view).offset(-);
make.size.mas_equalTo(CGSizeMake(, ));
}];
}
移除之后的区别(重点,涉及到理解强弱指针):执行上述代码后,屏幕上出现一上一下两个View, 点击空白区域, 移除掉两个View, 1秒后看一下,1秒后看是因为, 出了这个方法, 也就是运行到结束的括号之后, 才会把View移除掉, 注意看坐下控制台两个View,weakView为nil, 即已被释放, strongView还是存在, 因为即使从父视图上移除, self本身对其还有一个强引用, 不会释放掉,那么如果想把这个View释放掉需要怎么办, 就是在[_strongView removeFromSuperview]后面加一句_strongView = nil;
注意weakView为nil,strongView还存在
强指针View置空
下面图解一下, 为什么不置空, strongView就不被释放
强弱指针View实际区别
总结起来的话, 其实如果理解到位,使用强弱都没有问题,但是一般来说,由于弱引用会被及时的释放掉,所以需求允许的话,一般建议使用弱引用,那什么情况不能使用弱引用呢,这个要看具体需求,举个例子,如果一个View,需要从父View移除掉,但是之后还有可能加回来,还要保持移除之前的样子,这种情况强引用会更适合。
收集了一些意见:
懒加载不一定一定要, 这是完全没问题的,有人习惯把创建View,属性赋值,添加到父视图的代码写在一起,认为这样便于管理,顺着看更清晰,没问题。
如果View层次复杂,用懒加载弱引用View的时候注意层级关系,如果理解不到位,容易产生问题,因为addSubView写在懒加载里,极易造成层次不清晰,这时就要个人理解,用自己认为最适合的方法了。
我为什么喜欢将UI写成懒加载?aView就是aView,bLabel就是bLabel,每个控件做好自己事情,给自己颜色字号都弄好了,等我要用你的时候,比如要往父视图添加了,拿来直接加就好,所以在添加View这个方法里都是添加,无关代码没有,要修改aView背景色,去找aView(aView的懒加载里面改)啊
上篇发出之后收集了一些反馈, 总结起来以下几点:
没有demo,代码没有全部粘上来。
我认为这篇的内容不需要,不能我写个弱引用的懒加载怎么写,还一定要把声明weak属性的代码放上来吧。
关于xib/strotyboard和纯代码
我是两种用过,实际工作中也基本都达到了熟练的程度,现在使用纯代码也不是公司要求,自己觉得更好,其他的就不说了,这就相当于两条路都行的通,任意一条走成老司机了另一条也没问题,但是新人工作中最好纯代码为主。
关于懒加载是否一定要
理解到位想怎么搞怎么搞,萝卜青菜各有所爱。
提纲:上篇说到第4条
1. 关于xib/storyboard 与 纯代码的对比
2. 一条规范(又提了一点关于命名的)
3. UI工厂类 与 代码块
4. 懒加载, View使用strong还是weak
5. 复杂界面要会分区,要会障眼法
6. masonry均布View,及其布局时约束依赖关系
7. 关于屏幕适配的一点技巧
8. 循环引用(上篇文章有人对循环引用不理解,虽然是基础,有人不理解还是说一下吧)
5. 复杂界面要会分区,要会用障眼法
分区:什么叫分区,其实就是封装,干啥其实都是一样,UI网络逻辑思路有相同的地方,就包括收拾东西,为啥很多人喜欢把各种东西用各种盒子装起来,假设现在要写一个aView,上面是这样的
一个View上的元素
这个要怎么写, 直接挨个创建直接往aView上加吗, 这以后维护起来改点东西相信你死的心都会有的,一般这种元素有点多的都要适当的分一下区
分区后
这样分区后,如图所示,写UI的时候就先依次单独解决好上中下三部分,然后需要做的就是对上中下三部分的整体进行布局,这一级布局的时候就完全可以忽略他们内部的东西是什么样的,全部完成整体微调,该调里面就里面, 该调整体就整体
障眼法: 所谓障眼法就是投机取巧,当然可以有各种各样的方法,把一些复杂功能简化,不管用了什么方法,最终看起来像是实现了就可以。
下面举个例子, 这个例子是项目中的一个界面, 我简化了一下抽出来, 这是一个消费记录的界面, 有个tableview,每个cell如下所示,可以展开收起
展开状态
收起状态
看到这样一个界面,首先不要考虑如何展开收起,就看一下展开的要怎么写,(演示Demo中的UI因为没有使用网络数据,也为了演示方便,做了简化,实际账单消费下面还有一部分如何消费,可获得什么等等的区域),参照上一条,这种一个View里元素较多的时候可以先分区如下:
按功能或者位置分区如图
先假设展开状态已经写好了,下面要考虑如何收起,观察UI发现收起状态的信息是展开状态中的主要信息, 如图元素其实表达的是同样信息
那么难道要打破布局,将这几个view找到重新布局,其他的隐藏掉吗?那再点击回到展开状态怎么办,在重新布局?想想就麻烦
所以,这时再搞一个summaryView,负责收起的信息展示,这个View内部的时间桌号等控件,跟展开状态的时间桌号虽然长的一样,但是实际是两个不同的UI对象。
所以完成之后,这个View里会有如下几大块
summaryView (收起的View)
expendBgView(展开时的整体View)
topView (这样命名不好)
midView
如此布局,在点击了View要展开/收起的时候,只需要转换summaryView和expendBgView的隐藏状态,改变一下最外层View的底部约束即可
demo地址:https://github.com/CoderLXWang/LayoutViewDemo
6. masonry均布View,及其布局时约束依赖关系
均布View: 等间距布局 – 从0开始说一下masonry的使用
约束依赖关系:这个标题其实比较宽泛,也说不好,如何写约束本身就是比较灵活的,每个人的写法可能都不一样,下面举两个例子大概说一下,
示例1:
这个很简单, 左右间距都是30,第二三四行View的左右约束该怎么写,都写下面的吗?这样写如果要改这个30,就瞎了
make.left.equalTo(父视图).offset();
make.right.equalTo(父视图).offset(-);
因为这里的设计就是左右都要对其,所以下面都都依靠第一个布局即可,第二行两个不是左右都对其
make.left.right.equalTo(父视图).offset(第一个View);
代码少了一行是其次,主要是改的话只改一个,也可以透过代码看到这个地方的设计
注:这个示例很简单,勿喷,主要说这种做法,复杂布局也需要考虑到底依靠那个View布局,具体体况多体会,简单说就是要选取合适的依赖对象
示例2:
需求:
1.整体居中
2.宽度可变,看文字是否够一行,最宽左右内边距10
3.内部两个View的centerY对其
4.最小高度为图片高度,文字高度超度图片,就以文字高度为准
直接上代码,只为说明约束,不要找别的毛病,具体自己看吧,这里Label和ImageView一定要作为一个整体(即放到同一个父视图中),内部因为图片相对固定,左右尺寸都不变,要先布局图片才可以,否则Label没有可以依赖的东西
@interface ViewController () @property (nonatomic, strong) UIView *containerView; @end @implementation ViewController - (UIView *)containerView {
if (!_containerView) {
_containerView = [[UIView alloc] init];
_containerView.backgroundColor = [UIColor orangeColor]; UIImageView *imgView = [[UIImageView alloc] init];
imgView.image = [UIImage imageNamed:@"demo1.jpeg"];
[_containerView addSubview:imgView];
[imgView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(_containerView).offset();
make.size.mas_equalTo(CGSizeMake(, ));
make.centerY.equalTo(_containerView);
}]; UILabel *label = [[UILabel alloc] init];
label.numberOfLines = ;
label.text = @"这是阿三冲击红进口付出dsk红进口付出ds口付出dsk红进口付出dskjfhks口付kjfhks口付出dskj红进口付出dskjfhks口付出dskjjfhks口付出dskjfhd付出dsk红进口付出ds口付出dsk红进口付出dskjfhks口付kjfhks口付出dskj红进口付出dskjfhks口付出dskjjfhks口付出dskjfhdjfhdksjhfdk";
[_containerView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(imgView.mas_left).offset(-);
make.left.equalTo(_containerView).offset();
make.bottom.top.equalTo(_containerView).offset();
make.height.mas_greaterThanOrEqualTo();
}];
}
return _containerView;
} - (void)viewDidLoad {
[super viewDidLoad]; [self.view addSubview:self.containerView];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).offset();
make.centerX.equalTo(self.view);
make.width.mas_lessThanOrEqualTo([UIScreen mainScreen].bounds.size.width-);
}];
}
7. 关于屏幕适配的一点技巧
首先说一个屏幕适配到底是什么, 工作中很多人,甚至产品都搞错了
所谓屏幕适配,并不是大屏就要将UI变大,而是要显示更多的内容。
再说一个关于按钮的写UI原则
按钮设计的大没啥可说,如果设计的按钮很小,到程序员手里一定要让它看起来小,点起来大
KRATE :当然在这一基本原则下,有的时候大屏上的某些元素和小屏保持同样大小会有一些难看,这时还是要分别对待,如果以5s屏幕尺寸为基准(也有用6的尺寸做基准的,都一样,习惯问题),这里一般会定义这样一个宏
#define KRATE (SCREEN_WIDTH/320.0)
举个例子
5s效果
不做比例的适配,在6p上如图
其实也没啥问题,看起来也没有很不协调的地方,但是注意看一下券左右两条竖直虚线,会发现大屏上左面券命和右面打印的宽度会比较小,中间区域显得过大,应该稍微匀一点给左右两边,两边看起来会不那么挤,同时右侧点击范围也会相应放大,做法就是将左右约束的值*KRATE
[self.leftLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.bgView).offset(*KRATE);
make.top.equalTo(self.bgView).offset();
make.bottom.equalTo(self.bgView).offset(-);
make.width.mas_equalTo();
}]; [self.rightLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.bgView).offset(-*KRATE);
make.top.bottom.equalTo(self.bgView).offset();
make.width.mas_equalTo();
}];
乘上比例之后,效果如图
为什么会有这种问题产生, 其实也是由于个人的布局习惯引起的,在布局这个UI时,我是先将左右两条虚线定位好,内部的东西根据虚线的位置确定,而虚线的位置就是一块白色背景左右给定值布局的,所以换到大屏会左右宽度不变,这种情况乘个KRATE就可以了。
麻烦有些人不要来喷啥你写就不会有这个问题,按比例分区怎样的,那是你的方法,你要是按比例分区不也要想到底给0.几的比例吗,要是竖直方向在scollView里也有这个问题呢
KKRATE:因为KRATE是用不同屏幕的宽度算出的一个系数,假设某个宽度5s上宽度为10,KRATE后6上则为10375/320=11.7, 也就是屏幕大1号之后原本为10的宽度增大了1.7, 那么这个宽度如果是40呢,40*374/320 = 46.9。
为了解决小宽度 ×KRATE基本没效果或者宽度大 ×KRATE 又过分了的问题,又定义了这样一个宏,给KRATE在乘一个自己制定的系数,感觉没效果就给KKRATE传个大于1的系数,感觉过分了就KKRATE(0.95),这里注意传入的系数小于0.86就反而大屏UI更小了,这里不想在里面继续写个三目运算符判断了,就这样了
/** 在屏幕比例基础上再次比例, 大于0.86, 否则反而变小 */
#define KKRATE(rate) (KRATE > 1 ? KRATE*rate : KRATE)
拿一个界面举个例子,如图
5s效果
这里左右看起来窄窄的间距用的都是6dp,6dp如果直接*KRATE基本没用,乘完也就加一个dp,效果基本就是如下,屏幕很大,间距很小气,也许你会说小屏上也小气,设计说了,你不懂,正好
如果将各处左右间距设置为
make.left.equalTo(ws.view).offset(*KKRATE(1.8));
make.right.equalTo(ws.view).offset(-*KKRATE(1.8));
效果如下
*KKRATE后6P效果
明显大气了许多。。。
8. 循环引用(上篇文章有人对循环引用不理解,虽然是基础,有人不理解还是说一下吧)
这部分是计划外的,因为上篇有不少同学问起这个东西,发现不少人对看似简单的循环引用概念还是比较模糊,所以我就拿出来说一下,我会分别解释一下常见的循环引用,以及代理,block中的循环引用问题,这里只做理解解释,没有深入研究,大神直接略过吧。
先说一下内存管理,大家都知道内存管理在MRC下要手动写retain,release等代码,操作一个对象的引用计数,以此控制对象持有及释放,ARC下编译器会自动添加retain/release等代码,ARC的一个基本规则就是,只要某个对象被任一strong指针指向,那么它将不会被销毁。如果对象没有被任何strong指针指向,那么就将被销毁。
所以当前我们的代码基本都是ARC,当我们研究一个对象是否循环引用时,也就不考去考虑计数到底为几,什么时候retain,什么时候release,我们只需要按照ARC的基本原则关心指向这个对象的strong指针。
下面就按这个基本原则解释一下循环引用,观察是否释放在控制器打印dealloc方法即可
示例1:简单粗暴无逻辑演示
有一个控制器SampleRetainCycleController *retainVC,retainVC.view上面有个SampleRetainCycleView *testView,testView有个强引用指针,指向retainVC,看起来貌似循环成一个圈了,这就是循环引用吗?貌似怪怪的,因为少了一个引用
简单的循环引用?
实际上少了一个引用关系,没有考虑retainVC是那里来的,retainVC被创建之后加载nav导航栈里是被navController强引用的,这是我们就可以按ARC的原则分析了,就是看线,找实线,这里我们关心的是控制器会不会被正常释放,那我们就看控制器有几根实线,这时就会发现有两根,pop出去的时候,上面的那条nav的线断了,但是还有一条View的线,所以控制器就不会被释放
实际循环引用图示1
示例2:代理为什么用weak声明
如图就是代理为什么用弱引用,如果用强引用就变成示例1的情况了
代理用弱引用原因
示例3:一般使用block为什么注意循环引用,使用weakSelf
先说为什么block一定要用copy,既然会循环引用,那么就像代理一样,使用弱引用的指针不行吗?
详细看这篇文章吧 Block为什么使用copy修饰,
更详细可以看这篇谈Objective-C block的实现
总结起来就是为了使其存放在堆中,如果不copy一下,block是存放在栈中的,出了创建它的作用域,就可能被释放掉,但是用了copy,对这个block就是强引用,所以需要注意循环引用,使用weakSelf。
那什么是weakSelf,block默认对内部引用的外部变量是强引用,所以如果直接使用了self,则相当于block有一条实线(强指针)指向self,则self又有两条实线了
block为什么需要weakSelf
示例4:什么样的block不会造成循环引用
最常见的就是系统的一些block与masonry,系统的比如:
[UIView animateWithDuration: animations:^{ }];
首先是self(假设是当前的控制器)并没有copy(强引用)这个block,其次这还是个类方法,类方法里不能对属性进行复制,即也不能强引用这个block,所以直接用self(即block对self强引用)也不会形成循环引用
再比如masonry
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) { }];
看一下mas_makeConstraints是怎么写的
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
只有第三行执行了一下这个block,并没有任何引用的代码(即类似self.xxblock = block),所以根据上面的几篇文章,这种block是存放在栈上的,出了作用域(即这个方法)就会被释放掉,既然block都被释放掉了,自然不会循环引用。
demo地址:https://github.com/CoderLXWang/RetainCycleDemo
如何写UI及屏幕适配的一些技巧的更多相关文章
- 关于如何写UI及屏幕适配的一些技巧
因为公司开启了一个新的iOS项目, 所以近期比较忙, 没有更新博客,今天打算总结一下关于UI布局及屏幕适配的一些实战技巧,尤其使用纯代码,会对提升效率及代码易于维护等方面有明显帮助,这里提到的没有使用 ...
- iOS开发——UI基础-屏幕适配
一.适配 1.什么是适配?适应.兼容各种不同的情况 2.移动开发中,适配的常见种类 2.1系统适配 针对不同版本的操作系统进行适配 2.2屏幕适配 针对不同大小的屏幕尺寸进行适配 二.点和像素 1.在 ...
- Android屏幕适配技巧
屏幕适配一直是困扰 Android 开发工程师的一大问题,但是随着近几年各种屏幕适配方案的诞生,以及谷歌各种适配控件的推出,屏幕适配也显得越来越容易,这节课我们就来总结一下关于屏幕适配的那些技巧. C ...
- android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事
1.1 手机常见分辨率: 4:3VGA 640*480 (Video Graphics Array)QVGA 320*240 (Quarter VGA)HVGA 480*320 (Half ...
- 给你一个全自动的屏幕适配方案(基于SW方案)!—— 解放你和UI的双手
Calces系列相关文章:Calces自动实现Android组件化模块构建 前言 屏幕适配一直是移动端开发热议的问题,但是适配方案往往在实际开发的时候会和UI提供的设计稿冲突.本文主要是基于官方推荐的 ...
- Laya的屏幕适配,UI组件适配
参考: 屏幕适配API概述 版本2.1.1.1 目录 一 适配模式 二 UI组件适配 一 适配模式 基本和白鹭的适配模式一样. Laya官方也推荐了竖屏使用fiexedwidth,横屏使用fixedh ...
- 了解真实的『REM』手机屏幕适配
rem 作为一个低调的长度单位,由于手机端网页的兴起,在屏幕适配中得到重用.使用 rem 前端开发者可以很方便的在各种屏幕尺寸下,通过等比缩放的方式达到设计图要求的效果. rem 的官方定义『The ...
- Android 尺寸单位转换和屏幕适配相关
Android 尺寸单位转换和屏幕适配相关 各种尺寸单位的意义 dp: Density-independent Pixels 一个抽象的单元,基于屏幕的物理密度. (dp和dip的意义相同,所以不用区 ...
- 【收藏】Android屏幕适配全攻略(最权威的Google官方适配指导)
来源:http://blog.csdn.net/zhaokaiqiang1992 更多:Android AutoLayout全新的适配方式, 堪称适配终结者 Android的屏幕适配一直以来都在折磨着 ...
随机推荐
- 怎样修改SQL Server 2005/2008的系统存储过程(转)
我们知道,SQL Server 2005/2008的系统存储过程在正常情况下是无法直接修改的. 尽管本文是介绍怎样修改它的,但在这里,我还是建议大家尽量不要去修改它.(好像有点绕哈...) OK,闲话 ...
- TCP/UDP常见端口
著名端口 端口号码 / 层 名称 注释 1 tcpmux TCP 端口服务多路复用 5 rje 远程作业入口 7 echo Echo 服务 9 discard 用于连接测试的空服务 11 systat ...
- ORA-16038: log 3 sequence# 103 cannot be archived
[size=large]今天在自己机器做了个实验,插入10万条,由于空间少,重启数据库时出现: [size=x-large]SQL> startup ORACLE instance starte ...
- Android ListView 和 ***Adapter 从本地/网络获取歌曲列表
本文内容 环境 项目结构 测试数据 演示 1:SimpleAdapter 演示 2:BaseAdapter 演示 3:CustomLazyList 演示 4:CustomLazyCompleteLis ...
- Discuz常见小问题-如何取消帖子置顶
定位到一个帖子,然后顶部会有置顶的选项,还是勾选置顶,后面下拉列表选择无,然后点击确定,提示解除置顶
- 【iOS地图开发】巧妙打造中英文全球地图
地图开发的同学们经常遇到这样的问题,国内版地图开发,用高德或者百度就行了.但是,国外的地图怎么办?这里告诉大家,如果利用iOS地图,打造中英文的,国内国外都能用的,全球地图. 制作全英文地图的展示并不 ...
- python网络爬虫 - 如何伪装逃过反爬虫程序
有的时候,我们本来写得好好的爬虫代码,之前还运行得Ok, 一下子突然报错了. 报错信息如下: Http 800 Internal internet error 这是因为你的对象网站设置了反爬虫程序,如 ...
- ZH奶酪:PHP (爬虫)下载图片
原文地址:http://www.phpfensi.com/php/20140107/1128.html 通过图片地地址把图片保存到本址,这里我们直接通过readfile读取然后通过fopen保存即可, ...
- Internet传输协议-TCP
http://phei.eefocus.com/book/08-07/473781276058574.html http://www.eefocus.com/communication/210643 ...
- 世纪互联提供的关于Powershell中将虚拟机加入备份保管库的方法
请您参考以下步骤进行操作,如有问题请与我们联系: 对一台ARM虚拟机(虚拟机名称:paularm08r21)进行备份(参考:https://www.azure.cn/documentation/art ...