Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)

文章目录

  • Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)
    • 1.实现内容以及效果
    • 2. 实现代码
      • 2.1 顶部菜单栏以及侧滑栏实现(Toolbar)
        • 2.1.1 导入导航栏依赖
        • 2.1.2 配置toolbar菜单栏布局文件
        • 2.1.3 配置侧滑栏的xml布局文件
        • 2.1.4 Java逻辑代码实现
      • 2.2 导航栏实现(TabLayout + ViewPager + Fragment)
        • 2.2.1 导入相关依赖
        • 2.2.2 界面配置文件
      • 2.3 新闻列表实现
        • 2.3.1 布局配置文件
        • 2.3.2 Java代码实现listView与自定义新闻卡片结合
      • 2.4 新闻具体内容实现
        • 2.4.1 布局配置文件
        • 2.4.2 Java代码实现
    • 3. 总结

开发语言:Java

开发工具:Android Studio

用到的一些控件,功能:

Tablayout,ViewPager(滑动切换菜单功能),Navigation,ToolBar

需要的外部包

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;

注意!!!这里可能有的人版本是support-v4对应的包

添加了support-v4的包后发现build.gradle(Gradle Scripts文件夹下)有报错,

报错内容类似Version 28 (intended for Android Pie and below) is the last version of the legacy support library

这是因为当前的AS已经不支持这些旧的包,因此可以将support-v4迁移到AndroidX,具体方法参考下面的文章或者自行搜索:

(174条消息) Version 28 (intended for Android Pie and below) is the last version of the legacy support library_谷哥的小弟的博客-CSDN博客

代码的源码仓库地址为

https://github.com/Cheesheep/AndroidExp2-NEWSApp

1.实现内容以及效果

先放出最终的实现效果

  • 首页是国际新闻列表,总共有四个菜单

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第1张图片

  • 可以通过滑动或点击切换到其他菜单,可以看到不同页面的列表有一定的差异

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第2张图片

  • 点击查看其中一篇文章,可以看到本地是加载了一篇纯文本的内容

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第3张图片

  • 点击右上角的菜单列表,有另外两种查看该文章的方式,选择阅读原文

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第4张图片

    接着在app内显示出原文所在的网页

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第5张图片

    再次点击右上角菜单可以选择重新显示本地的文章

    如果选择浏览器打开,就会跳转到浏览器并且显示该网页

  • 回到主页面,左划或者点击左上角即可显示滑动菜单栏

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第6张图片

    打开后这里放了一些个人页面的信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4nWF9Sk9-1683948018508)(https://gitee.com/cheesheep/typora-photo-bed/raw/master/Timg/%E8%81%94%E6%83%B3%E6%88%AA%E5%9B%BE_20230422153131.png)]

    不过菜单上面的功能都没有实现,只是做了样式,包括顶部的分享和个人页面按钮也是

2. 实现代码

2.1 顶部菜单栏以及侧滑栏实现(Toolbar)

顶部菜单栏的效果如图

image-20230422164518062

涉及到的配置文件:

  • activity_main.xml :主活动页面

  • toolbar_menu:菜单栏图标(右侧的分享和个人页面的logo)

  • nav_header,xml :侧滑栏的头部信息(头像,昵称,联系方式)

  • left_drawer.xml:侧滑栏的菜单内容

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RVdj73Lq-1683948018509)(https://gitee.com/cheesheep/typora-photo-bed/raw/master/Timg/联想截图_20230422153131.png)]

    侧滑栏如上

  • Java活动文件:

    MainActivity.java :全部逻辑功能代码都在该活动当中

2.1.1 导入导航栏依赖

导入”NavigationView“的依赖

implementation 'com.android.support:design:29.0.1'

2.1.2 配置toolbar菜单栏布局文件

关于toolbar的各种设置,可以参考以下文章

(174条消息) Android Toolbar的使用详解_暗恋花香的博客-CSDN博客

设置为NoActionBar

要使用toolbar,首先要去掉系统默认设置的ActionBar

在AndroidManifest.xml文件当中可以设置活动的主题,我们新建一个NoActionBar的主题,并且给我们需要配置toolBar的页面赋予这个主题即可

AndroidManifest.xml

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第7张图片

themes.xml

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第8张图片

最右边是noActionBar,内容设置了toolbar的背景颜色等等

配置toolBar

需要在activity_main.xml文件当中放入toolBar,因为是在首页主活动放置toolBar

activity_main.xml部分代码


    <androidx.appcompat.widget.Toolbar
        android:id="@+id/my_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:titleTextColor="@color/white"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

除了在活动布局文件中放置toolbar,还需要一个菜单图标文件

toolbar_menu.xml


<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/tool_msg"
        android:icon="@drawable/share"
        android:orderInCategory="80"
        android:title="edit"
        app:showAsAction="ifRoom|withText" />
    <item
        android:id="@+id/tool_user"
        android:icon="@drawable/personal"
        android:orderInCategory="80"
        android:title="share"
        app:showAsAction="ifRoom|withText" />

menu>

这里的配置和actionBar的menu绘制方法类似,唯一区别就是app:showAsAction不同,该属性是Toolbar当中很关键的属性

其中四个不同的值的作用分别如下:

1)always:这个值会使菜单项一直显示在 ToolBar上。
2)ifRoom:如果有足够的空间,这个值会使菜单项显示在 Tool Bar上。
3)never:这个值会使菜单项永远都不出现在 ToolBar上。
4)withText:这个值会使菜单项和它的图标、菜单文本一起显示。一般和ifRoom一起通过“|”使用
app:showAsAction 属性值为 ifRoom|withText,表示如果有空间,那么就连同文字一起显示在标题栏中,否则就显示在菜单栏中。
而当app:showAsAction 属性值为 never时,该项作用为Menu不显示在菜单组件中。

