1. 程式人生 > >Android學習第7篇——碎片實踐,結合ListView的簡單閱讀應用,自適應手機和平板

Android學習第7篇——碎片實踐,結合ListView的簡單閱讀應用,自適應手機和平板

在學過了碎片(Fragment)、ListView之後,實現一個自適應手機和平板的文章閱讀應用

效果圖:

手機:

 

平板:



二、實現過程:

1、新建一個文章實體類News

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

    public News(String title, String content) {
        this.title = title;
        this.content = 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;
    }
}

包含標題和內容;

2、接著新建一個 news_item.xml 佈局,用於作為文章列表中子項的佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <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>
android:singleLine 設定為 true 表示讓這個 TextView 只能單行顯示。android:ellipsize 用於設定當文字內容超出控
件寬度時,文字的縮略方式,這裡指定成
end 表示在尾部進行縮略。

3、接下來需要建立文章列表的介面卡,讓這個介面卡繼承自 ArrayAdapter,並將泛型指定為 News

package com.csii.www.fragmentnews.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.csii.www.fragmentnews.R;
import com.csii.www.fragmentnews.entity.News;

import java.util.List;

/**
 * Created by zhang on 2018/3/27.
 */

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 類,並讓文章的標題在列表中進行顯示。

4、這樣基本就把文章列表部分的程式碼編寫完了,接下來我們看一下如何編寫新聞內容部分的程式碼。新建佈局檔案的程式碼。新建佈局檔案 frag_news_content.xml,程式碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <ImageView
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/spilt_line_vertical"
            />
        <LinearLayout
            android:id="@+id/visibility_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="invisible"
            android:orientation="vertical">

            <TextView
                android:id="@+id/newsContentTitle"
                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/newsContent"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:padding="15dp"
                android:textSize="18sp"
                />
        </LinearLayout>
    </LinearLayout>
</ScrollView>

文章內容的佈局主要可以分為兩個部分,頭部顯示完整的文章標題,正文部分顯示文章內容,中間使用一條細線分隔開。這裡的細線是利用 ImageView 顯示了一張很窄的圖片來實現的,將 ImageView android:scaleType 屬性設定為 fitXY,表示讓這張圖片填充滿整個控制元件的大小。另外外部用了ScrollView佈局,支援文章內容較長是可以滾動閱讀。

5、然後再新建一個 NewsContentFragment 類,繼承自 Fragment,程式碼如下所示:

public class NewsContentFragment extends Fragment{
    private View view;
    //建立Fragment時候構建一個View
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.frag_news_content,container);
        return view;
    }

    //渲染frament檢視view
    public void regresh(News news){
        //點選文章的時候頁面ScrollView滾動到頂部,否則頁面在底部,影響體驗
        view.scrollTo(0,0);
        //設定檢視的屬性顯示
        View visibilityLayout = view.findViewById(R.id.visibility_layout);
        visibilityLayout.setVisibility(View.VISIBLE);
        //通過傳送過來的News例項,填充內容。
        TextView newsTitle = view.findViewById(R.id.newsContentTitle);
        TextView newsContent = view.findViewById(R.id.newsContent);
        newsTitle.setText(news.getTitle());
        newsContent.setText(news.getContent());
    }
}

6、接下來還需要再建立一個用於顯示新聞列表的佈局,新建 news_title_frag.xml,程式碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/newList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</LinearLayout>
裡面只有一個 ListView。不過想必你已經猜到了,這個佈局並不是給活動使用的,而是給碎片使用的,因此我們還需要建立一個碎片來載入這個佈局。新建一個 NewsListFragment 類,繼承自 Fragment,程式碼如下所示:
public class NewListFragment extends Fragment implements AdapterView.OnItemClickListener{

    TitleAdapter titleAdapter;
    List newsList = new ArrayList();
    boolean isTwoPanel;

