13. 网络爬虫之实战
了解正则表达式
经典的正则表达式
1 | # 包含字母的字符串 |
经典的正则表达式
1 | # 包含字母的字符串 |
下图给的是最原始的鸿洋_的方案:
假设现在的 UI 设计图是按照 480 份数 * 320 份数设计的,且上面的宽和高的标识都是px的值,你可以直接将 px 转化为 x[1-320],y[1-480],这样写出的布局基本就可以全分辨率适配了。
会有什么问题?
突然有一天, 我看到在官网看到了这么一段话: 支持多种屏幕 | Android Developers - 声明适用于 Android 3.2 的平板电脑布局
于是有了采用sw修饰符来实现适配的想法. 这就需要采集手头所有设备的分辨率并 dp 化.
手机方面除了目前常用的 360 和 392, 再考虑到一些常见的手机型号的最小宽度 300,320,411,450 这四个也加上为宜.
还需要考虑哪些因素呢, 比如得考虑平板的虚拟按键栏, 所以还得采集具体设备的参数
例如平板 M2 PLE-703L 在横屏状态下为 1920px = 768dp, 但是如果有了虚拟按键, 则只剩下1830px = 732dp
取出最小宽度, 最终得到
手机版的一维数组:320,320,392,411,450"
Pad版的一维数组:480,532,640,698,732,768,800,852,912,960,1024,1280
sw<N>dp
还是 w<N>dp
修饰符由于 sw 取得是最小宽度, 一般情况下采用 sw 基本够用. 如果我们在开发时候要区分横屏或者竖屏, 所以选择 w<N>dp
修饰符更为合适。
320,360,392...
640,698,768...
假如以 1280px * 800px 的设备, 指定 横屏状态 下, 可以将宽度分成了 1280 份数, 然后之取出偶数份(剔除了奇数, 觉得太多余) 1280/2 = 640 份数
1 | # 参考公式 |
生成文件夹形如
1 | ls |
且每个文件夹下都有 precent_width.xml
文件, 以下是 values-w640dp
下的 xml 文件
1 | <?xml version="1.0" encoding="utf-8"?> |
1
2
3
4
<dimen name="x1276">638dp</dimen>
<dimen name="x1278">639dp</dimen>
<dimen name="x1280">640dp</dimen>
</resources>
生成工具(参考了鸿洋_的代码)改编而成
1 | import java.io.BufferedWriter; |
团队有没有专门针对平板设计 UI?
x
系列的 dimen 值, 例如x2
, x4
这种. 如果字体大小没特殊要求, 也建议大家使用 dp
, 如果你真的做了 sp
的适配.1920px*1080px
为基准w<N>dp
只会就近取小于等于的 dimen 值, 但是此方法稳定。由于 Android 碎片化严重,屏幕分辨率千奇百怪,而想要在各种分辨率的设备上显示基本一致的效果,适配成本越来越高。虽然 Android 官方提供了 dp 单位来适配,但其在各种奇怪分辨率下表现却不尽如人意,因此下面探索一种简单且低侵入的适配方式。
通常情况下,一部手机的分辨率是宽x高,屏幕大小是以寸为单位,那么三者的关系是:
以华为 P7 为例,计算其dpi值。先利用勾股定理得其对角线的像素值为 2202.91,再除以对角线的大小 5,即 2202.91/5 = 440.582;此处计算出的 440.58 便是该设备的真实屏幕密度 dpi。
现在我们再通过代码来获取设备的 dpi 值
1 | private void getDisplayInfo(){ |
输出:
1 | density = 3.0 |
发现代码中获取到的densityDpi=480和我们计算出来的屏幕实际密度值440.582不一样。因为在每部手机出厂时都会为该手机设置屏幕密度,若其屏幕的实际密度是440dpi那么就会将其屏幕密度设置为与之接近的 480dpi;如果实际密度为 325dpi 那么就会将其屏幕密度设置为与之接近的320dpi。
这也就是说常见的屏幕密度是与每个显示级别的最大值相对应的,比如:120、160、240、320、480、640 等。顺便说一下,看到代码中的density么?其实它就是一个倍数关系,它表示当前设备的 densityDpi 和 160 的比值,480/160=3 倍关系属于 xxhdpi。从而逻辑分辨率为640dp * 360dp
其实,关于这一点,我们从 Android 源码对于 densityDpi 的注释也可以看到一些端倪:
1 | The screen density expressed as dots-per-inch. |
请注意这里的措辞 ”May be”,它也没有说一定非要是DENSITY_LOW、DENSITY_MEDIUM、 DENSITY_HIGH这些系统常量。 这就 是Android ”碎片化”的一个佐证。
假设我们 UI 设计图是按屏幕宽度为 360dp 来设计的,如果屏幕宽度为 1080/(440/160)=392.7dp,也就是屏幕是比设计图要宽的。这种情况下, 即使使用 dp 也是无法在不同设备上显示为同样效果的。 同时还存在部分设备屏幕宽度不足 360dp,这时就会导致按 360dp 宽度来开发实际显示不全的情况。
资源目录名 。要讲的的很多. 例如可以针对不同的屏幕提供不同的布局,甚至针对 pad 与手机提供两套完全不同的布局样式。
但是通常情况下,设计师并不会对不同屏幕提供不同的设计图,他们的需求仅仅是不同屏幕下控件对屏幕的相对大小一致,直接使用 dp 并不能满足这一点,而对各种屏幕适配一遍又显得略为繁琐,并且修改也较为麻烦。
ConstraintLayout。百分比支持库deprecated之后推荐使用的布局,看起来似乎略复杂。
建立多套分辨率。编写脚本将长度转换成各分辨率下的长度,缺点是难以覆盖市面上的所有分辨率。此处有优化, 可以参考我的另外一篇文章
AutoLayout支持库。该库的想法非常好:对照设计图,使用 px 编写布局,不影响预览;绘制阶段将对应设计图的 px 数值计算转换为当前屏幕下适配的大小;为简化接入,inflate 时自动将各Layout 转换为对应的 AutoLayout,从而不需要在所有的 xml 中更改。但是同时该库也存在扩展性较差。对于每一种 ViewGroup 都要对应编写对应的 AutoLayout进 行扩展,对于各View的每个需要适配的属性都要编写代码进行适配扩展;在 onMeasure 阶段进行数值计算。消耗性能,并且这对于非 LayoutParams 中的属性存在较多不合理之处。
首先来梳理下我们的需求,一般我们设计图都是以固定的尺寸来设计的。比如以分辨率 1920 px * 1080 px
来设计,以 density 为 3 来标注,也就是屏幕其实是 640dp * 360dp。如果我们想在所有设备上显示完全一致,其实是不现实的,因为屏幕高宽比不是固定的,16:9、4:3 甚至其他宽高比层出不穷,宽高比不同,显示完全一致就不可能了。但是通常下,我们只需要以宽或高一个维度去适配,比如我们 Feed 是上下滑动的,只需要保证在所有设备中宽的维度上显示一致即可,再比如一个不支持上下滑动的页面,那么需要保证在高这个维度上都显示一致,尤其不能存在某些设备上显示不全的情况。
因此,总结下大致需求如下:
布局文件中 unit 转换,最终都是调用 TypedValue#applyDimension(int unit, float value, DisplayMetrics metrics) 来进行转换:
1 | public static float applyDimension(int unit, float value, |
各种单位说明:
PT(point)点: 一个专用的印刷单位“点”, 也是一种像素单位
IN: 英寸
MM: 毫米.
根据公式很容易得出 1 IN = 25.4MM = 72PT.
对 DIP 和 SP 下手对于老项目不够友好, 只能选择这三个单位. 又会发现这三个单位转换得到像素值的时候都会与metrics.xdpi
有关
xdpi: The exact physical pixels per inch of the screen in the X dimension.
其实说白了就是 X 横轴方向的 dpi。
一般给的图都是以像素为单位的. 例如1920*1080 5寸屏的我们如果有1pt = 1px. 则如果需要120px的宽度, 我们不用想写成 120pt 就 OK了。
1 | 要求得的 1pt 实际对应的 px / 屏幕宽度px = 1px / 设计图宽度px |
当前情况下容易得出 xdpi = 72
, 我们还是算出原来的xdpi 为 440, 也就是大概差了 6 倍.如果假设 1pt = 1px, 在使用过程中发现 1pt 变现为 6px, 也就是突然变大了, 你就知道pt失效导致的.自己去找原因并解决.
1 | final Point size = new Point(); |
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, value, metrics)
这是因为有一个已知条件
1pt = 1px
则等价于xdpi = 72
因为1334px * 750px
, 则对角线px = 1530.3px = 1530.3pt = 21.25 inch
如果采用1920px*1080px
的屏幕同理啦.
该方案由于不是自己原创, 我偷偷贴个代码, 没人发现吧
1 | package xxx.yyy.zzz; |
若存在webview导致适配失效的问题
可以先继承 WebView 并重写setOverScrollMode(int mode)
方法,在方法中调用super之后调用一遍ScreenHelper.resetDensity(getContext(), designWidth)
规避
若存在dialog中适配失效的问题
可以在 dialog 的 oncreate 中调用一遍ScreenHelper.resetDensity(getContext(), designWidth)
规避
旋转屏幕之后适配失效
可以在 onConfigurationChanged 中调用ScreenHelper .resetDensity(getContext(), designWidth)
规避
特定国产机型 ROM 中偶先 fragment 失效
可以在 fragment 的 onCreateView中调用 ScreenHelper .resetDensity(getContext(), designWidth)
规避
1920px*1080px
16:9 的屏幕,一般而言可以做到手机和Pad通吃,如果你们公司遵循"更大的屏幕显示更多的内容", 可以和美工协商规划.备用
FadeTop 只适合 win 7 稍微有点颜值吧
not
Eyes Relax (仅适用于 Win) 已经不跟新了。 一款专业的定时提醒休息保护视力软件,用户可以设置休息时间到规定的时间便会弹出休息提醒,支持定时提醒的时长和次数设置,还可根据自己的喜好设置屏保,防止视觉疲劳,保护眼睛。
f.lux 介绍
Microsoft Store 商店版 f.lux 全天候保护眼睛健康软件