說說 Android 中如何實(shí)現(xiàn)同時(shí)兼容手機(jī)與平板的新聞應(yīng)用界面

企業(yè)一般都會(huì)為應(yīng)用提供手機(jī)版與 Pad 版的程序畴蒲,我們可以利用 Android 碎片悠鞍,編寫出兼容手機(jī)與平板的應(yīng)用程序。

手機(jī)模擬器運(yùn)行效果

因?yàn)樾侣劻斜頃?huì)用到 RecyclerView模燥,所以我們先在 app/build.gradle 中引入依賴庫:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.android.support:recyclerview-v7:24.2.1'
    testCompile 'junit:junit:4.12'
}

接下來咖祭,編寫一個(gè)新聞的實(shí)體類:

public class News {

    /**
     * 標(biāo)題
     */
    private String title;

    /**
     * 內(nèi)容
     */
    private String content;

    /**
     * 圖片列表
     */
    private List<Integer> images;

    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;
    }

    public List<Integer> getImages() {
        return images;
    }

    public void setImages(List<Integer> images) {
        this.images = images;
    }

    @Override
    public String toString() {
        return "News{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", images=" + images +
                '}';
    }
}

新聞的實(shí)體類包含標(biāo)題、內(nèi)容和圖片資源列表蔫骂。

新建布局 news_content_frag.xml:

<?xml version="1.0" encoding="utf-8"?>
<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"
        >

        <!--標(biāo)題-->
        <TextView
            android:id="@+id/news_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="left"
            android:padding="10dp"
            android:textSize="26sp"
            android:textColor="#000"
            android:lineSpacingExtra="3dp"
            />

        <!--分割線-->
        <View android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#d0d0d0"/>

        <ImageView
            android:id="@+id/news_image"
            android:layout_width="400sp"
            android:layout_height="300sp"
            android:layout_gravity="center"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            />

        <!--內(nèi)容-->
        <TextView
            android:id="@+id/news_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:textSize="18sp"
            android:lineSpacingExtra="3dp"
            />
    </LinearLayout>
</RelativeLayout>

新聞內(nèi)容的布局主要分為兩個(gè)部分么翰,頭部顯示新聞標(biāo)題,正文顯示新聞圖片與內(nèi)容辽旋,中間使用一條細(xì)線分隔開浩嫌。細(xì)線采用 View 實(shí)現(xiàn)檐迟,把 View的寬與高都設(shè)置為 1dp,然后再通過 background 設(shè)置背景色即可码耐。

然后再新建一個(gè) NewsContentFragment 類追迟,作為新聞內(nèi)容的碎片:

public class NewsContentFragment extends Fragment {

    private View view;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.news_content_frag, container, false);
        return view;
    }

    /**
     * 更新
     *
     * @param title      標(biāo)題
     * @param content    內(nèi)容
     * @param imageResId 圖片資源 ID
     */
    public void refresh(String title, String content, int imageResId) {
        view.findViewById(R.id.visibility_layout).setVisibility(View.VISIBLE);
        ((TextView) view.findViewById(R.id.news_title)).setText(title);
        ((ImageView) view.findViewById(R.id.news_image)).setImageResource(imageResId);
        ((TextView) view.findViewById(R.id.news_content)).setText(content);


    }
}

這里提供了一個(gè) refresh 方法,用于將新聞的標(biāo)題伐坏、圖片與內(nèi)容顯示在界面中怔匣。

這樣就把新聞內(nèi)容的碎片和布局創(chuàng)建好了,但它們都是運(yùn)行在雙頁模式中的桦沉,所以我們還需創(chuàng)建一個(gè)活動(dòng) NewsContentActivity每瞒,用于單頁模式中。

NewsContentActivity 的 布局文件 activity_news_content.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">

    <fragment
        android:id="@+id/news_content_fragment"
        android:name="net.deniro.android.fragmentbestpractice.NewsContentFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></fragment>
</LinearLayout>

這里充分發(fā)揮了代碼的復(fù)用性纯露,直接在布局中引入了 NewsContentFragment剿骨,這相當(dāng)于把 news_content_frag 布局也自動(dòng)加載了進(jìn)來。