    //當Fragment和Activity建立聯絡的時候初始化資料
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        initNews();//初始化新聞資料
        titleAdapter = new TitleAdapter(context, R.layout.news_item, newsList);
    }
    //建立Fragment時候構建一個View
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.frag_news_list, container, false);//這裡是資原始檔的名稱
        ListView titleList = view.findViewById(R.id.newList);
        titleList.setAdapter(titleAdapter);
        titleList.setOnItemClickListener(this);
        return view;
    }

    //在活動與頁面關聯好後,判斷是手機還是pad
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if(getActivity().findViewById(R.id.news_content_layout) != null ){
            isTwoPanel = true;
        }else{
            isTwoPanel = false;
        }
    }

    private void initNews() {
        newsList.add(new News("誰為新詞譜一曲",
                "林花謝,\n" +
                        "\n" +
                        "落盡春紅。\n" +
                        "\n" +
                        "嘆華年易逝,\n" +
                        "\n" +
                        "時光太匆匆。\n" +
                        "\n" +
                        "無奈人生,山重水複。\n" +
                        "\n" +
                        "人生無奈,水復山重。\n" +
                        "\n" +
                        "清早間瀟瀟冷雨,\n" +
                        "\n" +
                        "到晚來悽悽寒風。\n" +
                        "\n" +
                        "紅顏一去,\n" +
                        "\n" +
                        "只留下,\n" +
                        "\n" +
                        "醉眼中搖曳的倩影;\n" +
                        "\n" +
                        "江山傾倒,\n" +
                        "\n" +
                        "只留下,\n" +
                        "\n" +
                        "心田裡胭脂上淚痕。\n" +
                        "\n" +
                        "何時入夢裡?\n" +
                        "\n" +
                        "與君相逢;\n" +
                        "\n" +
                        "何時入夢裡?\n" +
                        "\n" +
                        "與君重逢。\n" +
                        "\n" +
                        "怕只怕,\n" +
                        "\n" +
                        "人生空餘恨,似水東流;\n" +
                        "\n" +
                        "怕只怕,\n" +
                        "\n" +
                        "人生空餘恨,似水長流。"));
        newsList.add(new News("國慶節出行", "好急啊"));
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        News news = (News)newsList.get(position);
        if(isTwoPanel == true ){//雙屏顯示,點選文章標題重新整理右邊碎片
            //通過getFragmentManager(),然後fundFragmentById()獲取頁面中的Fragment
            NewsContentFragment newContentFragment = (NewsContentFragment)getFragmentManager().findFragmentById(R.id.newContentFragment);
            //將New實體傳送過去
            newContentFragment.regresh(news);
        }else{
            //如果是手機,直接啟動下一個Activity顯示文章內容。
            NewsContentActivity.startAction(getActivity(),news);
        }
    }
}

    根據碎片的生命週期,我們知道,onAttach()方法會首先執行,因此在這裡做了一些資料初始化的操作,比如呼叫 getNews()方法獲取幾條模擬的文章資料,以及完成 NewsAdapter 的建立。然後在 onCreateView()方法中載入了frag_news_list 佈局, 並給新聞列表的 ListView 註冊了點選事件。 接下來在 onActivityCreated()方法中,我們通過是否能夠找到一個 id news_content_layout View 來判斷當前是雙頁模式還是單頁模式,這個 id news_content_layout View 只在雙頁模式中才會出現,在稍後的佈局裡你將會看到。然後在 ListView 的點選事件裡我們就可以判斷,如果當前是單頁模式,就啟動一個新的活動去顯示新聞內容,如果當前是雙頁模式,就更新文章內容碎片裡的資料。

7、修改 activity_main.xml 中的程式碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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" android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context="com.csii.www.newsfragment.MainActivity">


    <fragment
        android:id="@+id/newListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.csii.www.newsfragment.fragment.NewListFragment"
        ></fragment>

</LinearLayout>

上述程式碼表示, 在單頁模式下, 只會載入一個新聞標題的碎片 。然後新建 layout-sw600dp資料夾,在這個資料夾下再新建一個 activity_main.xml 檔案,程式碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" tools:context="com.csii.www.newsfragment.MainActivity">

    <fragment
        android:id="@+id/newListFragment"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:name="com.csii.www.newsfragment.fragment.NewListFragment"
        ></fragment>
    <FrameLayout
        android:id="@+id/news_content_layout"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="match_parent">
        <fragment
            android:id="@+id/newContentFragment"
            android:name="com.csii.www.newsfragment.fragment.NewsContentFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </fragment>
    </FrameLayout>

</LinearLayout>

可以看出,在雙頁模式下我們同時引入了兩個碎片,並將新聞內容的碎片放在了一個FrameLayout 佈局下,而這個佈局的 id 正是 news_content_layout。因此,能夠找到這個 id 的時候就是雙頁模式,否則就是單面模式。

8、然後新建 NewsContentActivity,作為顯示新聞內容的活動,程式碼如下所示:

package com.csii.www.newsfragment;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.csii.www.newsfragment.entity.News;

public class NewsContentActivity extends AppCompatActivity {

    public static void startAction(Context context, News news){
        Intent intent = new Intent(context,NewsContentActivity.class);
        intent.putExtra("newsTitle",news.getTitle());
        intent.putExtra("newsContent",news.getContent());
        context.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_news_content);
        Intent intent = getIntent();
        String newsTitle = intent.getStringExtra("newsTitle");
        String newsContent = intent.getStringExtra("newsContent");
        TextView newsTitleView =(TextView) findViewById(R.id.newsContentTitle);
        TextView newsContentView =(TextView) findViewById(R.id.newsContent);
        newsTitleView.setText(newsTitle);
        newsContentView.setText(newsContent);
    }
}

對應佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.csii.www.newsfragment.NewsContentActivity">

    <TextView
        android:id="@+id/newsContentTitle"
        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:background="#000"
        />
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:orientation="vertical"
            android:layout_weight="1">
        <TextView
            android:id="@+id/newsContent"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:padding="15dp"
            android:layout_weight="1"
            android:textSize="18sp"
            />
        </ScrollView>

</LinearLayout>

這裡只對文章展示部分滑動,標題置頂顯示。