这个文件后面我们会在activity的Java代码当中写入并且连接上

MainActivity.java

myToolbar.inflateMenu(R.menu.toolbar_menu);

2.1.3 配置侧滑栏的xml布局文件

添加NavigationView组件

(要使用该组件需要从外部导入design包,在前面有提到导入的具体的包)

将该组件添加到toolbar所在的活动的页面当中,这里就是activity_main.xml

activity_main.xml部分代码


<androidx.drawerlayout.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    --------
    这里是该页面的其他布局文件,可以将整个布局文件代码放进去也是可以的
    
    --------
    

<com.google.android.material.navigation.NavigationView
    android:id="@+id/nav_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="@color/colorPrimary"
    app:headerLayout="@layout/nav_header"
    app:menu="@menu/left_drawer" />
androidx.drawerlayout.widget.DrawerLayout>

这个菜单栏由于是侧滑出现的,所以放在整个布局的最外面,并且需要用DrawerLayout包裹

注意看下面两个app的属性app:headerLayoutapp:menu

除此之外需要新建两个文件,一个是头部的代码,一个是菜单的部分

nav_header.xml

这里代码就不全部放出来了,给出效果

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第9张图片

left_drawer.xml


<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:id="@+id/navigation_item_user"
            android:title="用户中心" />
        <item
            android:id="@+id/navigation_item_setting"
            android:title="用户设置" />
        <item
            android:id="@+id/navigation_item_about"
            android:title="关于我们" />
        <item
            android:id="@+id/navigation_item_logout"
            android:title="注销" />
menu>

这个是菜单栏的页面,预览的效果和最终实现的效果是有差异的,不需要以预览的那个效果为准。

将nav_header和left_drawer结合之后,效果图片在上面有显示。

2.1.4 Java逻辑代码实现

布局文件写好后,就是在Activity活动当中去实现我们的点击事件,以及一些组件的连接,布局的设置其他等等。

这里对应的Java代码全部都在MainActivity.java当中

ToolBar和侧边栏的初始化都在MainActivity的initToolBarView()方法当中

初始化Toolbar

MainActivity.java