然后編寫 NewsContentActivity 的代碼:

public class NewsContentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_news_content);


        //獲取傳入的數(shù)據(jù)
        Intent intent = getIntent();
        String title = intent.getStringExtra("title");
        String content = intent.getStringExtra("content");
        int imageResId = intent.getIntExtra("imageResId", 0);

        Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
        ((NewsContentFragment) fragment).refresh(title, content, imageResId);
    }

    /**
     * 啟動(dòng)活動(dòng)
     *
     * @param context
     * @param title      標(biāo)題
     * @param content    內(nèi)容
     * @param imageResId 圖片資源 ID
     */
    public static void start(Context context, String title, String content, int imageResId) {
        Intent intent = new Intent(context, NewsContentActivity.class);
        intent.putExtra("title", title);
        intent.putExtra("content", content);
        intent.putExtra("imageResId", imageResId);
        context.startActivity(intent);
    }


}

在 onCreate() 方法中埠褪,我們通過 Intent 獲取傳入的新聞標(biāo)題浓利、圖片(這里為了簡便,只取出圖片列表的第一張圖片)和內(nèi)容钞速,然后調(diào)用 FragmentManager 的 findFragmentById() 方法得到 NewsContentFragment 的實(shí)例贷掖,接著調(diào)用它的 refresh() 方法,傳入相應(yīng)的數(shù)據(jù)渴语。

這里還為 Activity 定義了一個(gè)靜態(tài)的啟動(dòng)方法 start 苹威。

接著,創(chuàng)建顯示新聞列表的布局 news_title_frag.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.support.v7.widget.RecyclerView
        android:id="@+id/news_title_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

這里只定義了一個(gè)用于顯示新聞列表的 RecyclerView驾凶。

然后牙甫,新建 news_item.xml 作為 RecyclerView 子項(xiàng)的布局:

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


    <TextView
        android:id="@+id/news_title"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:gravity="left"
        android:paddingTop="40dp"
        android:paddingLeft="15dp"
        android:paddingRight="30dp"
        android:textSize="20sp"
        android:textColor="#000"
        >
    </TextView>



    <ImageView
        android:id="@+id/news_image"
        android:layout_width="130dp"
        android:layout_height="130dp"
        android:layout_gravity="right"
        android:paddingRight="15dp"
        />

    <!--分割線-->
    <View android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#d0d0d0"/>
</FrameLayout>

這里的布局采用 FrameLayout,然后使用 layout_gravity 來控制控件在布局中的對(duì)齊方式调违。

因?yàn)樾侣劻斜砗妥禹?xiàng)布局都創(chuàng)建好了窟哺,所以接下來就需要?jiǎng)?chuàng)建一個(gè) NewsTitleFragment 作為展示新聞列表的碎片:

public class NewsTitleFragment extends Fragment {

    private static final String TAG = "NewsTitleFragment";

    /**
     * 是否為雙頁模式
     */
    private boolean isTwoPage;

    class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
        private List<News> newsList;


        class ViewHolder extends RecyclerView.ViewHolder {
            ImageView image;
            TextView titleText;

            public ViewHolder(View itemView) {
                super(itemView);
                titleText = (TextView) itemView.findViewById(R.id.news_title);
                image = (ImageView) itemView.findViewById(R.id.news_image);
            }
        }

