Android View 体系(2):Android UI布局常见问题
2 Android UI布局常见问题
2.0 Android中常用的五种布局:
FrameLayout(帧布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局),每种布局都有自己适合的方式,另外,这五个布局元素可以相互嵌套应用,做出美观的界面。
FrameLayout
从屏幕的左上角开始布局,叠加显示,应用:透明的多层布局。
LinearLayout
从外框上可以理解为一个div,他首先是一个一个从上往下罗列在屏幕上。
每一个LinearLayout里面又可分为垂直布局(android:orientation="vertical")和水平布局(android:orientation="horizontal")。
当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。
AbsoluteLayout
绝对布局犹如div指定了absolute属性,用X,Y坐标来指定元素的位置android:layout_x="20px" android:layout_y="12px"
指定平板机型的游戏开发中经常用到绝对布局 widget 绝对布局,指定机型的平板游戏开发,机顶盒开发。
RelativeLayout
内部元素以某一个元素为参照物,来定位的布局方式。主要属性有:
android:layout_below="@id/aaa" 该元素在 id为aaa的下面
android:layout_toLeftOf="@id/bbb" 改元素的左边是bbb
相对于父元素的地方
android:layout_alignParentLeft="true" 在父元素左对齐
android:layout_alignParentRight="true"在父元素右对齐
TableLayout
表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,
TableRow里面可以具体定义每一个元素,设定他的对齐 方式android:gravity="" 。
2.1 自定义文字居中的标题栏
1. 自定义control_titlebar.xml
control_titlebar.xml的定义如下:
<!--android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" 使返回箭头图标颜色为白色-->
<!--app:elevation="0dp" 去掉AppBarLayout阴影-->
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<!-- app:popupTheme="@style/ThemeOverlay.AppCompat.Light" 使返回箭头图标颜色为白色-->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_sm_height"
android:gravity="center_horizontal"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<!--单行 限制长度 超长省略显示-->
<TextView
android:id="@+id/tv_title"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_centerInParent="true"
android:textAlignment="center"
android:ellipsize="end"
android:gravity="center"
android:maxEms="20"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@android:color/white"
android:textSize="@dimen/textsize_lg" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
2. 在布局文件中使用
<include layout="@layout/control_titlebar"></include>
3. 在AndroidManifest.xml中声明Activity时,使用NoActionBar主题
<activity android:name=".XXXActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|"
android:label="xxx"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
<style name="AppTheme>
<!--这里为自定义主题的相关项......-->
</style>
<style name="AppTheme.NoActionBar" >
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
4. Activity中设置setSupportActionBar为自定义的toolbar
Toolbar toolbar = (Toolbar )findView(R.id.toolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
//去除分割线和阴影,这里同布局中的app:elevation="0dp"
getSupportActionBar().setElevation(0);
//是否显示返回箭头: true 显示,false 不显示
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
如果显示返回箭头,为其添加设置事件监听代码:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == android.R.id.home)
{
// todo 退出前的其他处理
// 退出当前Activity
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
2.2 Activity通过主题设置样式
2.2.1 去除标题栏左侧空白
<!--ToolBar去除左侧空白-->
<style name="MyToolbar" parent="Widget.AppCompat.Toolbar">
<item name="contentInsetStart">0dp</item><!--去除左侧空白-->
</style>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimary</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="toolbarStyle">@style/MyToolbar</item>
<item name="overlapAnchor">false</item> <!--把该属性改为false即可使menu位置位于toolbar之下-->
</style>
2.2.2 设置菜单Menu与标题栏不重叠
如上述在AppTheme样式主题中设置<item name="overlapAnchor">false</item>
parent样式如果有Overflow,如"Widget.AppCompat.ActionBar.Overflow"> 去掉.Overflow
2.2.3 修改MenuItem背景颜色
如果使用类似于微信的黑色主题,主题颜色设为深色后,菜单可能还是白底黑字,希望改为黑底白字。如下在AppTheme中设置菜单样式actionOverflowMenuStyle
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/dark</item>
<item name="colorPrimaryDark">@color/dark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="actionOverflowMenuStyle">@style/optionMenu</item>
</style>
<style name="optionMenu" parent="Widget.AppCompat.ActionBar.Overflow">
<item name="android:popupBackground">@color/dark</item>
</style>
</resources>
另一种方式:
<android.support.v7.widget.Toolbar style="@style/MyTheme.ToolBar"
app:popupTheme="@style/MyTheme.ToolBar.PopupMenu"
android:id="@+id/toolbar"
android:layout_marginBottom="0dp"
app:navigationIcon="?attr/homeAsUpIndicator"
app:layout_collapseMode="pin">
<style name="MyTheme.ToolBar.PopupMenu" parent="@style/ThemeOverlay.AppCompat.Light">
<!-- 是否覆盖锚点,默认为true,即盖住Toolbar -->
<item name="overlapAnchor">false</item>
<item name="android:dropDownWidth">wrap_content</item>
<item name="android:paddingRight">5dp</item>
<!-- 弹出层背景颜色 -->
<item name="android:popupBackground">@color/white</item>
<!-- 设置弹出菜单文字颜色 -->
<item name="android:textColor">@color/black</item>
<!-- 弹出层垂直方向上的偏移,即在竖直方向上距离Toolbar的距离,值为负则会盖住Toolbar -->
<item name="android:dropDownVerticalOffset">1dp</item>
<!-- 弹出层水平方向上的偏移,即距离屏幕左边的距离,负值会导致右边出现空隙 -->
</style>
2.3 Activity代码设置相关样式
2.3.1 设置状态栏、底部导航栏的颜色
/**
* 设置状态栏、底部导航栏的颜色
* @param window
* @param color
*/
public static void setTitleBarColor(Window window, int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setStatusBarColor(color);
window.setNavigationBarColor(color);
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
//与标题栏颜色同
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
else {
//android 4.2以下
}
}
在Activity的Oncreate中,在setContentView()被调用之后调用:
setTitleBarColor(getWindow(), ContextCompat.getColor(this, R.color.colorPrimary));
上述方法有一个bug,状态栏被设置成白色后文字图标不显示的问题,解决方法:
在app的build.gradle中dependencies添加依赖项
compile 'com.githang:status-bar-compat:latest.integration'
在Activity的Oncreate中,在setContentView()被调用之后调用:
setTitleBarColor(getWindow(), Color.WHITE);
StatusBarCompat.setStatusBarColor(this, Color.WHITE);
2.3.2 菜单操作
1. 使用菜单资源
在res下的menu目录下定义菜单资源editmenu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item android:id="@+id/action_add"
android:title="添加"
android:orderInCategory="1"
android:icon="@drawable/add"
app:showAsAction="always"/>
<item android:id="@+id/action_edit"
android:title="编辑"
android:orderInCategory="2"
android:icon="@drawable/edit"
app:showAsAction="always" />
</menu>
使用菜单资源填充菜单:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.editmenu, menu);
super.onCreateOptionsMenu(menu);
return true;
}
处理点击事件:
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == R.id.action_add){
// todo 处理添加业务
return true;
}else if(item.getItemId() == R.id.action_edit) {
// todo 处理编辑业务
return true;
}
return super.onOptionsItemSelected(item);
}
2. 下拉子菜单显示icon
上述方式,在菜单显示为下拉菜单时,图标不显示。可以改用以下方式定义:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:orderInCategory="100"
android:showAsAction="always"
android:title="更多">
<menu>
<item android:id="@+id/action_add"
android:title="添加"
android:orderInCategory="1"
android:icon="@drawable/add"
app:showAsAction="ifRoom|withText"/>
<item android:id="@+id/action_edit"
android:title="编辑"
android:orderInCategory="2"
android:icon="@drawable/edit"
app:showAsAction="ifRoom|withText" />
</menu>
</item>
</menu>
3. 创建一个只显示文字的菜单
<item android:title="下一步"
android:showAsAction="ifRoom|withText" />
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.editmenu, menu);
super.onCreateOptionsMenu(menu);
return true;
}
或者
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem item= menu.add(0,1,0,“下一步”);
item.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM| | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
return true;
}
说明:
1.alaways:这个值会使菜单项一直显示在ActionBar上。
2.ifRoom:如果有足够的空间,这个值会使菜单显示在ActionBar上。
3.never:这个值菜单永远不会出现在ActionBar是。
4.withText:这个值使菜单和它的图标,菜单文本一起显示