private void initToolBarView() {
    Toolbar myToolbar = findViewById(R.id.my_toolbar);
    drawer_layout = findViewById(R.id.drawer_layout);
    //将图标菜单文件添加到toolbar当中
    myToolbar.inflateMenu(R.menu.toolbar_menu);
    myToolbar.setTitle("Hello News");
    //ToolBar的菜单的点击事件
    myToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            switch (item.getItemId()){
                default:
                    Toast.makeText(MainActivity.this, "菜单栏功能尚未开发", Toast.LENGTH_SHORT).show();
            }
            return true;
        }
    });

通过inflateMenu()将右侧的菜单图标添加到toolbar当中。

然后设置这些图标的点击事件,只不过这里我没有去写对应的功能,要用到的话,识别item当中的id即可。

监听打开侧滑栏的按钮

//配置侧滑栏,并且监听点击事件
myToolbar.setNavigationIcon(R.drawable.left_nav);
//打开侧滑栏的监听事件
myToolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        drawer_layout.openDrawer(GravityCompat.START);
    }
});

这样就可以通过点击打开侧滑栏了。

然后是侧滑栏的按钮的监听设置

//侧滑栏里面的菜单的监听事件
NavigationView mNavigationView = findViewById(R.id.nav_view);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        //侧滑栏中菜单的点击事件
    }

});

这样就完成了toolbar的代码了


注意事项!:

想让Toolbar本身的inflateMenu生效,则必须删去以下类似代码!!!

不然会由于同时使用了ActionBar导致失效

 //设置侧边栏
setSupportActionBar(myToolbar);
setTitle("Top News");//设置标题名称
getSupportActionBar().setDisplayHomeAsUpEnabled(true);//设置左边home键
getSupportActionBar().setHomeAsUpIndicator(R.drawable.left_nav);//更换home键样式

2.2 导航栏实现(TabLayout + ViewPager + Fragment)

导航栏使用了上述三样东西结合

TabLayout:提供选项切换到不同的菜单

ViewPager:用于滑动切换到不同的菜单

Fragment:每个菜单显示的页面内容

涉及配置文件

  • activity_main.xml
  • selected.xml (选中菜单的颜色设置)
  • themes.xml (设置菜单的文件大小)

2.2.1 导入相关依赖

如果是旧版的话应当是导入support-v4里面的组件,这个时候可能会出现兼容问题

2.2.2 界面配置文件

该菜单就是在首页展现的,因此所有布局文件也都在activity_main.xml当中

Tablayout+ViewPager控件


    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        app:tabIndicatorColor="#ffffff"
        app:tabIndicatorHeight="5dp"
        app:tabTextColor="@color/white"
        app:tabIconTint="@color/white"
        app:tabSelectedTextColor="@color/white"
        app:tabMode="fixed"
        app:tabBackground="@drawable/selected"
        app:tabTextAppearance="@style/MyTabLayoutTextAppearance"
        />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

接着要在对应的页面的活动文件当中进行代码逻辑编写:

initViewPager()

private void initViewPager() {
    mViewPager= (ViewPager) findViewById(R.id.viewPager);
    MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
    mViewPager.setAdapter(myFragmentPagerAdapter);
}

初始化viewPager,这里用到了一个新的类myFragmentPagerAdapter来初始化内容

该类需要继承FragmentPagerAdapter,不过现在的android studio当中会显示该类已经被移除了,但是实际上还能用,不报错就行,不用管那个下划线,

FragmentPagerAdapter.java

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    private String[] mTitles = new String[]{"国际", "体育", "生活","科学"};
    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }
    //选择不同的菜单返回不同的Fragment页面
    @Override
    public Fragment getItem(int position) {
        if (position == 1) {
            return new SportNewsFragment();
        } else if (position == 2) {
            return new LifeNewsFragment();
        }else if (position==3){
            return new ScienceNewsFragment();
        }
        return new GlobalNewsFragment();
    }
    @Override
    public int getCount() {return mTitles.length;}

    //ViewPager与TabLayout绑定后,这里获取到PageTitle就是Tab的Text
    @Override
    public CharSequence getPageTitle(int position) {return mTitles[position];}
}