        public NewsAdapter(List<News> data) {
            newsList = data;
            Log.d(TAG, "NewsAdapter: " + newsList);
        }


        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
            final ViewHolder holder = new ViewHolder(view);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    News news = newsList.get(holder.getAdapterPosition());
                    Integer firstImageResId = news.getImages().get(0);
                    if (isTwoPage) {//雙頁模式,則直接刷新 NewsContentFragment 中的內(nèi)容
                        ((NewsContentFragment) getFragmentManager().findFragmentById(R.id.news_content_fragment)).refresh(news.getTitle(), news.getContent(), firstImageResId);
                    } else {//單頁模式技肩,直接啟動(dòng) NewsContentActivity 活動(dòng)
                        NewsContentActivity.start(getActivity(), news.getTitle(), news.getContent(), firstImageResId);
                    }
                }
            });
            return holder;
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            News news = newsList.get(position);
            holder.titleText.setText(news.getTitle());
            holder.image.setImageResource(news.getImages().get(0));//取第一張圖片
        }

        @Override
        public int getItemCount() {
            return newsList.size();
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.news_title_frag, container, false);

        //為 RecyclerView 填充數(shù)據(jù)
        RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.news_title_recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(new NewsAdapter(getNews()));

        return view;
    }

    private List<News> getNews() {
        List<News> list = new ArrayList<>();
        addNews(list, R.drawable.new1, "在韓國上演的北京8分鐘且轨,中國首次用AI展示國家形象", "時(shí)隔14年后,奧林匹克再次進(jìn)入北京時(shí)間虚婿≈掣妫 剛剛結(jié)束的平昌冬奧會(huì)閉幕儀式上,張藝謀和團(tuán)隊(duì)用8分鐘的時(shí)間雳锋,展示了國家形象并向全球發(fā)出邀請(qǐng)黄绩。與上次雅典8分鐘不同的是,這次中國的形象有了更多科技元素玷过∷ぃ可能你不知道筑煮,整個(gè)展示過程其實(shí)是由人工智能和人類演員共同完成。今晚20點(diǎn)20分粤蝎,2名大熊貓?zhí)厥埂?2名北體大學(xué)生滑冰登場真仲,緊隨人類表演者亮相的還有24面冰雪通透的屏幕,按照長城磚比例設(shè)計(jì)初澎,由24個(gè)機(jī)器人操作秸应。整個(gè)表演也因此呈現(xiàn)“畫中畫”模式。");
        addNews(list, R.drawable.new2, "AI的烏托邦碑宴!谷歌母公司正在建造超級(jí)智慧城市 ", "xxx");
        addNews(list, R.drawable.new3, "諾基亞CEO:世界各大運(yùn)營商加速 5G部署將提前一年 ", "xxx");
        addNews(list, R.drawable.new4, "買房難软啼,蘋果新總部附近房屋平均售價(jià)116萬美元 ", "xxx");
        addNews(list, R.drawable.new5, "人民日?qǐng)?bào)三問區(qū)塊鏈:區(qū)分是技術(shù)創(chuàng)新還是集資創(chuàng)新 ", "xxx");
        Log.d(TAG, "getNews: " + list);
        return list;

    }

    /**
     * 新增新聞
     *
     * @param list
     * @param image   圖片資源
     * @param title   標(biāo)題
     * @param content 內(nèi)容
     */
    private void addNews(List<News> list, int image, String title, String content) {
        News news = new News(title, content);
        List<Integer> images = new ArrayList<>();
        images.add(image);
        news.setImages(images);
        list.add(news);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (getActivity().findViewById(R.id.news_content_layout) != null) {//雙頁模式
            isTwoPage = true;
        } else {
            isTwoPage = false;
        }
    }
}
  1. 這里新建了一個(gè)內(nèi)部類 NewsAdapter 來作為 RecyclerView 的適配器,因?yàn)閮?nèi)部類可以直接訪問外部類的變量延柠。

  2. 在 onCreateViewHolder 中祸挪,我們注冊(cè)了點(diǎn)擊事件,并根據(jù)當(dāng)前所處的模式贞间,來進(jìn)行相應(yīng)的邏輯處理贿条。如果是單頁模式,就啟動(dòng)一個(gè)新的活動(dòng)來顯示新聞內(nèi)容增热;如果是雙頁模式整以,就更新新聞內(nèi)容碎片中的內(nèi)容。

  3. 在 onCreateView 方法中峻仇,把數(shù)據(jù)填充到 RecyclerView 中公黑。

  4. 在 onActivityCreated 方法中,我們通過能否找到一個(gè) news_content_layout 的 View 來判斷當(dāng)前處于的模式(雙頁或單頁)础浮。這是通過限定符來實(shí)現(xiàn)的:

主布局 activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/news_title_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/news_title_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="net.deniro.android.fragmentbestpractice.NewsTitleFragment"
        />

</FrameLayout>

