入门教程 Android实现一个简易的新闻列表APP(TabLayout+Vie
实现一个简易的新闻列表APP(++)
文章目录 2.2 导航栏实现( + + ) 2.3 新闻列表实现 2.4 新闻具体内容实现 3. 总结
开发语言:Java
开发工具:
用到的一些控件,功能:
,(滑动切换菜单功能),,
需要的外部包:
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
注意!!!这里可能有的人版本是-v4对应的包
添加了-v4的包后发现build.( 文件夹下)有报错,
报错内容类似 28 ( for Pie and below) is the last of the
这是因为当前的AS已经不支持这些旧的包,因此可以将-v4迁移到,具体方法参考下面的文章或者自行搜索:
(174条消息) 28 ( for Pie and below) is the last of the 谷哥的小弟的博客-CSDN博客
代码的源码仓库地址为
1.实现内容以及效果
先放出最终的实现效果:
2. 实现代码 2.1 顶部菜单栏以及侧滑栏实现()
顶部菜单栏的效果如图
涉及到的配置文件:
2.1.1 导入导航栏依赖
导入”“的依赖
implementation 'com.android.support:design:29.0.1'
2.1.2 配置菜单栏布局文件
关于的各种设置,可以参考以下文章
(174条消息) 的使用详解_暗恋花香的博客-CSDN博客
设置为:
要使用,首先要去掉系统默认设置的
在.xml文件当中可以设置活动的主题,我们新建一个的主题,并且给我们需要配置的页面赋予这个主题即可
.xml
.xml
最右边是,内容设置了的背景颜色等等
配置
需要在.xml文件当中放入,因为是在首页主活动放置
.xml部分代码
<androidx.appcompat.widget.Toolbarandroid: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"/>
除了在活动布局文件中放置,还需要一个菜单图标文件
.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><itemandroid:id="@+id/tool_msg"android:icon="@drawable/share"android:orderInCategory="80"android:title="edit"app:showAsAction="ifRoom|withText" /><itemandroid:id="@+id/tool_user"android:icon="@drawable/personal"android:orderInCategory="80"android:title="share"app:showAsAction="ifRoom|withText" />
menu>
这里的配置和的menu绘制方法类似,唯一区别就是app:不同,该属性是当中很关键的属性
其中四个不同的值的作用分别如下:
1):这个值会使菜单项一直显示在 上。
2):如果有足够的空间,这个值会使菜单项显示在 Tool Bar上。
3)never:这个值会使菜单项永远都不出现在 上。
4):这个值会使菜单项和它的图标、菜单文本一起显示。一般和一起通过“|”使用
app: 属性值为 |,表示如果有空间,那么就连同文字一起显示在标题栏中,否则就显示在菜单栏中。
而当app: 属性值为 never时,该项作用为Menu不显示在菜单组件中。
这个文件后面我们会在的Java代码当中写入并且连接上
.java
myToolbar.inflateMenu(R.menu.toolbar_menu);
2.1.3 配置侧滑栏的xml布局文件
添加组件
(要使用该组件需要从外部导入包,在前面有提到导入的具体的包)
将该组件添加到所在的活动的页面当中,这里就是.xml
.xml部分代码
<androidx.drawerlayout.widget.DrawerLayoutxmlns: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.NavigationViewandroid: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>
这个菜单栏由于是侧滑出现的,所以放在整个布局的最外面,并且需要用包裹
注意看下面两个app的属性app:和app:menu
除此之外需要新建两个文件,一个是头部的代码,一个是菜单的部分
.xml
这里代码就不全部放出来了,给出效果
.xml
<menu xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/navigation_item_user"android:title="用户中心" /><itemandroid:id="@+id/navigation_item_setting"android:title="用户设置" /><itemandroid:id="@+id/navigation_item_about"android:title="关于我们" /><itemandroid:id="@+id/navigation_item_logout"android:title="注销" />
menu>
这个是菜单栏的页面,预览的效果和最终实现的效果是有差异的,不需要以预览的那个效果为准。
将和结合之后,效果图片在上面有显示。
2.1.4 Java逻辑代码实现
布局文件写好后,就是在活动当中去实现我们的点击事件,以及一些组件的连接,布局的设置其他等等。
这里对应的Java代码全部都在.java当中
和侧边栏的初始化都在的()方法当中
初始化:
.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() {@Overridepublic boolean onMenuItemClick(MenuItem item) {switch (item.getItemId()){default:Toast.makeText(MainActivity.this, "菜单栏功能尚未开发", Toast.LENGTH_SHORT).show();}return true;}});
通过()将右侧的菜单图标添加到当中。
然后设置这些图标的点击事件,只不过这里我没有去写对应的功能,要用到的话,识别item当中的id即可。
监听打开侧滑栏的按钮:
//配置侧滑栏,并且监听点击事件
myToolbar.setNavigationIcon(R.drawable.left_nav);
//打开侧滑栏的监听事件
myToolbar.setNavigationOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {drawer_layout.openDrawer(GravityCompat.START);}
});
这样就可以通过点击打开侧滑栏了。
然后是侧滑栏的按钮的监听设置
//侧滑栏里面的菜单的监听事件
NavigationView mNavigationView = findViewById(R.id.nav_view);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {@Overridepublic boolean onNavigationItemSelected(@NonNull MenuItem item) {//侧滑栏中菜单的点击事件}});
这样就完成了的代码了
注意事项!:
想让本身的生效,则必须删去以下类似代码!!!
不然会由于同时使用了导致失效
//设置侧边栏
setSupportActionBar(myToolbar);
setTitle("Top News");//设置标题名称
getSupportActionBar().setDisplayHomeAsUpEnabled(true);//设置左边home键
getSupportActionBar().setHomeAsUpIndicator(R.drawable.left_nav);//更换home键样式
2.2 导航栏实现( + + )
导航栏使用了上述三样东西结合
:提供选项切换到不同的菜单
:用于滑动切换到不同的菜单
:每个菜单显示的页面内容
涉及配置文件:
2.2.1 导入相关依赖
如果是旧版的话应当是导入-v4里面的组件,这个时候可能会出现兼容问题
2.2.2 界面配置文件
该菜单就是在首页展现的,因此所有布局文件也都在.xml当中
+控件:
<com.google.android.material.tabs.TabLayoutandroid: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.ViewPagerandroid:id="@+id/viewPager"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"/>
接着要在对应的页面的活动文件当中进行代码逻辑编写:
()
private void initViewPager() {mViewPager= (ViewPager) findViewById(R.id.viewPager);MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());mViewPager.setAdapter(myFragmentPagerAdapter);
}
初始化,这里用到了一个新的类er来初始化内容
该类需要继承,不过现在的 当中会显示该类已经被移除了,但是实际上还能用,不报错就行,不用管那个下划线,
.java
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {private String[] mTitles = new String[]{"国际", "体育", "生活","科学"};public MyFragmentPagerAdapter(FragmentManager fm) {super(fm);}//选择不同的菜单返回不同的Fragment页面@Overridepublic 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();}@Overridepublic int getCount() {return mTitles.length;}//ViewPager与TabLayout绑定后,这里获取到PageTitle就是Tab的Text@Overridepublic CharSequence getPageTitle(int position) {return mTitles[position];}
}
该类的代码也比较简短,根据需要的菜单数量,增加数组元素个数和页面的数量就行
()
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);
}
初始化的设置,先将与绑定在一起,然后设定对应的位置,最后设置图标,代码比较简单。
注意事项!:
其他xml文件的添加
这里说几个和要导入的一些其他的简短的xml文件
在.xml(或.xml)文件当中要添加style name = rance的样式
<style name="MyTabLayoutTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">- "android:textSize"
>18sp- "android:textColor"
>@color/whitestyle>
还有在文件下的 .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 新闻列表实现
涉及配置文件:
Java文件:
由于四个新闻列表页面的布局是很像的,所以这里只拿其中一个举例
菜单的布局实现后,就要说下具体怎么实现新闻的列表内容了。
这里也是相对复杂一点的内容,因为该的代码内容比较多
但是布局文件xml是比较少的,或者说都是相似的
2.3.1 布局配置文件
首先是碎片的布局
很简单,只有一个在里面
.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"><ListViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/globalList"/>
FrameLayout>
相对的其他的碎片文件也是一样
接着是list里面每个的样式该怎么实现呢?
这就要我们自己去涉及一个布局样式
.xml
这里代码较长,就只给出一个样式结合以及图片了
其他的样式例如有
2.3.2 Java代码实现与自定义新闻卡片结合
接下来是将与自定义的卡片xml文件结合到一起
最终效果如下:
.java :
首先看看代码初始化的内容
public class GlobalNewsFragment extends Fragment {private ListView lv;private ArrayList<NewsBean> mList;private View globalView;private MainActivity mainActivity;@Overridepublic 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;}
只需要一个()是类当中的函数重载,其他的函数都是自己写出来的了。
初始化的时候,获取了上面写好的配置文件.xml 。
介绍三个初始化的函数内容
至此就完成了新闻列表样式的渲染和点击事件了。
2.4 新闻具体内容实现
相关配置文件:
java代码:
该页面对应一个,实现效果如下:
点击阅读原文,实际上是将当前页面的标题和内容隐藏,然后将显示出来。
2.4.1 布局配置文件
根据页面内容可以看出,活动文件的内容应当有标题,内容,。
.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"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">
<TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:textSize="30sp"android:fontFamily="sans-serif-black"android:id="@+id/LocalTitle"/>
<Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="@color/cardview_dark_background"/>
<TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="18sp"android:id="@+id/LocalContent"/>
<WebViewandroid:id="@+id/news_webView"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="gone"/>LinearLayout>ScrollView>
LinearLayout>
这里要用到来避免由于文章内容过多而页面无法下拉的问题。
一开始的设置是不可见gone的,在运行后经过点击事件才能让其可见。
标题栏:
直接使用默认给出的
<style name="Theme.NEWSPage" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
标题当中的菜单栏
.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" ><itemandroid:id="@+id/article_open_webView"android:title="阅读原文"/><itemandroid:id="@+id/article_open_browser"android:title="用浏览器打开"/>
menu>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--12)(%E8%81%94%E6%83%B3%E6%88%AA%E5%9B%.png)]
2.4.2 Java代码实现
相关代码都在.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(){//重写这个方法解决重定向的问题@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {return false;}});webView.loadUrl(articleUrl);
}
这里都是对.xml布局的内容渲染。
代码分为三个步骤
通过()和abled()来设置顶部菜单栏左边的返回按钮。用()获取传过来的文章标题,内容和链接urls,并且给控件的内容设置相应的文本设置,加载Url链接到控件上面。(这里还需要去当中设置一下uses-和)
关于获得的数据,我在类当中写了一个()方法作为接口来接收,提供给外部想要进入这个活动并且传参。
//提供一个传入意图的接口,用来跳转活动
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);
}
这里的方法将之前写好的.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--13)(%E8%81%94%E6%83%B3%E6%88%AA%E5%9B%.png)]
至此就完成了新闻文章详情页面的所有功能了。
注意事项!!:
无法正常打开的原因(这里指已经设置了uses-的情况):
可以参考这篇博客文章,完美解决问题
(174条消息) 出现net:和net::ME错误的解决办法_飞鸭传书的博客-CSDN博客
主要原因有例如现在的版本不支持http格式的协议,因此需要在.xml当中新添加一行
<uses-permission android:name="android.permission.INTERNET"/>
<application........其他设置android:usesCleartextTraffic="true"......其他设置>
接着会出现网页能够加载一下,然后就又发生了错误,这次提示net::ME错误,这里是重定向的问题
解决方法是重写 ding( view, url) 方法
webView.setWebViewClient(new WebViewClient(){@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {return false;}
});
或者采用上面博客给出的更加多判断的方法,可以对更多类型的页面的重定向进行判断
3. 总结
最后来说一下总结吧
本次可以说是安卓课上第一次做一个比较像App的实验了,之前的几次实验和作业也只是实现了一些简单的样式或者功能,而这次不仅要实现功能,UI也要进行一定的设计和美化。
个人认为工作量还是比较大的了,花费的时间也比较多,虽然最后做出来的功能其实并没有很多,但是因为是第一次做这种体量的安卓项目。
相比于以往接触到的小程序开发,web开发,给人最大的不同就是需要配置大量的布局文件。在当中,并不需要编写像html,css这样的文件去渲染页面,而是需要用xml文件来展现布局的页面内容,也并没有这样的语言去对前端的样式,数据逻辑进行处理,而是靠Java语言来编写一个叫做活动()的东西,将数据连接到一起。