该类的代码也比较简短,根据需要的菜单数量,增加String数组元素个数和页面Fragment的数量就行

initTabLayoutView()

private void initTabLayoutView() {
    //将TabLayout与ViewPager绑定在一起
    TabLayout mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
    mTabLayout.setupWithViewPager(mViewPager);

    //指定Tab的位置
    TabLayout.Tab one = mTabLayout.getTabAt(0);
    TabLayout.Tab two = mTabLayout.getTabAt(1);
    TabLayout.Tab three = mTabLayout.getTabAt(2);
    TabLayout.Tab four = mTabLayout.getTabAt(3);

    //设置Tab的图标,假如不需要则把下面的代码删去
    one.setIcon(R.drawable.global);
    two.setIcon(R.drawable.soccer);
    three.setIcon(R.drawable.life);
    four.setIcon(R.drawable.science);
}

初始化TabLayout的设置,先将viewPager与TabLayout绑定在一起,然后设定对应的位置,最后设置图标,代码比较简单。

注意事项!:

其他xml文件的添加

这里说几个tablayout和viewPager要导入的一些其他的简短的xml文件

image-20230423002236907

themes.xml(或styles.xml)文件当中要添加style name = MyTabLayoutTextAppearance的样式


    <style name="MyTabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
        "android:textSize">18sp
        "android:textColor">@color/white
    style>

还有在drawable文件下的 selected.xml,用于展示被选中下菜单的颜色


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@color/TabBackGround"/>
    <item android:drawable="@color/colorAccent"/>
selector>

2.3 新闻列表实现

涉及配置文件

  • fragment_global_news.xml 以及类似的四个文件(都是只有一个ListView)
  • listView_item.xml以及相关的三种卡片布局

Java文件

  • GlobalNewsFragment.java (新闻列表的显示页面)
  • NewsUtils.java (存放新闻的数据,例如标题,内容,url)
  • NewsBean.java 新闻类(含标题,内容等)

由于四个新闻列表页面的布局是很像的,所以这里只拿其中一个举例

菜单的布局实现后,就要说下具体怎么实现新闻的列表内容了。

这里也是相对复杂一点的内容,因为该Fragment的代码内容比较多

但是布局文件xml是比较少的,或者说都是相似的

2.3.1 布局配置文件

首先是Fragment碎片的布局

很简单,只有一个ListView在里面

fragment_global_news.xml


<FrameLayout 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=".newsListPage.GlobalNewsFragment">
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/globalList"
        />
FrameLayout>

相对的其他的碎片文件也是一样

接着是list里面每个的样式该怎么实现呢?

这就要我们自己去涉及一个布局样式

listview_item.xml

这里代码较长,就只给出一个样式结合以及图片了

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第10张图片

其他的样式例如有

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第11张图片

2.3.2 Java代码实现listView与自定义新闻卡片结合

接下来是将listView与自定义的卡片xml文件结合到一起

最终效果如下:

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第12张图片

GlobalNewsFragment.java

首先看看代码初始化的内容

public class GlobalNewsFragment extends Fragment {
    private ListView lv;
    private ArrayList<NewsBean> mList;
    private View globalView;
    private MainActivity mainActivity;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 获取view,并且连接到主活动上面
        globalView = inflater.inflate(R.layout.fragment_global_news, container, false);
        mainActivity =(MainActivity) getActivity();
        initUI();
        initData();
        initAdapter();
        return globalView;
    }

只需要一个onCreateVIew()是Fragment类当中的函数重载,其他的函数都是自己写出来的了。

初始化globalVIew的时候,获取了上面写好的配置文件fragment_global_news.xml