接著,在 res 目錄下新建 layout-sw600dp 文件夾奠骄,并在這個(gè)文件夾下再新建一個(gè)布局
activity_main.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="horizontal">

   <fragment
       android:id="@+id/news_title_fragment"
       android:name="net.deniro.android.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="2"
        >
        <fragment
            android:id="@+id/news_content_fragment"
            android:name="net.deniro.android.fragmentbestpractice.NewsContentFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </FrameLayout>


</LinearLayout>

這樣當(dāng)運(yùn)行在屏幕寬度大于 600 dp 的設(shè)備上時(shí)豆同,就會(huì)加載 news_content_fragment 布局,這樣我們也就能判斷出當(dāng)前活動(dòng)所處的模式啦O(∩_∩)O~

在手機(jī)模擬器中運(yùn)行程序:


手機(jī)模擬器中的新聞列表

點(diǎn)擊一條新聞:

手機(jī)模擬器中的新聞內(nèi)容

然后在平板模擬器中運(yùn)行程序:


平板模擬器運(yùn)行效果

是不是很酷呀O(∩_∩)O~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末含鳞,一起剝皮案震驚了整個(gè)濱河市影锈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝉绷,老刑警劉巖鸭廷,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異熔吗,居然都是意外死亡辆床,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門桅狠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讼载,“玉大人轿秧,你說我怎么就攤上這事∽傻蹋” “怎么了菇篡?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長一喘。 經(jīng)常有香客問我驱还,道長,這世上最難降的妖魔是什么凸克? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任议蟆,我火速辦了婚禮躏吊,結(jié)果婚禮上脯爪,老公的妹妹穿的比我還像新娘脖阵。我一直安慰自己梅桩,他們只是感情好唯竹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布垂涯。 她就那樣靜靜地躺著嵌巷,像睡著了一般重窟。 火紅的嫁衣襯著肌膚如雪鸟雏。 梳的紋絲不亂的頭發(fā)上享郊,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音孝鹊,去河邊找鬼炊琉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛又活,可吹牛的內(nèi)容都是我干的苔咪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼柳骄,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼团赏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耐薯,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤舔清,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后曲初,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體体谒,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年臼婆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抒痒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颁褂,死狀恐怖评汰,靈堂內(nèi)的尸體忽然破棺而出纷捞,到底是詐尸還是另有隱情,我是刑警寧澤被去,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布主儡,位于F島的核電站,受9級(jí)特大地震影響惨缆,放射性物質(zhì)發(fā)生泄漏糜值。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一坯墨、第九天 我趴在偏房一處隱蔽的房頂上張望寂汇。 院中可真熱鬧,春花似錦捣染、人聲如沸骄瓣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽榕栏。三九已至,卻和暖如春蕾各,著一層夾襖步出監(jiān)牢的瞬間扒磁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國打工式曲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妨托,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓吝羞,卻偏偏與公主長得像兰伤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钧排,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,304評(píng)論 25 707
  • 本篇文章主要介紹以下幾個(gè)知識(shí)點(diǎn):碎片 fragment 的用法敦腔;碎片 fragment 的生命周期;動(dòng)態(tài)加載布局的...
    開心wonderful閱讀 1,477評(píng)論 3 7
  • 一卖氨、News 實(shí)體類: 二会烙、新聞列表中子項(xiàng)的布局 news_item.xml: 這段代碼也非常簡單负懦,只是在 Lin...
    TTTqiu閱讀 1,269評(píng)論 1 1
  • 平板電腦和手機(jī)最大的區(qū)別就是屏幕的大小不同筒捺,一般手機(jī)屏幕的大小會(huì)在3英寸到6英寸之間,而一般平板電腦屏幕的大小會(huì)在...
    付凱強(qiáng)閱讀 821評(píng)論 0 0
  • 漏夜里纸厉,風(fēng)雪至系吭,恰應(yīng)和,庭前梅枝颗品。不忍折梅枝肯尺,不堪擾風(fēng)雪沃缘,便靜立庭前看花,待風(fēng)雪染盡则吟,融入這天地槐臀。不覺涼,不畏寒氓仲,...
    矢夭閱讀 1,277評(píng)論 14 19