What's the difference between a style and a theme?
A style applies to a View. In XML, you apply a style using the style attribute.
A theme applies to an Activity or an entire app, rather than to an individual View. In XML, you apply a theme using the android:theme attribute.
Any style can be used as a theme. For example, you could apply the CodeFont style as a theme for an Activity, and all the text inside the Activity would use gray monospace font.
再来看一下图片选择器相关的UI开发,顺便梳理一下UI相关的知识点。常用的一些基础东西就不写了,这里只记录一些容易弄混,出错,不容易记住的东西
假设我们想要做成的图片选择器的UI类似于下图这样:
主题
我们希望UI上的元素尽可能的可配置,因此将相关的UI属性抽出来并定义成主题。比如:标题的颜色,文字的颜色,字体等。在开发的时候,还是像知乎那样提供两套基础的主题。一种主题的样式显示效果如上图所示,采用白底的头部。另一种,我们采用蓝底的头部。先回顾一下
Style
和Theme
相关的基础。新增Style
和Theme
的方式是一样的,都是直接在xml文件的<resources>
结点中添加<style>
结点,定义名称,添加属性。那么Style
和Theme
的区别是什么, Google官方是这么说的:Any style can be used as a theme. For example, you could apply the CodeFont style as a theme for an Activity, and all the text inside the Activity would use gray monospace font.
概括来讲,最大的区别是在于
Theme
是可以用在Activity
或整个app。其实有些属性是只能定义在Theme
中的,比如windowActionBar
属性,就只能作为Theme
的属性 当我们在android studio中新建一个module时,工具会自动帮我们生成一个style, 代码如下:默认会创建一个主题,即
Apptheme
,它继承自Theme.AppCompat.Light.DarkActionBar
, 然后自定义了三个属性,colorPrimary
,colorPrimaryDark
,colorAccent
。这三个属性是用来定义应用的基础色调。colorPrimary
: 应用的主色调,actionBar, Toolbar的底色colorPrimaryDark
:应用的主要暗色调,statusBar默认使用的颜色colorAccent
: 控件选中效果的默认颜色android系统提供的属性,可以从这里查看。接下来定义自己的
Theme
。第一步 我们在
attr.xml
中定义相关的属性 相关的属性后面可以结合着代码看第二步 在
styles.xml
中自定义Theme
第三步 在布局文件中使用新定义的属性:
第四步 为Activity或者app指定主题:
沉浸式模式
我们希望用户在使用图片选择器时,进行预览操作, 查看大图时,页面能够隐藏掉状态栏和标题,扩大可视区域。因此需要用到沉浸式模式。
沉浸式模式,也通常有人说是沉浸式导航,immersive 等,但描述的都是同一个东西。沉浸式表现的效果通常有以下种:
来看个Demo, 创建一个Activity, 在其布局文件中
隐藏掉状态栏
隐藏状态栏,我们只需要加对
DecorView
调用setSystemUiVisibility
方法,设置flag为View.SYSTEM_UI_FLAG_FULLSCREEN
。同时隐藏掉actionBar
。代码如下:状态栏透明
让状态栏透明,同时让内容延伸到状态栏的下方。代码如下:
在Android 5.0以后,系统提供了
setStatusBarColor
方法来手动设置statusBar的背景色,此处我们也仅考虑5.0以上的兼容。需要注意的是此处的flag需要用到SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
和SYSTEM_UI_FLAG_LAYOUT_STABLE
这两个。这样才能保证状态栏显示,同时内容也能延伸到状态栏的下方。隐藏底部的导航栏
隐藏底部的导航栏操作一般用得少,通常在视频,游戏类app中要多一些。而且隐藏导航栏的操作通常会有些问题,比如,我们用
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
和View.SYSTEM_UI_FLAG_FULLSCREEN
两个flag, 结果发现,状态栏和导航栏都隐藏了,但是点击一下屏幕又都显示了。只能做一个透明的导航栏,代码如下:视频app中全屏的显示
需要重写
onWindowFocusChanged
方法以上只是沉浸式最常用的操作,在国内android生态碎片化严重的情况下,会出现兼容性的问题,这篇文章中有部份记载,可以参考。 在项目中我引入了
ImmersionBar
来管理statusBar,compile com.gyf.barlibrary:barlibrary:2.3.0
, 如果想详细了解相关的操作可以去看源码。列表的显示
在上方的图中,我们可以看到,有两个列表,一个是相册列表,另一个是图片列表。同时,我们也知道,对于机册的图片的查询,都可以通过利用
CursorLoader
来从Content Provider
中查,查询到的数据都以Cursor
的形式返回,考虑到这点共性,我们可以将相册和图片列表要使用到的Adapter
进行抽象,抽出其共性。我们定义一个父Adapter, 考虑到平时很少将ListView
和Cursor
一起用,回顾一下: 对于ListView, 使用adapter可以屏蔽视图,数据的差异性,让ListView只做好自己份内的事就可以。对于ListView
, android 提供了多种类别的Adapter
供我们使用,如ArrayAdapter
,CursorAdapter
,SimpleAdapter
等。这三个Adapter
都是直接继承自BaseAdapter
,其中的CursorAdapter
是利用游标来返回数据,在需要从数据库中读取数据或者从Content Provider
中读取数据时,使用会比较方便。使用CursorAdapter
时,需要重写newView
和bindView
两个方法, 此处写个Demo回顾一下:如果我们使用
RecyclerView
,都是直接使用RecyclerView
中的Adapter
类,就不像ListView
那样,可以使用CursorAdapter
,但我们可以将Cursor
传递到RecyclerView.Adapter
中去。