介绍三个初始化的函数内容

  • initUI()

    监听列表每个item的点击事件

    private void initUI() {
        lv = (ListView) globalView.findViewById(R.id.globalList);
        //设置点击事件监听
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //跳转到显示文章内容的活动
                NewsBean bean = mList.get(position); 		         NewsArticleContentActivity.actionStart(mainActivity,bean.title,bean.news_content,bean.news_url);
            }
        });
    }
    

    这里就是对每个列表的新闻卡片做了一个点击监听的事件,通过Intent跳转到文章的详情页面,经典的活动之间的跳转方法,不阐述了。

    listView的获取连接了之前写的xml文件globalList.xml当中

    该意图已经封装好一个方法,只需要传固定的参数即可,分别是标题,内容,还有url链接。

    文章的详情页面用一个Activity来实现,下一小节会讲到。

  • initData()

    private void initData() {
        mList = NewsUtils.getGlobalNews(mainActivity);
    }
    

    这里只调用了一个函数。

    功能是将数据存到mList当中,方便后面用适配器Adapter调用

    来看下NewsUtils类里面是怎么获取数据的

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第13张图片

    代码内容是比较简单直接的,虽然这里可以使用数据库的方式会更高效。

    MewsBean里面的内容也只有简单的几个成员数据而已。

    NewsBean

    public class NewsBean {
        public String title;
        public String des;
        public Drawable icon;
        public String news_url;
        public String news_content;
    }
    
  • initAdapter()

    一行代码

    private void initAdapter() {
        lv.setAdapter(new GlobalNewsFragment.NewsAdapter());
    }
    

    setAdapter()方法是官方提供的,而里面的NewsAdapter()则需要我们去自定义实现

    NewsAdpter类

    private class NewsAdapter extends BaseAdapter {
        //适配器处理新闻列表
        @Override
        public int getCount() {
            return mList.size();
        }
        @Override
        public NewsBean getItem(int position) {
            return mList.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            GlobalNewsFragment.ViewHolder holder;
            if (convertView == null) {//获取卡片的具体内容
                holder = new GlobalNewsFragment.ViewHolder();
                convertView = View.inflate(mainActivity.getApplicationContext(), R.layout.listview_item, null);
                holder.tv_title = (TextView) convertView.findViewById(R.id.tv_title);
                holder.tv_des = (TextView) convertView.findViewById(R.id.tv_des);
                holder.iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon);
                convertView.setTag(holder);
            } else {
                holder = (GlobalNewsFragment.ViewHolder) convertView.getTag();
            }
            NewsBean item = getItem(position);
            holder.tv_title.setText(item.title);
            holder.tv_des.setText(item.des);
            holder.iv_icon.setImageDrawable(item.icon);
            return convertView;
        }
    }
    

    该类继承了BaseAdapter,并对四个基本的方法进行了重载。

    前面的三个都比较简单,根据名字就可以知道该方法调用的是一些基本的参数,例如获得列表当中的item等等。

    最后的getView()比较长,主要是将数据传递到view布局上面

    该方法可以看到调用了listview_item.xml文件,想要不同的卡片样式,这里可以选中不同的布局文件。

    Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第14张图片

    holder类(直接定义在当前的Fragment类里面就行)

    private static class ViewHolder {
        TextView tv_title;
        TextView tv_des;
        ImageView iv_icon;
    }
    

至此就完成了新闻列表样式的渲染和点击事件了。

2.4 新闻具体内容实现

相关配置文件

  • activity_news_article_content.xml
  • article_open_browser.xml (设置右上角菜单内容)

java代码

  • NewsArticleContentActivity.java

该页面对应一个Activity,实现效果如下:

Android实现一个简易的新闻列表APP(TabLayout+ViewPager+Fragment)_第15张图片

点击阅读原文,实际上是将当前页面的标题和内容隐藏,然后将webView显示出来。

2.4.1 布局配置文件

根据页面内容可以看出,活动文件的内容应当有标题,内容,webView。

activity_news_article_content.xml


<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=".NewsArticleContentActivity">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="30sp"
                android:fontFamily="sans-serif-black"
                android:id="@+id/LocalTitle"/>

            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="@color/cardview_dark_background"
                />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:id="@+id/LocalContent"/>

            <WebView
                android:id="@+id/news_webView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="gone"
                />
        LinearLayout>
    ScrollView>

LinearLayout>

这里要用到scorllView来避免由于文章内容过多而页面无法下拉的问题。

一开始的WebView设置是不可见gone的,在运行后经过点击事件才能让其可见。

