企业一般都会为应用提供手机版与 Pad 版的程序,我们可以利用 Android 碎片,编写出兼容手机与平板的应用程序。

因为新闻列表会用到 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'}

接下来,编写一个新闻的实体类:

public class News {    /**     * 标题     */    private String title;    /**     * 内容     */    private String content;    /**     * 图片列表     */    private List 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 getImages() {        return images;    }    public void setImages(List images) {        this.images = images;    }    @Override    public String toString() {        return "News{" +                "title='" + title + '\'' +                ", content='" + content + '\'' +                ", images=" + images +                '}';    }}

新闻的实体类包含标题、内容和图片资源列表。

新建布局 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"        >                <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"            />                <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>

新闻内容的布局主要分为两个部分,头部显示新闻标题,正文显示新闻图片与内容,中间使用一条细线分隔开。细线采用 View 实现,把 View的宽与高都设置为 1dp,然后再通过 background 设置背景色即可。

然后再新建一个 NewsContentFragment 类,作为新闻内容的碎片:

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      标题     * @param content    内容     * @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);    }}

这里提供了一个 refresh 方法,用于将新闻的标题、图片与内容显示在界面中。

这样就把新闻内容的碎片和布局创建好了,但它们都是运行在双页模式中的,所以我们还需创建一个活动 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>

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

然后编写 NewsContentActivity 的代码:

public class NewsContentActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_news_content);        //获取传入的数据        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);    }    /**     * 启动活动     *     * @param context     * @param title      标题     * @param content    内容     * @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 获取传入的新闻标题、图片(这里为了简便,只取出图片列表的第一张图片)和内容,然后调用 FragmentManager 的 findFragmentById() 方法得到 NewsContentFragment 的实例,接着调用它的 refresh() 方法,传入相应的数据。

这里还为 Activity 定义了一个静态的启动方法 start 。

接着,创建显示新闻列表的布局 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>

这里只定义了一个用于显示新闻列表的 RecyclerView。

然后,新建 news_item.xml 作为 RecyclerView 子项的布局:

<?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 来控制控件在布局中的对齐方式。

因为新闻列表和子项布局都创建好了,所以接下来就需要创建一个 NewsTitleFragment 作为展示新闻列表的碎片:

public class NewsTitleFragment extends Fragment {    private static final String TAG = "NewsTitleFragment";    /**     * 是否为双页模式     */    private boolean isTwoPage;    class NewsAdapter extends RecyclerView.Adapter {        private List 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 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 中的内容                        ((NewsContentFragment) getFragmentManager().findFragmentById(R.id.news_content_fragment)).refresh(news.getTitle(), news.getContent(), firstImageResId);                    } else {//单页模式,直接启动 NewsContentActivity 活动                        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 填充数据        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 getNews() {        List list = new ArrayList<>();        addNews(list, R.drawable.new1, "在韩国上演的北京8分钟,中国首次用AI展示国家形象", "时隔14年后,奥林匹克再次进入北京时间。 刚刚结束的平昌冬奥会闭幕仪式上,张艺谋和团队用8分钟的时间,展示了国家形象并向全球发出邀请。与上次雅典8分钟不同的是,这次中国的形象有了更多科技元素。可能你不知道,整个展示过程其实是由人工智能和人类演员共同完成。今晚20点20分,2名大熊猫特使、22名北体大学生滑冰登场,紧随人类表演者亮相的还有24面冰雪通透的屏幕,按照长城砖比例设计,由24个机器人操作。整个表演也因此呈现“画中画”模式。");        addNews(list, R.drawable.new2, "AI的乌托邦!谷歌母公司正在建造超级智慧城市 ", "xxx");        addNews(list, R.drawable.new3, "诺基亚CEO:世界各大运营商加速 5G部署将提前一年 ", "xxx");        addNews(list, R.drawable.new4, "买房难,苹果新总部附近房屋平均售价116万美元 ", "xxx");        addNews(list, R.drawable.new5, "人民日报三问区块链:区分是技术创新还是集资创新 ", "xxx");        Log.d(TAG, "getNews: " + list);        return list;    }    /**     * 新增新闻     *     * @param list     * @param image   图片资源     * @param title   标题     * @param content 内容     */    private void addNews(List list, int image, String title, String content) {        News news = new News(title, content);        List 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. 这里新建了一个内部类 NewsAdapter 来作为 RecyclerView 的适配器,因为内部类可以直接访问外部类的变量。

  2. 在 onCreateViewHolder 中,我们注册了点击事件,并根据当前所处的模式,来进行相应的逻辑处理。如果是单页模式,就启动一个新的活动来显示新闻内容;如果是双页模式,就更新新闻内容碎片中的内容。

  3. 在 onCreateView 方法中,把数据填充到 RecyclerView 中。

  4. 在 onActivityCreated 方法中,我们通过能否找到一个 news_content_layout 的 View 来判断当前处于的模式(双页或单页)。这是通过限定符来实现的:

主布局 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 文件夹,并在这个文件夹下再新建一个布局
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>

这样当运行在屏幕宽度大于 600 dp 的设备上时,就会加载 news_content_fragment 布局,这样我们也就能判断出当前活动所处的模式啦O(∩_∩)O~

在手机模拟器中运行程序:

点击一条新闻:

然后在平板模拟器中运行程序:

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

更多相关文章

  1. 第七章 布局
  2. Android的启动模式
  3. Android 5.0上动态布局层级覆盖问题
  4. Android自适应不同分辨率或不同屏幕大小的layout布局(横屏|竖屏)
  5. android常用的设计模式总结 一
  6. Android 中 Activity 的4种启动模式
  7. 安卓课程六 android常用布局属性的介绍

随机推荐

  1. Android世界下的悲慘升級故事
  2. Android如何让Handler中内部run停止(runna
  3. java.net.UnknownServiceException: CLEA
  4. Android换肤功能设计与实现(5)——网络加载
  5. Android 动画系列之逐帧(Frame)动画详解
  6. android 获取定位坐标,在百度地图出现大偏
  7. Android通过Wifi来调试你的应用(转自stor
  8. Android Camer2与Camera1 自定义相机拍照
  9. Android Studio 调试过程中快捷查看断点
  10. 去抖音面试被问到硬编码与软编码区别,如何