Android Compose 新闻App(六)导航动画、WebView、浮动按钮、底部导航
- 前言
- 正文
- 一、导航动画
- ① 添加依赖
- ② 使用
- 二、WebView使用
- ① 导航传递URL参数
- ② 配置WebView
- 三、FloatingActionButton使用
- ① 修改默认显示位置
- 四、App主页面构建
- ① 密封类
- ② 构建底部导航Item
- ③ 装载底部导航Item
- ④ 显示导航
- 五、源码
- 一、导航动画
前言
在上篇文章中完成了页面的导航,而在本篇文章中将会有更多新的Compose用法,一起来看看吧。
正文
一些应用有一些花里花哨的操作就会让人眼前一亮,大部分花里胡哨的操作就是动画,那么作为Compose的导航也是可以使用动画的,下面我们来使用一下:
一、导航动画
① 添加依赖
导航动画是需要一个依赖库的,在app的build.gradle的dependencies{}闭包中中增加如下代码:
代码语言:javascript复制 //Navigation动画
implementation "com.google.accompanist:accompanist-navigation-animation:$accompanist_version"
这里的accompanist_version在之前的文章中已经定义好了,accompanist_version = ‘0.24.4-alpha’。
② 使用
使用之前我们先来看一下要更改的地方,如下图所示:
图中是上一篇文章中所写的代码,如果要使导航有动画效果,则需要换一下。换了之后如下图所示:
对应的包名就是这三个:
代码语言:javascript复制import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.composable
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
这里动画分为四种模式
enterTransition :进入当前页面的动画。 exitTransition:退出当前页面的动画。 popEnterTransition:当前页面在另一个页面弹出后重新出现的动画。 popExitTransition:当前页面弹出栈后隐藏时的动画。
这些动画可以直接设置在NavHost中,下面我们设置一下:
下面我们运行一下:
可以看到当前页面进入到详情页面有动画效果,而返回之前的页面时也是这个动画效果,两者一样,我们再试试其他的动画。
这里用的是展开和收缩动画,然后我们在动画中增加一个动画时间,都是500毫秒,下面我们运行一下看看效果:
下面我们再尝试一个滑动动画。
运行一下:
这些动画效果要多去尝试,才可以的。找一个自己觉得喜欢的就行了,这个滑动的效果就不错,不是那么花里胡哨同样又能提高用户的体验。
二、WebView使用
做过常规应用开发的对WebView肯定不陌生,甚至有的H5页面居多的App,全靠WebView来操作,那么在Compose中怎么去使用WebView呢?这是一个值得去探究的问题,我们结合到当前App的实际情况来看。
① 导航传递URL参数
当前的App中有两个页面,疫情新闻页面和风险区详情页面,那么我们需要再写一个WebView的加载页面,可以让我们去加载Url。在pages包下,新建一个WebViewPage.kt文件,里面的代码如下:
代码语言:javascript复制@Composable
fun WebViewPage(navController: NavHostController, title: String, url: String){
Scaffold(
topBar = {
//顶部应用栏
TopAppBar(
title = {
Text(
text = title,
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colors.onSecondary,
overflow = TextOverflow.Ellipsis, //超出省略
maxLines = 1 //单行显示
)
},
navigationIcon = {
IconButton(onClick = { navController.popBackStack() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "ArrowBack"
)
}
},
elevation = 4.dp
)
}
) {
AndroidView(factory = { context ->
val webView = WebView(context)
webView.settings.javaScriptEnabled = true
webView.settings.javaScriptCanOpenWindowsAutomatically = true
webView.settings.domStorageEnabled = true
webView.settings.loadsImagesAutomatically = true
webView.settings.mediaPlaybackRequiresUserGesture = false
webView.webViewClient = WebViewClient()
webView.loadUrl(url)
webView
})
}
}
此函数参数有三个,navController,title,url。着重讲一下WebView的使用,Compose中目前并没有WebView的直接使用,因为我们的WebView还是Android的原生WebView,没有经过Compose的封装,而如果要在Compose中使用原生的Android控件,则就需要通过AndroidView来加载。
然后我们在PageConstant中增加一个WEB_VIEW_PAGE,如下图所示:
下面我们在HomeActivity中添加一个composable用来设置WebView页面,如下图所示:
然后是设置点击跳转的地方,如下图中所示:
这里的列表数据中的new中是有url的,因此我们几点将title和url传递过去,在EpidemicNewsListPage中添加如下图所示的代码。
记得clickable要添加,下面我们运行一下,看能不能跳转过去。
真是世事难料啊,没想到会报错,报错的原因就是url的问题,如果我们将Url作为参数传递,那么需要对url做一个处理,如下图所示:
下面我们再运行一次:
加载就完成了。
② 配置WebView
我们同样可以检测Url加载的进度。
在WebViewPage函数中添加如下代码:
代码语言:javascript复制 val mWebViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
Log.d("webView", "加载开始")
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
Log.d("webViewT", "加载完成")
}
}
val mWebViewChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
Log.d("webView", "加载:$newProgress")
super.onProgressChanged(view, newProgress)
}
}
然后再修改一下AndroidView中的内容,如下图所示:
最终位置如下图所示:
运行一下:
嗯,OK。
三、FloatingActionButton使用
浮动按钮在日常开发中,也是很常见的,下面在我们的EpidemicNewsListPage中添加一个浮动按钮。 因为页面使用了Scaffold,因此可以直接通过Scaffold去添加浮动按钮。
添加浮动按钮的同时,我把TopAppBar中多余的内容清除掉了,下面我们运行一下:
点击时弹出Toast,默认显示在页面的右下角。
那如果要改位置呢?
① 修改默认显示位置
就两个参数,默认就是End。
当然了,上面说的是在Scaffold,如果你要换一个地方显示呢?那就按照之前写常规布局那样,用Column然后使用Box做层叠就好了。这里我们还是改成End。
代码语言:javascript复制floatingActionButtonPosition = FabPosition.End
这里疫情详情页面已经是写完了,你会看到当前页面中有一个浮动按钮,那么这个按钮就是用来返回主页面的,App现在还没有主页面的,下面我们来构建主页面。
四、App主页面构建
在pages包下新建一个HomePage.kt文件,里面的代码如下:
代码语言:javascript复制@Composable
fun HomePage(navController: NavHostController) {
Scaffold(
topBar = {
//顶部应用栏
TopAppBar(
title = {
Text(
text = stringResource(id = R.string.app_name),
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colors.onSecondary,
overflow = TextOverflow.Ellipsis, //超出省略
maxLines = 1, //单行显示
textAlign = TextAlign.Center
)
}
)
}
) {
}
}
然后在PageConstant中增加一个
代码语言:javascript复制const val HOME_PAGE = "homePage"
再回到HomeActivity中。
将第一个启动的页面改成HomePage,再运行之后如下图所示。
在这里我们将进行页面的导航。
① 密封类
首先我们在app的build.gradle的dependencies{}闭包中添加如下依赖:
代码语言:javascript复制 //图标库
implementation "androidx.compose.material:material-icons-extended:$compose_version"
Sync Now,这是一个图标库,后面我们将用到它。
下面构建一个密封类,在utils包下新建一个BottomItemScreen,代码如下:
代码语言:javascript复制/**
* 定义路线名称,底部标题和图标
*/
sealed class BottomItemScreen(val route: String, val title: String, val icon: ImageVector){
object HOME: BottomItemScreen(HOME_ITEM,"首页", Icons.Default.Home)
object STAR: BottomItemScreen(COLLECTION_ITEM,"收藏", Icons.Default.Favorite)
}
② 构建底部导航Item
在ui包下新建一个BottomBarView.kt,里面的代码如下:
代码语言:javascript复制@Composable
fun BottomBarView(navController: NavController) {
val navItem = listOf(
BottomItemScreen.HOME,
BottomItemScreen.STAR
)
val navBackStackEntry by navController.currentBackStackEntryAsState()
//当前路线
val currentRoute = navBackStackEntry?.destination?.route
BottomAppBar {
navItem.forEach {
BottomNavigationItem(
label = { Text(text = it.title) },//设置item标签
icon = { Icon(imageVector = it.icon, contentDescription = it.title)},//设置item图标
selectedContentColor = Color.White,//选中时颜色
unselectedContentColor = colorResource(id = R.color.gray),//未选中时颜色
selected = currentRoute == it.route,//选中时赋值
onClick = {
//点击时根据,选中了不同items,则先赋值,在进行路线导航,导航后保存状态,
navController.navigate(it.route){
popUpTo(navController.graph.findStartDestination().id){
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
这个可组合函数就是构建底部导航的ItemView,然后我们在PageConstant中定义主页中的两个子页面的描述
代码语言:javascript复制 const val HOME_ITEM = "home"
const val COLLECTION_ITEM = "collection"
下面我们回到HomePage.kt中,主页面中修改代码如下:
③ 装载底部导航Item
代码语言:javascript复制@Composable
fun HomePage() {
val navController = rememberAnimatedNavController()
Scaffold(
topBar = {
//顶部应用栏
TopAppBar(
title = {
Text(
text = stringResource(id = R.string.app_name),
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colors.onSecondary,
overflow = TextOverflow.Ellipsis, //超出省略
maxLines = 1, //单行显示
textAlign = TextAlign.Center
)
}
)
},
modifier = Modifier.fillMaxSize(),
bottomBar = {
BottomBarView(navController)
}
) {
AnimatedNavHost(
navController = navController,
startDestination = HOME_ITEM,
enterTransition = {
slideInHorizontally(
initialOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
)
},
exitTransition = {
slideOutHorizontally(
targetOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(500)
)
},
popEnterTransition = {
slideInHorizontally(
initialOffsetX = { fullWidth -> -fullWidth },
animationSpec = tween(500)
)
},
popExitTransition = {
slideOutHorizontally(
targetOffsetX = { fullWidth -> fullWidth },
animationSpec = tween(500)
)
}
) {
composable(HOME_ITEM) {
HomeItem()
}
composable(COLLECTION_ITEM) {
CollectionItem()
}
}
}
}
这里关键的代码如下图标注所示:
主要就是在Scaffold中增加了一个bottomBar,然后设置AnimatedNavHost,这和前面的内容相似。
④ 显示导航
那么现在我们还需要新建两个Item,在pages包下新建一个HomeItem.kt
代码语言:javascript复制@Composable
fun HomeItem() {
Text(text = "Home")
}
再新建一个CollectionItem.kt
代码语言:javascript复制@Composable
fun CollectionItem() {
Text(text = "Collection")
}
现在该有的就都有了,下面我们运行一下:
下一篇将会增加一个抽屉,然后在抽屉中增加疫情新闻的入口。
五、源码
如果你觉得代码对你有帮助的话,不妨Fork或者Star一下~ GitHub:GoodNews CSDN:GoodNews_6.rar