Android学习笔记十五.深入理解fragment(三)之《兼容多
发表时间:2020-10-19
发布人:葵宇科技
浏览次数:79
深刻懂得fragment(三)
之《兼容多分辨率的应用》拭魅战
在上一篇博文中介绍了若何应用Android Fragment开辟实用于大年夜屏幕应用,如今我们在上一个应用的基本上持续进修若何应用Fragment开辟兼容多分辨率的应用。
[img]http://img.blog.csdn.net/20150104175535634?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjYzNzUwMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
[img]http://blog.csdn.net/u012637501/article/details/42395447/file:/C:/Users/Jiangdongguo/AppData/Local/YNote/data/jiangdongguo2013@126.com/59ba06ae72fc4c8bac3f32a384442a45/clipboard.png
1.建立/res/values-large/refs.xml引用资本文件
为了开辟兼顾屏幕分辨率的应用,我们须要建立一个引用资本文件,专门用于定义各类引用项。refs.xml引用资本文件中定义了一项引用,其感化就是标明activity_book_list实际引用(@)/res/layout/activity_book_twopane.xml界面构造文件。
之所以如许应用,目标是为了在Activity加载R.layout.activity_book_list时将会根据运行平台的屏幕大年夜小主动选择界面构造文件:在大年夜屏幕的平板电脑上,R.layout.activity_book_list将会变成/res/layout/目次小的activity_book_twopane界面构造文件;在小屏幕的手机上,R.layout.activity_book_list依然引用/res/layout/目次下的activity_book_list.xml界面构造文件。源码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--定义activity_book_list实际引用@layout/activity_book_twopane资本 -->
<item type="layout" name="activity_book_list">
@layout/activity_book_twopane</item>
</resources>2.建立/res/layout/activity_book_list.xml小屏幕界面构造文件
该构造文件仅仅是显示BookListFragment组件(android:name="包名.BookListFragment"),即该界面构造文件中只是显示图书列表。源码如下:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.example.android_fragment_1.BookListFragment"
android:id="@+id/book_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="16dp"
android:layout_marginLeft="16dp"/>3.建立/res/layout/activity_book_twopane.xml大年夜屏幕界面构造文件
这个构造文件就定义了Activity的显示界面:左边将会显示一个ListFragment,右边只是一个FrameLayout容器。个中FrameLayout容器将会动态更新个中显示的Fragment。
<?xml version="1.0" encoding="utf-8"?>
<!-- 定义一个水等分列的LinearLayout,并指定应用中等分隔条 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:divider="?android:attr/dividerHorizontal"
android:showDividers="middle">
<!-- 应用资本文件方法:添加一个fragment到Activity中 -->
<fragment
android:name="com.example.android_fragment_1.BookListFragment"
android:id="@+id/book_list"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="1"/>
<!-- 添加一个FrameLayout容器,用于显示图书具体信息 -->
<FrameLayout
android:id="@+id/book_detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"/>
</LinearLayout>
4.建立/src/../BookListActivity.java主Activity
实现BookListActivity将会针对不合屏幕分辨率来加载不合的界面构造文件,即经由过程获取界面资本文件"activity_book_list",剖断该界面构造文件中是否包含有ID为book_detail_containner的组件。如不雅有,则解释为大年夜屏幕应用的是activity_book_twopane.xml界面构造文件;不然,为activity_book_list.xml界面构造文件。源码如下:
package com.example.android_fragment_1;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class BookListActivity extends Activity implements
BookListFragment.Callbacks
{
//1.定义一个旗标,用于标识是否该应用是否支撑大年夜屏幕
private boolean mTwoPane;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//2.指定加载activity_book_list对应的界面构造文件,实际上会根据分辨率选择响应的构造界面
setContentView(R.layout.activity_book_list);
//3.如不雅加载的界面构造文件中包含ID为book_detail_container的组件,则解释支撑大年夜屏幕
if(findViewById(R.id.book_detail_container)!=null)
{
mTwoPane=true; //支撑大年夜屏幕
((BookListFragment)getFragmentManager()
.findFragmentById(R.id.book_list))
.setActivateOnItemClick(true);
}
}
//4.实现Fragment与Activity交互办法
@Override
public void onItemSelected(Integer id) {
/*如不雅加载的是大年夜屏幕构造界面文件*/
if(mTwoPane)
{
//a.创建Bundle,预备向Fragment传入参数(将键值对绑定到arguments对象中)
Bundle arguments=new Bundle();
arguments.putInt(BookDetailFragment.ITEM_ID,id);
//b.创建BookDetailFragment对象,并向Fragment传入参数
BookDetailFragment fragment=new BookDetailFragment();
fragment.setArguments(arguments);
//c.应用fragment调换book_detail_container容器当前显示的Fragment
getFragmentManager().beginTransaction()
.WordStr(R.id.book_detail_container, fragment).commit();
}
/*如不雅加载的是小屏幕构造界面文件*/
else
{
//a.创建启动BookDetailActivity的Intent
Intent detailIntent=new Intent(this,BookDetailActivity.class);
//b.设置传递给BookDetailActivity参数,并启动Activity
detailIntent.putExtra(BookDetailFragment.ITEM_ID, id);
startActivity(detailIntent);
}
}
}
5.建立/src/../BookDetailActivity.java显示图书详情Activity
BookDetailActivity重要用于显示小屏幕图书详情,他将直接复竽暌姑已有的BookDetailFragment。重要完成两个功能:一是当用户当即Activity某个列表项时,会Intent跳转到该Activity并将打包的某图书详情显示在Activity上;二是,该Activity还启用了ActionBar上的应用法度榜样搁笔,许可用户点击该搁笔返回到法度榜样的主Activity。
package com.example.android_fragment_1;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
public class BookDetailActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//1.指定加载/res/layout目次下的activity_book_detail.xml构造文件
setContentView(R.layout.activity_book_detail);
//2.将ActionBar上应用搁笔转换成可点击的按钮
getActionBar().setDisplayHomeAsUpEnabled(true);
if(savedInstanceState==null)
{
//a.创建BookDetailFragment对象
BookDetailFragment fragment=new BookDetailFragment();
//b.创建Bundle对象
Bundle arguments=new Bundle();
arguments.putInt(BookDetailFragment.ITEM_ID, getIntent()
.getIntExtra(BookDetailFragment.ITEM_ID,0));
//c.向Fragment传入参数
fragment.setArguments(arguments);
//d.指定fragment添加到book_detail_container容器中
getFragmentManager().beginTransaction()
.add(R.id.book_detail_container, fragment).commit();
}
}
//3.按下搁笔响应
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
if(item.getItemId()==android.R.id.home)
{
//a.创建启动BookListActivity的Intent
Intent intent=new Intent(this,BookListActivity.class);
//b.添加额外的Flag,将Activity栈中处于FirstActivity之上的Activity弹出
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
//c.启动intent对应的Activity
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
/res/layout目次下的activity_book_detail.xml构造文件
该界面构造文件内只定义了一个ID名为book_detail_container的FrameLayout,用于显示图书详情。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/book_detail_container" >
</FrameLayout>
6.建立/src/../BookDetailFragment.java显示图书详情Fragment
当为大年夜屏幕时,此时BookListFragment和BookDetailFragment就起感化了,前者为列表Fragment,后者为包含两个文本框组件的Fragment。别的,主Activity加载的是activity_book_
twopane.xml界面构造文件。
onItemSelected()传入的参数id是列表的被选中的行ID, BookDetailFragment 用这个ID来大年夜法度榜样的ContentProvider中取得标题标内容。
(1)实现onCreate(Bundle savedInstanceState)办法:
获取启动该Fragment时传入的ITEM_ID参数并根据该ID获取BookContent的ITEM_MAP中的图手札息
(2)实现onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)办法:
a.为图书详情Fragment加载一个界面构造文件,为两个文本框;
b.根据传入的参数ID来更新View容器,使文本框显示不合的内容;
package com.example.android_fragment_1;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/*功能:
* 应用Fragment将会显示加载一份简单的界面构造文件,并根据传入的参数来更新
* 界面组件*/
public class BookDetailFragment extends Fragment {
public static final String ITEM_ID="item_id";
BookContent.Book book; //保存该Fragment显示的book对象
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//如不雅启动该Fragment时包含了ITEM_ID参数,个中 Map containsKey(String Key) 断定key有没有对应的value值; 有,则返回true 没有,则返回false
//大年夜Bundle对象中获取传入的参数(键值对)
if(getArguments().containsKey(ITEM_ID))
{
book=BookContent.ITEM_MAP.get(getArguments().getInt(ITEM_ID));
//获取启动该Fragment时传入的ITEM_ID参数并根据该ID获取BookContent的ITEM_MAP中的图手札息?
}
}
//2.重写该办法:该办法返回的View将作为Fragment显示的组件
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//a.加载/res/layout/目次下的fragment_book_detail.xml构造文件,返回一个view目标使该fragment的构造显示在Activity中
View view=inflater.inflate(R.layout.fragment_book_detail, //指明当前fragment的资本文件
container, //父容器控件
false); //注解是否连接该构造和其父容器控件(这里体系已经插入了构造到父容器中)
/*将图手札息中的标题、属性显示在容器的两个文本框中*/
if(book!=null)
{
//b.让book_title文本框显示book对象的title属性
((TextView) view.findViewById(R.id.book_title)).setText(book.title);
//c.让book_desc文本框显示book对象的desc属性
((TextView) view.findViewById(R.id.book_desc)).setText(book.desc);
}
return view;
}
}
个中界面资本构造文件为/res/layout/fragment_book_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- 定义一个TextView来显示图书标题 -->
<TextView
style="?android:attr/textAppearanceLarge"
android:id="@+id/book_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"/>
<!-- 定义一个TextView来显示图书描述 -->
<TextView
style="?android:attr/textAppearanceLarge"
android:id="@+id/book_desc"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"/>
</LinearLayout>
7.建立/src/../BookListFragment.java显示图书详情Fragment
自定义类,持续于ListFragment,无需实现OnCreateView()办法,用于Activity右边显示列表fragment。
(1)定义Callbacks接口:定义一个回调接口Callback,用于实现该Fragment与它地点的Activity交互;
(2)实现onCreate(Bundle savedInstanceState)办法:经由过程Adapter所供给的多个列表项,设置Fragment列表显示的列表项;
(3)实现onAttach(Activity activity)办法:将Fragment添加并显示到Acitvity中,并将传入的activity对象强迫类型转化为 Callbacks接口对象,以便调用接口公共办法onItemSelected(Integer id)响应用户单击的某列表项;
(4)实现ListFragment的onListItemClick(ListView l, View v, int position, long id)办法:
当用户点击Acitivity中的某项列表时,onListItemClick办法被激发。在这个办法中调用接口的onItemSelected来竽暌闺activity共享事宜。onItemSelected()传入的参数id是列表的被选中的行ID,另一个fragment(B)( BookDetailFragment )用这个ID来大年夜法度榜样的ContentProvider中取得标题标内容。
package com.example.android_fragment_1;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class BookListFragment extends ListFragment {
//1.定义一个回调接口Callback,用于实现该Fragment与它地点的Activity交互(留意:该接口的实现须要在Activit中)
private Callbacks mCallbacks; //Callbacks接口对象
public interface Callbacks
{
public void onItemSelected(Integer id); //参数为Map集合的键
}
//2.onCreate办法中为该ListFragment设置Adapter,让该ListFragment显示该Adapter所供给的多个列表项
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<BookContent.Book>(getActivity(),//
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
BookContent.ITEMS)); //
}
//3.调用该办法将Fragment添加并显示到Acitvity中
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
//a.如不雅Activity中没有实现Callbacks接口,抛出异常
if(!(activity instanceof Callbacks))
{
throw new IllegalStateException("异常:BookListFragment地点的Activity必须实现Callback接口!");
}
//把该Activity当成Callbacks对象(就是这一句导致出现NullPointerException缺点)
mCallbacks=(Callbacks)activity;
}
//4.当该Fragment大年夜他所属的Acitivity中被删除时,调用该办法
@Override
public void onDetach() {
super.onDetach();
mCallbacks=null; //将mCallbacks赋值为null
}
//5.当用户单击某列表项时激发该回调办法
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
mCallbacks.onItemSelected(BookContent.ITEMS.get(position).id);//激发mCallbacks接口的onItemSelected办法
}
public void setActivateOnItemClick(boolean activateOnItemClick) {
getListView().setChoiceMode(activateOnItemClick ? ListView.CHOICE_MODE_SINGLE:ListView.CHOICE_MODE_NONE);
}
}
须要留意的是,不像BookDetailFragment,因为其持续于ListFragment,无需实现OnCreateView()办法。是以,无需定义界面构造文件。
8.res/../BookContent.java:
用于模仿体系的数据模型
(1)List集合为左边fragment供给图书(标题)列表项数据
public static List<Book> ITEMS=new ArrayList<Book>();
对于List集合来说,book为(1,"猖狂Android教材","小我评价:这本书很好,就是有点厚!"2...3...)
(2)Map集合为右边fragment供给图书详情(标题、属性)数据
public static Map<Integer,Book> ITEM_MAP =new HashMap<Integer,Book>();
对应Map集合来说,键book.id<--->值(1.......2.......3......)
package com.example.android_fragment_1;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BookContent {
//1.定义一个内部类,作为体系的营业对象
public static class Book
{
public Integer id; //Map键
public String title;
public String desc;
public Book(Integer id,String title,String desc)//构造函数,初始化图书详情的"map键,标题,内容"
{
this.id=id;
this.title=title;
this.desc=desc;
}
public String toString()
{
return title;
}
}
//2.应用List集合记录体系所包含的Book对象ITEMS,应用它调用其add(对象)办法项List集合中添加列表项
public static List<Book> ITEMS=new ArrayList<Book>();
//3.应用Map集合记录体系所包含的Book对象ITEM_MAP,应用它调用put(Key,Value)办法向Map集合中添加列表项
public static Map<Integer,Book> ITEM_MAP =new HashMap<Integer,Book>();
static{
//应用静态初始化代码,将Book对象添加到List集合、Map集合中
addItem(new Book(1,"猖狂Android教材","小我评价:这本书很好,就是有点厚!"));
addItem(new Book(2,"数学之美","小我评价:来自天然语音的使者"));
addItem(new Book(3,"大年夜话数据构造","小我评价:不知道如何,据说很不错"));
}
private static void addItem(Book book) {
// TODO Auto-generated method stub
ITEMS.add(book); //添加List集合中列表项
ITEM_MAP.put(book.id,book);//添加Map集合中列表项
}
}
/*注释:
* static{},称为static代码块,也叫静态代码块。是在类中自力于类成员的static语句块,可以有多个且地位可以随便放。
* 它不属于任何的办法体内,JVM加载类时会履行这些静态的代码块,如不雅有多个则按先后次序履行且每个代码块智会被履行依次。
* 比如,我们可以应用静态代码块可以对一些statci变量进行赋值*/
9.修改AndroidManifest.xml
因为在源码中实现了一个BookDetailActivity,所以我们须要在工程文件中声明它。
<application
.......>
<activity
android:name=".BookListActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".BookDetailActivity"
android:label="@string/app_name" >
</activity>
</application>
</manifest>
小屏幕显示效不雅:
[img]http://img.blog.csdn.net/20150104175515953?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjYzNzUwMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
[img]http://blog.csdn.net/u012637501/article/details/42395447/file:/C:/Users/Jiangdongguo/AppData/Local/YNote/data/jiangdongguo2013@126.com/d25fb13bd1944507b74e951741ab0124/clipboard.png
大年夜屏幕显示效不雅:
[img]http://img.blog.csdn.net/20150104175507413?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjYzNzUwMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center








