Android Compose 新闻App(六)导航动画、WebView、浮动按钮、底部导航

2022-05-03 11:37:40 浏览数 (1)

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

0 人点赞