UI进阶
Fragment
Android从3.0开始引入Fragment(碎片)
允许将Activity拆分成多个完全独立封装的可重用的组件
为不同型号、尺寸、分辨率的设备提供统一的UI设计方案
自定义的Fragment必须继承Fragment类或其子类
创建Fragment
通常在创建Fragment时,需要实现三个方法∶
onCreate()
onCreateView()
onPause()
将Fragment加载到Activity中主要有两种方式∶
把Fragment添加到Activity的布局文件中
在Activity的代码中动态添加Fragment
管理Fragment
通过FragmentManager实现管理Fragment对象的管理
通过getFragmentManager()获取FragmentManager对象
FragmentManager能够完成以下三方面的操作︰
通过findFragmentByld()或findFragmentByTag()方法,来获取Activity中已存在的Fragment对象
通过popBackStack()方法将Fragment从Activity的后退栈中弹出
通过addOnBackStackChangedListerner()方法来注册一个侦听器以监视后退栈的变化
获取FragmentTransaction对象
FragmentManager fragmentManager=getFragmentManager ( ) ;
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
FragmentTransaction被称作Fragment事务,与数据库事务类似,Fragment事务代表了Activity对Fragment执行的多个改变操作。
事务中动作的执行顺序可以随意,但需注意以下两点:
程序的最后必须调用commit()方法
程序中添加了多个Fragment对象,显示的顺序跟添加顺序一致
当删除Fragment对象时,在没有调用addToBackStack()方法情况下,Fragment对象会被销毁
调用commit(O后,事务并不会马上提交,而是会在Activity的UI线程中等待直到线程能执行的时候才执行。
与Activity通讯
Fragment获取其所在的Activity中的组件
View listview=getActivity ( ).findViewById(R.id.list);
Activity获取指定Frament实例
ExampleFragment fragment = (ExampleFragment)getFragmentManager().findFragmentById(R.id.example_fragment)
在Fragment中定义回调接口
public static class FragmentA extends ListFragment {
//Activity必须实现下面的接口
public interface OnNewsSelectedListener {
//传递当前被选中的标题的id
public void onNewsSelected ( long id) ;
}
}
Fragment与Activity共享事件
public static class FragmentA extends ListFragment {
OnNewsSelectedListener mListener;
//.. ....省略
@override
public void onListItemClick(Listview l,View v,int position,long id){
mListener.onNewsselected (id);
}
//......省略
}
在数据传递时,也可以直接把数据从FragmentA传递给FragmentB,不过该方式降低了Fragment的可重用的能力。现在的处理方式只需要把发生的事件告诉宿主,由宿主决定如何处置,以便Fragment的重用性更好。
Fragment的生命周期
Fragment的生命周期具有以下四个状态:
活动状态
暂停状态
停止状态
销毁状态
Fragment生命周期中的方法
方法功能描述onAttach()当一个Fragment对象关联到一个Activity时被调用onCreate()初始化创建Fragment对象时被调用onCreateView()当Activity获得Fragment的布局时调用此方法onActivityCreated()当Activity对象完成自己的onCreate()方法时调用onStart()Fragment对象在UI界面可见时调用onResume()Fragment对象的UI可以与用户交互时调用onPause()由Activity对象转为onPause状态时调用onStop()有组件完全遮挡,或者宿主Activity对象转为onStop状态时调用onDestroyView()Fragment对象清理View资源时调用,即移除Fragment中的视图onDestroy()Fragment对象完成对象清理View资源时调用onetach()当Fragment被从Activity中删掉时被调用
Fragment和Activity两者之间生命周期的关系
Activity直接影响其所包含的Fragment的生命周期
Fragment的回调方法要比Activity多,多出的方法主要用于与Activity的交互
当Activity进入运行状态时(即running状态) ,才允许添加或删除Fragment
有当Activity处于resumed状态时,Fragment的生命周期才能独立运转
其他阶段依赖于Activity的生命周期
静态方式
Fragment的生命周期调用过程:
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
onStart()
onResume()
onPause()
onStop()
onAttach()
onCreate()
onCreateView()
onActivityCreated()
onStart()
onResume()
当首次展示布局页面时,其生命周期方法调用的顺序是︰
当关闭手机屏幕或者手机屏幕变暗时,其生命周期方法调用的顺序是︰
当对手机屏幕解锁或者手机屏幕变亮时,其生命周期方法调用的顺序是︰
当对Fragment所在屏幕按返回键时,其生命周期方法调用的顺序是︰
Menu菜单和ToolBar
Menu菜单
Android中提供的菜单有如下几种
选项菜单
子菜单
上下文菜单
图标菜单
扩展菜单
Options Menu选项菜单
系统创建菜单的方法主要有以下两种:
onCreateOptionsMenu():创建选项菜单
onCreateContextMenu():创建上下文菜单
上下文菜单使用onCreateOptionsMenu()回调方法对菜单进行初始化;使用onPrepareOptionsMenu()方法动态改变选项菜单的内容
创建并显示Menu菜单
@override
public boolean onCreateOptionsMenu (Menu menu) {
super.onCreateOptionsMenu (menu) ;
//添加4个菜单项,分成2组
int group1 = 1;
int gourp2 = 2;
menu.add (group1, 1, 1,"菜单项1");
menu.add (group1, 2,2,"菜单项2");
menu.add (gourp2,3,3,"菜单项3");
menu. add (gourp2, 4, 4,"菜单项4");
//显示菜单
return true;
}
响应菜单项
Android为菜单提供了两种响应方式:
onOptionsItemSelected()方法
onMenuItemSelected()方法
onMenuItemSelected与onOptionsItemSelected区别:
onMenuItemSelected():当选择选项菜单或上下文菜单都会触发该事件处理方法
onOptionsItemSelected():该方法只在选项菜单被选中时才会被触发
如果Activity中同时重写onMenuItemSelected()和onOptionsItemSelected()方法时,当点同一个菜单项时,将先调用onMenuItemSelected()方法,然后调用onOptionsItemSelected()方法性。
onOptionsItemSelected()方法
@override
public boolean onOptionsItemSelected (MenuItem item){
switch (item. getItemId () ){
case 1:
Toast.makeText(this,"菜单项1",Toast. LENGTH_SHORT) .show ();
break;
case 2: ...
}
return super.onOptionsItemSelected (item) ;
}
onMenuItemSelected()方法
@override
public final boolean onMenuItemSelected (intfeatureId,MenuItem item){
switch (item. getItemId()) {
case 1:
Toast.makeText(this,"菜单项11",Toast.LENGTH_SHORT).show ();
case 2:
case 3:
case 4:
}
return super.onMenuItemSelected (featureId, item ) ;
}
SubMenu子菜单
创建步骤:
重写Activity类的onCreateOptionsMenu()方法
调用Menu的addSubMenu()方法添加子菜单
调用SubMenu的add()方法为子菜单添加菜单项
重写Activity类的onOptionsItemSelected()方法
当调用setIcon)方法设置图标时,图标无法显示是因为在MenuBuilder的optionalIconsVisible属性默认为false。当要显示图标时,需要通过反射机制调用MenuBuilder对象的setOptionalIconsVisible)方法,将其设置为true即可。
创建子菜单
public boolean onCreateOptionsMenu (Menu menu){
//添加子菜单
SubMenu subMenu = menu.addSubMenu ( 0,2,Menu .NONE,"基础操作");
subMenu .setIcon (android.R.drawable.ic_menu_manage);setIconEnable (menu);
//添加子菜单项
//重命名菜单项
MenuItem renameItem = subMenu . add(2,201,1,"重命名");
renameItem.setIcon (android.R.drawable.ic_menu_edit);
//......
}
ContextMenu上下文菜单
上下文菜单是通过调用ContextMenu接口中的方法来实现
onCreateContextMenu()方法来生成ContextMenu对象
onCreatecontextMenu(contextMenu menu,viewv ,ContextMenu .ContextMenuInfo menuInfo)
当需要传递额外信息时,需要重写getContextMenuInfo(方法,并返回一个带有数据的ContextMenuInfo实现类对象。
使用XML资源生成菜单
使用XML资源生成菜单项的步骤:
在res目录中创建menu子目录
在menu子目录中创建一个Menu Resource file ( XML文件)
使用XML文件的资源ID,在Activity中将XML文件中所定义的菜单元素添加到menu对象中
通过判断菜单项对应的资源ID来实现响应的事件处理
使用XML资源生成菜单1
<menu>
<group android: id="@+id/ group1" >
<item
android: id="@+id/ item_send"
android: title="发送"/>
<item
android:id="@+id/ item_rename"
android: title="重命名"/>
<item
android: id="@+id/ item_del"
android: title="删除"/>
</group>
</menu>
使用XML资源生成菜单2
contextMenuBtn = (Button)
findViewById(R.id.contextMenuBtn) ;
//为按钮注册上下文菜单,长按按钮则弹出上下文菜单
this.registerForContextMenu(contextMenuBtn);
@override
public void onCreateContextMenu(ContextMenu menu,View v,ContextMenuInfo menuInfo){
menu.setHeaderTitle ("文件操作");
getMenuInflater().inflate(R.menu.context_menu,menu);
}
资源文件实现子菜单
<item android :title="系统设置">
<menu>
<item android:id="@+id/mi_display_setting"
android:title="显示设置"/>
<item android:id="@+id/mi_network_setting"
android:title="网络设置"/>
<!--其他菜单项-->
</menu>
为菜单项添加图标
<item
android:id="@+id/mi_exit"
android:title="退出"
android : icon="@drawable/exit"/ >
设置菜单项的可选策略
<group android:id="... "
android: checkableBehavior="all">
<!--菜单项-->
</group>
使用android:checked设置特定菜单项
<item
android:id="..."
android:title="sometitle"
android:checked="true"/>
为菜单项添加图标
<item
android:id=" ..."
android:title="sometitle"
android:enabled="false"/>
设置菜单项可见/不可见
<item
android:id="..."
android:title="sometitle"
android:visible="false"/>
Toolbar操作栏
Material Design风格的导航组件
取代Actionbar
为开发者预留许多可定制修改的余地∶
支持添加一个或多个的自定义组件
设置App的Logo图标
支持设置标题和子标题
设置导航栏图标
支持Action Menu
方法功能描述setTitle(int resId)设置标题setSubtitle(int resId)设置子标题setTitleTextColor(int color)设置标题字体颜色setSubtitleTextColor(int color)设置子标题字体颜色setNavigationIcon(Drawable icon)设置导航栏的图标setLogo(Drawable darwable)设置Toolbar的Logo图标
高级组件
AdapterView与Adapter
AdapterView实现过程类似于MVC架构
AdapterView实现过程
控制层:Adapter适配器承担了控制层的角色
视图层:AdapterView用于将前端显示和后端数据分离
模型层:数组、XML文件等形式的数据
AdapterView具有以下特征:
AdapterView继承了ViewGroup,其本质上是容器
AdapterView可以包括多个”列表项“,并将”列表项“以合适的形式显示出来
AdapterView所显示的”列表项“是由Adapter提供,通过AdapterVIew的setAdapter()方法来设置Adapter适配器。
AdapterView及其子类的继承关系
通常将ListView、GridView、Spinner和Gallery等AdapterView子类作为容器,然后使用Adapter为容器提供“列表项”,AdapterView负责采用合适的方式显示这些列表项。
Adapter的常用子接口:
ListAdapter接口
baseAdapter抽象类
SImpleCursorAdapter类
ArrayAdapter类
SimpleAdapter类
Adapter对象扮演着桥梁的角色,通过桥梁连接着AdapterView和所要显示的数据。Adapter提供了一个连通数据项的途径,将数据集呈现到View中。
ListView列表视图
ListView通常具有两个职责:
将数据填充到布局,以列表的方式来显示数据
处理用户的选择、点击等操作SimpleCursorAdapter
通常创建ListView的两种方式:
直接使用ListView进行创建
使用Activity继承ListActivity,实现ListView对象的获取
XML属性功能描述android:divider设置列表的分隔条android:dividerHeight用来指定分割条的高度android:entries指定一个数组资源android:footerDividersEnabled各个footer之间绘制分割条android:headerDividersEnabled各个header之间绘制分割条
ListView从AbsListView中继承的属性
XML属性描述android:cacheColorHint用于设置该列表的背景始终以单一、固定的颜色绘制android:choiceMode为视图指定选择的行为adnroid:drawSelectorOnTop如果为true,选中的列表项将会显示在上面android:fastScrollEnabled用于设置是否允许使用快速滚动滑块android:listSelector设置选中项显示的可绘制对象android:scrollingCache设置在滚动时是否使用绘制缓存,默认为true。android:smoothScrollbar列表会使用更精确的基于条目在屏幕上的可见像素高度的计算方法android:stackFromBottom设置是否将列表项从底部开始显示android:textFilterEnabled设置是否对列表项进行过滤android:transcriptMode设置该组件的滚动模式
使用ListView步骤:
准备ListView所要显示的数据
使用数组或List集合存储数据
创建适配器,作为列表项数据源
将适配器对象添加到ListView,并进行展示
实现ListView
ListView组件本身默认的id为@id/android:list
直接调用getListView()
在ListActivity中显示其他组件的步骤∶
先定义Activity的布局文件,在布局UI界面时先增加其他组件,再添加一个ListView组件用于展示数据
在Activity中通过setContentView()方法来添加布局对象
获取并绑定Activity中的ListView
<!-— 默认的Listview -->
<Listview
android: id="@+id/ listview"
android: layout_width="match_ parent"
android: layout_height="0dip"
android: layout_weight="1"
android : drawselectorOnTop="false" />
通过继承ListActivity来实现ListView时,当用户也定义了一个id为@id/android:list的ListView,与ListActivity中的默认ListView组件id一致,则使用setContentViewO方法可以指定用户定义的ListView作为ListActivity的布局,否则会使用系统提供的ListView。
实现图文混排步骤︰
定义行选项的布局格式
自定义一个Adapter,并重写其中的关键方法
注册列表选项的单击事件
创建Activity并加载对应的布局文件
GridView网格视图
用于按行和列的分布方式来显示多个组件
通过Adapter来提供显示数据
XML属性描述android:numColumns设置列数android:columnWidth设置每一列的宽度android:stretchMode设置拉伸模式android:verticalSpacing设置各个元素之间的垂直边距android:horizontalSpacing设置各个元素之间的水平边距
创建GridView的步骤︰
在布局文件中使用
<GridView>
元素来定义GridView组件自定义一个Adapter,并重写其中的关键方法
注册列表选项的单击事件
创建Activity并加载对应的布局文件
WebView
WebView用于在App中加载网页
使用Web检查器来调试HTML、CSS、Javascript等代码
可以对URL请求、页面加载、渲染以及页面的交互进行处理
WebView具有以下几个辅助类:
WebChromeClient:辅助WebView实现与浏览器的交互动作
WebViewClient:帮助WebView处理各种通知、请求事件等
WebSettings : x对WebView进行配置和管理
addJavascriptInterface():将Java对象绑定到WebView中,以便JavaScript从页面中控制Java对象,实现WebView与HTML页面的交互
在Android 4.3及以前版本WebView内部采用Webkit渲染引擎,在Android 4.4以上版本采用chromium渲染引擎来渲染View的内容。
使用WebView的步骤:
<uses-permission android:name="android.permission.INTERNET"/>
在布局文件中创建WebView元素
在代码中加载网页
在AndroidManifest.xml中配置访问权限
使用loadData()或loadDataWithBaseURL()方法将HTML代码片段或本地存储的HTML页面内容显示出来
loadDataWithBaseURL()不能加载来自网络的内容
baseUrl:基础目录
data:被加载的内容
mimeType :指定资源的媒体类型
Encoding :设置网页的编码格式
historyUrl :历史记录字段
ViewPager
ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view
ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类。
ViewPager类需要一个PagerAdapter适配器类给它提供数据。
ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用
最普通的PagerAdapter需要重写下面的四个方法:
①将给定位置的view添加到ViewGroup(容器)中,创建并显示出来
②返回一个代表新增页面的Object(key),通常都是直接返回view本身就可以了
getCount():获得viewpager中有多少个view
destroyltem():移除一个给定位置的页面。适配器有责任从容器中删除这个视图。这是为了确保在finishUpdate(viewGroup)返回时视图能够被移除。
instantiateItem():
isViewFromObject():判断instantiateltem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图
自定义组件
Android中所有控件和布局的基类都是View,自定义控件也就是继承View或者View的派生类,然后再重写类中的内部方法。
通常来说自定义控件分为三种:
自定义View:继承View
基于现有组件∶继承View的派生类
组合的方式∶自定义控件中包含了其他的组件
自定义控件绘制过程︰
创建一个类,继承View类
onMeasure()方法,测量计算视图的大小
onLayout()方法,设置视图在屏幕中显示的位置
onDraw()方法,绘制视图
为什么要在安卓中使用自定义控件? 安卓在使用中大多数使用已有的一些控件,用法比较简单,还有一部分是比较复杂的、用户自己想的控件,这些就需要进行自定义控件!
自定义View的方法,有以下十三种:
onFinishInflate()︰回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure()∶检测View组件及其子组件的大小
onLayout():当该组件需要分配其子组件的位置、大小时
onSizeChange():当该组件的大小被改变时
onDraw():当组件将要绘制它的内容时
onKeyDown :当按下某个键盘时
onKeyUp :当松开某个键盘时