mdpi 是1倍图
hdpi 是1.5倍图
xhdpi 是2倍图
xxhdpi 是3倍图
xxxhdpi 是4倍图
drawable-ldrtl-*的之类的资源目录是布局方向的,可以先不看,所以适配的图片都在
drawable-mdpi 、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi
drawable-mdpi 是1倍图
drawable-hdpi 是1.5倍图
drawable-xhdpi 是2倍图
drawable-xxhdpi 是3倍图
drawable-xxxhdpi 是4倍图
drawable资源目录放的都是xml文件,并没有放适配的图片。
可以在文件夹中看这些文件夹中资源的数量:
drawable 含有533项
drawable-mdpi 含有155项
drawable-hdpi 含有152项
drawable-xhdpi 含有155项
drawable-xxhdpi 含有153项
drawable-xxxhdpi 含有102项
drawable-xxxhdpi这个资源目录比较特殊,资源数量比较少,因为这个 资源目录的分辨率比较高,机型比较少,很多资源图片就没有在这个资源目录做适配了。
以 baseline_account_circle_white_24.webp 图片为例:
在drawable-mdpi 、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi 这五个资源目录下的尺寸分别为:2424、3636、4848、7272、96*96,即尺寸大小是1倍、1.5倍、2倍、3倍、4倍的关系。
使用 baseline_account_circle_white_24.webp 这张图片的控件:
是id为contact_field_icon
的这个ImageView:
<ImageView
android:id="@+id/contact_field_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="16dp"
android:tint="@color/grey_600"
tools:src="@drawable/ic_phone_right_unlock_solid_24" />
注意到这个ImageView的宽和高设置的尺寸是:
android:layout_width=“24dp”
android:layout_height=“24dp”
那是怎么适配的?注意ImageView设置图片用的是src属性而不是background属性,ImageView中的background属性会根据ImageView组件设定的长宽进行拉伸图片(即图片适应ImageView的大小),而src属性就存放的是原图的大小,不会进行拉伸ImageView(即ImageView适应图片的大小,图片什么尺寸,ImageView就是什么尺寸)。src是图片内容(前景),background是背景,可以同时使用。
所以最终显示的时候,ImageView是按照读取的图片的尺寸大小进行显示的,而图片的大小已经在drawable-mdpi 、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi 这些资源目录中适配了,所以实现了适配。
再来看ic_arrow_right.webp这张图片:
使用在
<ImageView
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="2dp"
android:src="@drawable/ic_arrow_right"
android:tint="@color/core_white"/>
这个布局控件中。
也在五个资源目录中做了适配,大小分别为2424,3636,4848,7272,96*96
再看一个ic_caption_28.webp图片:
也在五个资源目录中做了适配,大小分别为2828,4242,5656,8484,112*112
再看一个conversation_list_empty_state.webp的图片:
是首页会话列表为空的显示图片,也在五个资源目录中做了适配,ImageView的layout_width和layout_height都是设置为wrap_content
总结下signal的适配方案:
1.ImageView设置图片使用src属性,这样ImageView的大小根据图片的大小进行自适应
2.图片的大小怎么适配?在drawable-mdpi 、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi资源目录中放对应大小的图片,因此需要5套切图
3.利用Android系统的drawable资源寻找规则,找到最符合当前手机屏幕密度的drawable下的图片资源
一般适配的方案总体分为两种:
- 适配ImageView的宽和高。即按照UI稿设置ImageView的宽度和高度,然后设置ImageView的图片时用的是background属性,而不是src属性,这样让图片的大小来自适应ImageView的大小,这种适配方案只需要一套切图即可,一般是用2倍的切图,放在drawable-xhdpi文件夹下,这样遇到屏幕密度比320dpi低的手机时Android系统会压缩图片,遇到屏幕密度比320dpi高的手机时Android系统会放大图片,取中间的320dpi既不会缩小的太多,也不会放大的太多。
- 适配图片的宽和高。即ui切图一般要切5套,分别放在drawable-mdpi 、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi资源目录中,然后Android系统根据当前手机的屏幕密度去取最匹配的文件夹下的图片,然后设置ImageView的图片时用的是src属性,而不是background属性,从而让ImageView的大小自适应图片的大小。
Android屏幕非常多,当然常见的屏幕尺寸比例,比如7201280,10801920,14402560都是16:9=1.78的比例,但是很多屏幕并不是这个比例,比如:
Samsung Galaxy S是480800,比例是5:3=1.67
Samsung Galaxy S8(2017年发布)是14402960,5.8inch,比例是:37:18=2.06
Samsung Galaxy S8+(2017年发布)是14402960,6.2inch,比例是:37:18=2.06
字体的适配
看下首页的这行字 Give your inbox something to write home about. Get started by messaging a friend. 是如何适配的:
是显示在这个TextView:
<TextView
style="@style/Signal.Text.Body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="20dp"
android:gravity="center"
android:text="@string/conversation_list_fragment__give_your_inbox_something_to_write_home_about_get_started_by_messaging_a_friend" />
使用的style是Signal.Text.Body ,看下这个样式:
<style name="Signal.Text.Body" parent="Base.TextAppearance.AppCompat.Body1">
<item name="android:textSize">16sp</item>
<item name="android:lineSpacingExtra">2sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:letterSpacing" tools:ignore="NewApi">0.01</item>
</style>
是固定的16sp
看下在几个设备的页面效果图:
在Pixel XL,5.5inch 1440*2560 560dpi 上的效果图:
在Nexus S,4.0inch 480*800 hdpi(233dpi) 上的效果图:
可以看到页面元素的尺寸比例明显差异比较大。
我们把两者放在一起对比下:
对比查看,可以看到,差异还是非常明显的。跟UI设计同学一起看后,UI同学也表示差异很明显。
颜色的适配
<EmojiTextView
android:id="@+id/conversation_item_body"
style="@style/Signal.Text.Body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginTop="@dimen/message_bubble_top_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_collapsed_footer_padding"
android:ellipsize="end"
android:textColor="?conversation_item_sent_text_primary_color"
android:textColorLink="?conversation_item_sent_text_primary_color"
app:emoji_maxLength="1000"
app:scaleEmojis="true"
tools:text="Mango pickle lorem ipsum" />
可以看到字体的颜色是使用引用的方式来设置颜色的:android:textColor="?conversation_item_sent_text_primary_color"
values/themes.xml文件:
...
<style name="TextSecure.BaseLightTheme" parent="@style/Theme.MaterialComponents.Light.Bridge">
<item name="theme_type">light</item>
<item name="icon_tint">@color/core_grey_75</item>
<item name="icon_tint_dark">@color/core_grey_15</item>
<item name="insight_modal_background">@drawable/insights_modal_background</item>
<item name="insight_modal_button_background">@color/core_grey_10</item>
<item name="insight_title">@color/core_grey_90</item>
<item name="insight_body_2">@color/core_grey_60</item>
<item name="insight_dashboard_bottom_bar_background">@color/core_grey_02</item>
<item name="insight_progress_background">@color/core_grey_15</item>
...
<item name="conversation_item_sent_text_primary_color">@color/core_grey_90</item>
...
<item name="recipient_message_circle_icon">@drawable/ic_message_outline_ultramarine_24</item>
<item name="recipient_call_circle_icon">@drawable/ic_phone_right_outline_ultramarine_24</item>
<item name="recipient_insecure_call_circle_icon">@drawable/ic_phone_right_unlock_outline_ultramarine_24</item>
<item name="recipient_video_call_circle_icon">@drawable/ic_video_outline_ultramarine_24</item>
<item name="recipient_contact_button_color">@color/core_grey_02</item>
</style>
<style name="TextSecure.DarkTheme" parent="@style/TextSecure.BaseDarkTheme">
<!-- leave empty to allow overriding -->
</style>
<style name="TextSecure.BaseDarkTheme" parent="@style/Theme.MaterialComponents.Bridge">
<item name="theme_type">dark</item>
<item name="icon_tint">@color/core_grey_15</item>
<item name="icon_tint_dark">?icon_tint</item>
<item name="insight_modal_background">@drawable/insights_modal_background_dark</item>
<item name="insight_modal_button_background">@color/core_grey_60</item>
<item name="insight_title">@color/core_grey_25</item>
<item name="insight_body_2">@color/core_grey_25</item>
<item name="insight_progress_background">@color/core_grey_60</item>
<item name="insight_dashboard_bottom_bar_background">@color/core_grey_80</item>
...
<item name="conversation_item_sent_text_primary_color">@color/core_grey_05</item>
...
<item name="chipStyle">@style/Signal.Chip.Action</item>
<item name="colorControlNormal">@color/core_white</item>
<item name="circular_progress_button_state">@drawable/progress_button_state_dark</item>
<item name="recipient_message_circle_icon">@drawable/ic_message_solid_ultramarine_light_24</item>
<item name="recipient_call_circle_icon">@drawable/ic_phone_right_solid_ultramarine_light_24</item>
<item name="recipient_insecure_call_circle_icon">@drawable/ic_phone_right_unlock_solid_ultramarine_light_24</item>
<item name="recipient_video_call_circle_icon">@drawable/ic_video_solid_ultramarine_light_24</item>
<item name="recipient_contact_button_color">@color/core_grey_80</item>
</style>
在TextSecure.BaseLightTheme
和 TextSecure.BaseDarkTheme
中都定义了对应的颜色,android:textColor="?conversation_item_sent_text_primary_color"
使用的conversation_item_sent_text_primary_color
颜色也都在其中定义了。