标题栏

直接使用默认给出的actionBar

<style name="Theme.NEWSPage" parent="Theme.MaterialComponents.DayNight.DarkActionBar">

标题当中的菜单栏

article_open_browser.xml


<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/article_open_webView"
        android:title="阅读原文"/>
    <item
        android:id="@+id/article_open_browser"
        android:title="用浏览器打开"/>
menu>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-txfrVbhX-1683948018512)(https://gitee.com/cheesheep/typora-photo-bed/raw/master/Timg/%E8%81%94%E6%83%B3%E6%88%AA%E5%9B%BE_20230423013518.png)]

2.4.2 Java代码实现

相关代码都在NewsArticleContentActivity.java当中实现

首先看看初始化这个活动的时候用到的代码

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_news_article_content);
    //设置标题栏内容
    ActionBar actionBar = getSupportActionBar();
    if(actionBar != null){
        setTitle("Article");
        actionBar.setHomeButtonEnabled(true);//设置左上角是否可以点击
        actionBar.setDisplayHomeAsUpEnabled(true);//添加返回的图标
    }
    //设置文章内容
    String newsTitle = getIntent().getStringExtra("news_title");
    String newsContent = getIntent().getStringExtra("news_content");
    articleUrl = getIntent().getStringExtra("news_url");
    title = findViewById(R.id.LocalTitle);
    content = findViewById(R.id.LocalContent);
    title.setText(newsTitle);
    content.setText(newsContent);
    //设置webView内容
    isArticleDisplayed = true;//从新闻列表进入文章的时候默认标志位为真
    webView = findViewById(R.id.news_webView);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebViewClient(new WebViewClient(){
        //重写这个方法解决重定向的问题
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return false;
        }
    });
    webView.loadUrl(articleUrl);
}

这里都是对activity_news_article_content.xml布局的内容渲染。

代码分为三个步骤

  1. 通过setHomeBUttonEnabled()setDisplayHomeAsUpEnabled()来设置顶部菜单栏左边的返回按钮。
  2. getIntent()获取传过来的文章标题,内容和链接urls,并且给控件的内容设置相应的文本
  3. 设置WebView,加载Url链接到WebView控件上面。(这里还需要去AndroidManifest当中设置一下uses-permission和usesClearText)

关于getIntent获得的数据,我在NewsArticleContentActivity类当中写了一个actionStart()方法作为接口来接收Intent,提供给外部想要进入这个活动并且传参。

//提供一个传入意图的接口,用来跳转活动
public static void actionStart(Context context,String newsTitle,String newsContent,String newsUrl){
    Intent intent = new Intent(context,NewsArticleContentActivity.class);
    intent.putExtra("news_title",newsTitle);
    intent.putExtra("news_content",newsContent);
    intent.putExtra("news_url",newsUrl);
    context.startActivity(intent);
}

创建右侧的顶部菜单栏

//重写顶部菜单栏构造方法
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.article_open_browser,menu);
    return super.onCreateOptionsMenu(menu);
}

这里的方法将之前写好的article_open_browser.xml放到menu当中

最后是重写这个菜单里面的点击触发事件,代码如下

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            //设置返回按钮事件
            finish();
            return true;
        case R.id.article_open_browser:
            //设置浏览器打开事件
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(articleUrl));//跳转到网页
            startActivity(intent);
            return true;
        case R.id.article_open_webView:
            //设置显示的显示网页内容
            if(isArticleDisplayed){
                title.setVisibility(View.GONE);
                content.setVisibility(View.GONE);
                webView.setVisibility(View.VISIBLE);
                item.setTitle("本地文章");
            }else {
                title.setVisibility(View.VISIBLE);
                content.setVisibility(View.VISIBLE);
                webView.setVisibility(View.GONE);
                item.setTitle("嵌入网页");
            }
            isArticleDisplayed = !isArticleDisplayed;
            return true;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}

分别对返回键,显示网页内容,和跳转浏览器三个按键做了点击响应

