zoukankan      html  css  js  c++  java
  • android: 碎片的demo

    现在你已经将关于碎片的重要知识点都掌握得差不多了,不过在灵活运用方面可能还有 些欠缺,因此又该进入我们本章的最佳实践环节了。

    前面有提到过,碎片很多时候都是在平板开发当中使用的,主要是为了解决屏幕空间不 能充分利用的问题。那是不是就表明,我们开发的程序都需要提供一个手机版和一个 Pad 版 呢?确实有不少公司都是这么做的,但是这样会浪费很多的人力物力。因为维护两个版本的 代码成本很高,每当增加什么新功能时,需要在两份代码里各写一遍,每当发现一个 bug 时, 需要在两份代码里各修改一次。因此今天我们最佳实践的内容就是,教你如何编写同时兼容 手机和平板的应用程序。

    还记得在本章开始的时候提到过的一个新闻应用吗?现在我们就将运用本章中所学的 知识来编写一个简易版的新闻应用,并且要求它是可以同时兼容手机和平板的。新建好一个 FragmentBestPractice 项目,然后开始动手吧!

    第一步我们要先准备好一个新闻的实体类,新建类 News,代码如下所示:

    public class News { private String title; private String content;

    public String getTitle() {

    return title;

    }

    public void setTitle(String title) {

    this.title = title;

    }

    public String getContent() {

    return content;

    }

    public void setContent(String content) {

    this.content = content;

    }

    }

    News 类的代码还是比较简单的,title 字段表示新闻标题,content 字段表示新闻内容。 接着新建一个 news_item.xml 布局,用于作为新闻列表中子项的布局:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

    android:orientation="vertical" >

    <TextView android:id="@+id/news_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:ellipsize="end" android:textSize="18sp" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="15dp" android:paddingBottom="15dp"

    />

    </LinearLayout>

    这段代码也非常简单,只是在 LinearLayout 中放入了一个 TextView 用于显示新闻的标

    题。仔细观察 TextView,你会发现其中有几个属性是我们之前没有学过的。android:padding 表示给控件的周围加上补白,这样不至于让文本内容会紧靠在边缘上。android:singleLine 设 置为 true 表示让这个 TextView 只能单行显示。android:ellipsize 用于设定当文本内容超出控 件宽度时,文本的缩略方式,这里指定成 end 表示在尾部进行缩略。

    接下来需要创建新闻列表的适配器,让这个适配器继承自 ArrayAdapter,并将泛型指定 为 News 类。新建类 NewsAdapter,代码如下所示:

    public class NewsAdapter extends ArrayAdapter<News> {

    private int resourceId;

    public NewsAdapter(Context context, int textViewResourceId, List<News>

    objects) {

    super(context, textViewResourceId, objects);

    resourceId = textViewResourceId;

    }

    @Override

    public View getView(int position, View convertView, ViewGroup parent) { News news = getItem(position);

    View view;

    if (convertView == null) {

    view = LayoutInflater.from(getContext()).inflate(resourceId, null);

    } else {

    view = convertView;

    }

    TextView newsTitleText = (TextView) view.findViewById(R.id.news_title);

    newsTitleText.setText(news.getTitle());

    return view;

    }

    }

    可以看到,在 getView()方法中,我们获取到了相应位置上的 News 类,并让新闻的标题 在列表中进行显示。

    这样基本就把新闻列表部分的代码编写完了,接下来我们看一下如何编写新闻内容部分 的代码。新建布局文件 news_content_frag.xml,代码如下所示:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >

    <LinearLayout android:id="@+id/visibility_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:visibility="invisible" >

    <TextView android:id="@+id/news_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="10dp" android:textSize="20sp" />

    <ImageView android:layout_width="match_parent" android:layout_height="1dp" android:scaleType="fitXY" android:src="@drawable/spilt_line" />

    <TextView android:id="@+id/news_content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:padding="15dp" android:textSize="18sp" />

    </LinearLayout>

    <ImageView android:layout_width="1dp" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:scaleType="fitXY" android:src="@drawable/spilt_line_vertical" />

    </RelativeLayout>

    新闻内容的布局主要可以分为两个部分,头部显示完整的新闻标题,正文部分显示新闻

    内容,中间使用一条细线分隔开。这里的细线是利用 ImageView 显示了一张很窄的图片来实 现的,将 ImageView 的 android:scaleType 属性设置为 fitXY,表示让这张图片填充满整个控 件的大小。

    然后再新建一个 NewsContentFragment 类,继承自 Fragment,代码如下所示:

    public class NewsContentFragment extends Fragment {

    private View view;

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.news_content_frag, container, false);

    return view;

    }

    public void refresh(String newsTitle, String newsContent) {

    View visibilityLayout = view.findViewById(R.id.visibility_layout);

    visibilityLayout.setVisibility(View.VISIBLE);

    TextView newsTitleText = (TextView) view.findViewById (R.id.news_title); TextView newsContentText = (TextView) view.findViewById(R.id.news_

    content);

    newsTitleText.setText(newsTitle); // 刷新新闻的标题

    newsContentText.setText(newsContent); // 刷新新闻的内容

    }

    }

    首先在 onCreateView()方法里加载了我们刚刚创建的 news_content_frag 布局,这个没什 么好解释的。接下来又提供了一个 refresh()方法,这个方法就是用于将新闻的标题和内容显 示在界面上的。可以看到,这里通过 findViewById()方法分别获取到新闻的标题和内容控件, 然后将方法传递进来的参数设置进去。

    接着要创建一个在活动中使用的新闻内容布局,新建 news_content.xml,代码如下所示:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

    android:orientation="vertical" >

    <fragment android:id="@+id/news_content_fragment" android:name="com.example.fragmentbestpractice.NewsContentFragment" android:layout_width="match_parent" android:layout_height="match_parent"

    />

    </LinearLayout>

    这里我们充分发挥了代码的复用性,直接在布局中引入了 NewsContentFragment,这样 也就相当于把 news_content_frag 布局的内容自动加了进来。

    然后新建 NewsContentActivity,作为显示新闻内容的活动,代码如下所示:

    public class NewsContentActivity extends Activity {

    public static void actionStart(Context context, String newsTitle, String newsContent) {

    Intent intent = new Intent(context, NewsContentActivity.class); intent.putExtra("news_title", newsTitle); intent.putExtra("news_content", newsContent);

    context.startActivity(intent);

    }

    @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.news_content);

    String newsTitle = getIntent().getStringExtra("news_title");

    // 获取传入的新闻标题

    String newsContent = getIntent().getStringExtra("news_content");

    // 获取传入的新闻内容

    NewsContentFragment newsContentFragment = (NewsContentFragment)

    getFragmentManager()

    .findFragmentById(R.id.news_content_fragment);

    newsContentFragment.refresh(newsTitle, newsContent);

    // 刷新NewsContentFragment界面

    }

    }

    可以看到,在 onCreate()方法中我们通过 Intent 获取到了传入的新闻标题和新闻内容,

    然后调用 FragmentManager 的 findFragmentById()方法得到了 NewsContentFragment 的实例, 接着调用它的 refresh()方法,并将新闻的标题和内容传入,就可以把这些数据显示出来了。 注意这里我们还提供了一个 actionStart()方法,还记得它的作用吗?如果忘记的话就再去阅 读一遍 2.6.3 节吧。

    接下来还需要再创建一个用于显示新闻列表的布局,新建 news_title_frag.xml,代码如 下所示:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

    android:orientation="vertical" >

    <ListView android:id="@+id/news_title_list_view" android:layout_width="match_parent" android:layout_height="match_parent" >

    </ListView>

    </LinearLayout>

    这个布局的代码就非常简单了,里面只有一个 ListView。不过想必你已经猜到了,这个 布局并不是给活动使用的,而是给碎片使用的,因此我们还需要创建一个碎片来加载这个布 局。新建一个 NewsTitleFragment 类,继承自 Fragment,代码如下所示:

    public class NewsTitleFragment extends Fragment implements

    OnItemClickListener {

    private ListView newsTitleListView;

    private List<News> newsList; private NewsAdapter adapter; private boolean isTwoPane;

    @Override

    public void onAttach(Activity activity) {

    super.onAttach(activity);

    newsList = getNews(); // 初始化新闻数据

    adapter = new NewsAdapter(activity, R.layout.news_item, newsList);

    }

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.news_title_frag, container, false);

    newsTitleListView = (ListView) view.findViewById(R.id.news_title_

    list_view); newsTitleListView.setAdapter(adapter); newsTitleListView.setOnItemClickListener(this);

    return view;

    }

    @Override

    public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    if (getActivity().findViewById(R.id.news_content_layout) != null) {

    isTwoPane = true; // 可以找到news_content_layout布局时,为双页模式

    } else {

    isTwoPane = false; // 找不到news_content_layout布局时,为单页模式

    }

    }

    @Override

    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

    News news = newsList.get(position);

    if (isTwoPane) {

    // 如果是双页模式,则刷新NewsContentFragment中的内容

    NewsContentFragment newsContentFragment = (NewsContentFragment)

    getFragmentManager().findFragmentById(R.id.news_

    content_fragment);

    newsContentFragment.refresh(news.getTitle(), news.getContent());

    } else {

    // 如果是单页模式,则直接启动NewsContentActivity

    NewsContentActivity.actionStart(getActivity(), news.getTitle(), news.getContent());

    }

    }

    private List<News> getNews() {

    List<News> newsList = new ArrayList<News>(); News news1 = new News();

    news1.setTitle("Succeed in College as a Learning Disabled Student"); news1.setContent("College freshmen will soon learn to live with a roommate, adjust to a new social scene and survive less-than-stellar dining hall food. Students with learning disabilities will face these transitions while also grappling with a few more hurdles."); newsList.add(news1);

    News news2 = new News();

    news2.setTitle("Google Android exec poached by China's Xiaomi"); news2.setContent("China's Xiaomi has poached a key Google executive involved in the tech giant's Android phones, in a move seen as a coup for the rapidly growing Chinese smartphone maker."); newsList.add(news2);

    return newsList;

    }

    }

    这个类的代码有点长,我来重点解释一下。根据碎片的生命周期,我们知道,onAttach() 方法会首先执行,因此在这里做了一些数据初始化的操作,比如调用 getNews()方法获取几 条模拟的新闻数据,以及完成 NewsAdapter 的创建。然后在 onCreateView()方法中加载了 news_title_frag 布局,并给新闻列表的 ListView 注册了点击事件。接下来在 onActivityCreated() 方法中,我们通过是否能够找到一个 id 为 news_content_layout 的 View 来判断当前是双页 模式还是单页模式,这个 id 为 news_content_layout 的 View 只在双页模式中才会出现,在 稍后的布局里你将会看到。然后在 ListView 的点击事件里我们就可以判断,如果当前是单 页模式,就启动一个新的活动去显示新闻内容,如果当前是双页模式,就更新新闻内容碎 片里的数据。

    剩下工作就非常简单了,修改 activity_main.xml 中的代码,如下所示:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >

    <fragment android:id="@+id/news_title_fragment" android:name="com.example.fragmentbestpractice.NewsTitleFragment"

    android:layout_width="match_parent" android:layout_height="match_parent"

    />

    </LinearLayout>

    上述代码表示,在单页模式下,只会加载一个新闻标题的碎片。然后新建 layout-sw600dp

    文件夹,在这个文件夹下再新建一个 activity_main.xml 文件,代码如下所示:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >

    <fragment android:id="@+id/news_title_fragment" android:name="com.example.fragmentbestpractice.NewsTitleFragment" android:layout_width="0dp"

    android:layout_height="match_parent" android:layout_weight="1" />

    <FrameLayout android:id="@+id/news_content_layout" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" >

    <fragment android:id="@+id/news_content_fragment" android:name="com.example.fragmentbestpractice.

    NewsContentFragment" android:layout_width="match_parent" android:layout_height="match_parent" />

    </FrameLayout>

    </LinearLayout>

    可以看出,在双页模式下我们同时引入了两个碎片,并将新闻内容的碎片放在了一个 FrameLayout 布局下,而这个布局的 id 正是 news_content_layout。因此,能够找到这个 id 的 时候就是双页模式,否则就是单面模式。

    最后再将 MainActivity 稍作修改,把标题栏去除掉,代码如下所示:

    public class MainActivity extends Activity {

    @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);

    setContentView(R.layout.activity_main);

    }

    }

    这样我们所有的编写工作就已经完成了,赶快来运行一下吧!首先在手机模拟器上运行, 效果如图 4.15 所示。

     

    图   4.15

    可以看到两条新闻的标题,并且超出屏幕部分的文字是在尾部使用省略号代替的。 然后点击第二条新闻,会启动一个新的活动来显示新闻的内容,效果如图 4.16 所示。

    图   4.16

     接下来将程序在平板模拟器上运行,同样点击第二条新闻,效果如图 4.17 所示。

     

    图   4.17

  • 相关阅读:
    Android OpenGL ES 2.0 (四) 灯光perfragment lighting
    Android OpenGL ES 2.0 (五) 添加材质
    冒泡排序函数
    javascript object 转换为 json格式 toJSONString
    Liunx CentOS 下载地址
    jquery 图片切换特效 鼠标点击左右按钮焦点图切换滚动
    javascript 解析csv 的function
    mysql Innodb Shutdown completed; log sequence number解决办法
    Centos 添加 yum
    javascript 键值转换
  • 原文地址:https://www.cnblogs.com/zgqys1980/p/5162565.html
Copyright © 2011-2022 走看看