对应下图的三个图标:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzwPV83b-1683948018513)(https://gitee.com/cheesheep/typora-photo-bed/raw/master/Timg/%E8%81%94%E6%83%B3%E6%88%AA%E5%9B%BE_20230423091235.png)]

至此就完成了新闻文章详情页面的所有功能了。

注意事项!!:

webview无法正常打开的原因(这里指已经设置了uses-permission的情况):

可以参考这篇博客文章,完美解决问题

(174条消息) WebView出现net:ERR_CLEARTEXT_NOT_PERMITTED和net::ERR_UNKNOWN_URL_SCHEME错误的解决办法_飞鸭传书的博客-CSDN博客

主要原因有例如现在的版本不支持http格式的协议,因此需要在AndroidManifest.xml当中新添加一行


<uses-permission android:name="android.permission.INTERNET"/>
<application
   ........其他设置
    android:usesCleartextTraffic="true"
   ......其他设置
    >

接着会出现网页能够加载一下,然后就又发生了错误,这次提示net::ERR_UNKNOWN_URL_SCHEME错误,这里是重定向的问题

解决方法是重写 shouldOverrideUrlLoading(WebView view, String url) 方法

webView.setWebViewClient(new WebViewClient(){
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }
});
  • return true 表示当前url即使是重定向url也不会再执行(除了在return true之前使用webview.loadUrl(url)除外,因为这个会重新加载)

  • return false 表示由系统执行url,直到不再执行此方法,即加载完重定向的ur(即具体的url,不再有重定向)。

或者采用上面博客给出的更加多判断的方法,可以对更多类型的页面的重定向进行判断


3. 总结

最后来说一下总结吧

本次可以说是安卓课上第一次做一个比较像App的实验了,之前的几次实验和作业也只是实现了一些简单的样式或者功能,而这次不仅要实现功能,UI也要进行一定的设计和美化。

个人认为工作量还是比较大的了,花费的时间也比较多,虽然最后做出来的功能其实并没有很多,但是因为是第一次做这种体量的安卓项目。

相比于以往接触到的小程序开发,web开发,android给人最大的不同就是需要配置大量的布局文件。在android当中,并不需要编写像html,css这样的文件去渲染页面,而是需要用xml文件来展现布局的页面内容,也并没有JavaScript这样的语言去对前端的样式,数据逻辑进行处理,而是靠Java语言来编写一个叫做活动(Activity)的东西,将数据连接到一起。
ndroid.permission.INTERNET"/>
…其他设置
android:usesCleartextTraffic=“true”
…其他设置
>


接着会出现网页能够加载一下,然后就又发生了错误,这次提示`net::ERR_UNKNOWN_URL_SCHEME错误`,这里是重定向的问题

解决方法是重写 `shouldOverrideUrlLoading(WebView view, String url)` 方法

webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
});


- `return true` 表示当前url即使是重定向url也不会再执行(除了在return true之前使用webview.loadUrl(url)除外,因为这个会重新加载)

- `return false` 表示由系统执行url,直到不再执行此方法,即加载完重定向的ur(即具体的url,不再有重定向)。

或者采用上面博客给出的更加多判断的方法,可以对更多类型的页面的重定向进行判断



---

## 3. 总结

最后来说一下总结吧

本次可以说是安卓课上第一次做一个比较像App的实验了,之前的几次实验和作业也只是实现了一些简单的样式或者功能,而这次不仅要实现功能,UI也要进行一定的设计和美化。

个人认为工作量还是比较大的了,花费的时间也比较多,虽然最后做出来的功能其实并没有很多,但是因为是第一次做这种体量的安卓项目。

相比于以往接触到的小程序开发,web开发,android给人最大的不同就是需要配置大量的布局文件。在android当中,并不需要编写像html,css这样的文件去渲染页面,而是需要用xml文件来展现布局的页面内容,也并没有JavaScript这样的语言去对前端的样式,数据逻辑进行处理,而是靠Java语言来编写一个叫做活动(Activity)的东西,将数据连接到一起。

你可能感兴趣的:(android,android,studio,gradle,java,前端)