Android Compose 新闻App网络图片加载TabHorizontalPager
Posted 初学者-Study
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Compose 新闻App网络图片加载TabHorizontalPager相关的知识,希望对你有一定的参考价值。
android Compose 新闻App(七)网络图片加载、Tab、HorizontalPager
前言
在上一篇文章中,新增加了一个主页面,那么这个主页面用来做什么呢?主页面的底部我分为两个部分,目前是首页和收藏,首页需要显示好几个类型的新闻数据,那么我们先来做这一步,本文效果图如下:
正文
首先我们需要申请API,在天行API中申请如下图所示的API接口.
鉴于五个不同的数据类型,我们就需要五个接口。
一、申请API
首先从社会新闻这个接口开始,我们通过测试请求,然后就能拿到此接口的返回值,通过这个返回值我们生成一个数据类,在bean包下新建一个News类,代码如下:
data class News(val msg: String = "",
val code: Int = 0,
val newslist: List<Newslist>)
data class Newslist(val picUrl: String = "",
val ctime: String = "",
val description: String = "",
val id: String = "",
val source: String = "",
val title: String = "",
val url: String = "")
现在数据有了,下面我们就现在HomeItem.kt中显示数据。显示数据也得一步一步来,首先。
① 增加服务接口
首先在ApiService中添加getSocialNews()函数,代码如下:
/**
* 获取社会新闻
*/
@GET("/social/index?key=$API_KEY")
fun getSocialNews(): Call<News>
然后在NetworkRequest中增加getSocialNews()函数,代码如下:
//获取社会新闻
suspend fun getSocialNews() = service.getSocialNews().await()
② HomeRepository
现在我们还没有HomeRepository的,在repository中新增HomeRepository,代码如下:
@ViewModelScoped
class HomeRepository @Inject constructor() : BaseRepository()
/**
* 获取社会新闻
*/
fun getSocialNews() = fire(Dispatchers.IO)
val news = NetworkRequest.getSocialNews()
if (news.code == CODE) Result.success(news)
else Result.failure(RuntimeException("getNews response code is $news.code msg is $news.msg"))
这个方法就是调用NetworkRequest中的getSocialNews()函数,这在前面的文章中你可能见到过。那么下一个就是创建ViewModel,与HomeItem相对应的就是HomeViewModel。
③ HomeViewModel
在viewmodel包下中新增一个HomeViewModel,里面的代码如下:
@HiltViewModel
class HomeViewModel @Inject constructor(repository: HomeRepository) :ViewModel ()
val result = repository.getSocialNews()
然后在页面上我们需要一层一层的传递。通常我们Activity和ViewModel是绑定,之前我们在HomeActivity中创建了一个MainViewModel,然后我们在HomeActivity中再加一个HomeViewModel,代码如下:
val homeViewModel: HomeViewModel = viewModel()
同样我们需要在导航到HomePage中时增加导航控制器和homeViewModel,如下图所示:
下面我们更改HomePage()函数中的参数,如下图所示:
这里又把参数传递到HomeItem中,下面我们再修改一下HomeItem中的代码,如下所示:
@Composable
fun HomeItem(mNavController: NavHostController, viewModel: HomeViewModel)
val dataState = viewModel.result.observeAsState()
dataState.value?.let
ShowNewsList(mNavController,it.getOrNull()!!.newslist)
@Composable
fun ShowNewsList(mNavController: NavHostController, newslist: List<Newslist>)
LazyColumn(
state = rememberLazyListState(),
modifier = Modifier.padding(8.dp)
)
items(newslist) new ->
Log.d("TAG", "ShowNewsList: $Gson().toJson(new)")
Column(modifier = Modifier
.clickable
val encodedUrl = URLEncoder.encode(new.url, StandardCharsets.UTF_8.toString())
mNavController.navigate("$PageConstant.WEB_VIEW_PAGE/$new.title/$encodedUrl")
.padding(8.dp))
Text(
text = new.title,
fontWeight = FontWeight.ExtraBold,
fontSize = 16.sp,
modifier = Modifier.padding(0.dp, 10.dp)
)
Text(text = new.description, fontSize = 12.sp)
Text(text = new.ctime, fontSize = 12.sp)
Divider(
modifier = Modifier.padding(horizontal = 8.dp),
color = colorResource(id = R.color.black).copy(alpha = 0.08f)
)
下面我们运行一下:
这里的数据就显示出来了,通过日志打印我看到有一个图片Url。
然后如果我们要通过图片Url显示图片要怎么做呢?
二、网络图片加载
之前在Android的开发你肯定是了解过Glide框架的,那么现在在Compose中使用Coli库,这个库有什么优点呢?
Coil 是一个 Android 图片加载库,通过 Kotlin 协程的方式加载图片。使用它需要添加依赖,在app的build.gradle的dependencies闭包,代码如下:
//Coil库
implementation 'io.coil-kt:coil-compose:2.0.0-rc03'
然后我们需要修改一下之前的item,因为要添加一个图片,所以在Column的外部再添加一个Row,代码如下:
Row(modifier = Modifier
.clickable
val encodedUrl = URLEncoder.encode(new.url, StandardCharsets.UTF_8.toString())
mNavController.navigate("$PageConstant.WEB_VIEW_PAGE/$new.title/$encodedUrl")
.padding(8.dp)
)
AsyncImage(
model = new.picUrl,
contentDescription = null,
modifier = Modifier
.width(120.dp)
.height(80.dp),
contentScale = ContentScale.FillBounds
)
Column(modifier = Modifier.padding(8.dp,0.dp,0.dp,0.dp))
Text(
text = new.title,
fontWeight = FontWeight.ExtraBold,
fontSize = 16.sp
)
Row(modifier = Modifier.padding(0.dp, 10.dp))
Text(text = new.source, fontSize = 12.sp)
Text(
text = new.ctime,
fontSize = 12.sp,
modifier = Modifier.padding(8.dp, 0.dp)
)
这里的图片使用AsyncImage,而不是Image,在这个控件里面增加图片的加载地址,然后修改一下图片的宽高和占满边界,注意一下上面这段代码添加的位置,如下图所示:
下面我们运行一下:
三、BottomBar遮挡
我们尝试一下把这个列表滑动到页面底部看看。
可以看到这里的BottomBar遮挡住客了这个列表的最后一项,那么怎么解决这个问题呢?其实很简单,一行代码解决问题。
navigationBarsPadding()
在HomeItem中增加,如下图所示:
这样就可以解决了。
四、Tab + HorizontalPager
这里的Tab是已经有了,但是要使用HorizontalPager还需要添加依赖,在app的build.gradle的dependencies闭包中添加如下依赖:
//viewpage
implementation "com.google.accompanist:accompanist-pager:$accompanist_version"
//viewpage指示器
implementation "com.google.accompanist:accompanist-pager-indicators:$accompanist_version"
使用的话我们用一个函数来表示,在HomeItem中新增一个TabViewPager函数,代码如下:
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalPagerApi::class)
@Composable
private fun TabViewPager()
Column(modifier = Modifier.fillMaxSize())
val pages by mutableStateOf(
listOf("社会", "军事", "科技", "财经", "娱乐")
)
val pagerState = rememberPagerState(initialPage = 0)//初始化页面,0就表示第一个页面
TabRow(
selectedTabIndex = pagerState.currentPage,
// 使用提供的 pagerTabIndicatorOffset 修饰符自定义指示器
indicator = tabPositions ->
TabRowDefaults.Indicator(
Modifier.pagerTabIndicatorOffset(pagerState, tabPositions)
)
,
backgroundColor = colorResource(id = R.color.white),
contentColor = colorResource(id = R.color.black)
)
//给全部页面添加标签栏
pages.forEachIndexed index, title ->
Tab(
text = Text(title) ,
selected = pagerState.currentPage == index,//是否选中
onClick =
CoroutineScope(Dispatchers.Main).launch
pagerState.scrollToPage(index)
,
modifier = Modifier.alpha(0.9f),//透明度
enabled = true,//是否启用
selectedContentColor = colorResource(id = R.color.black),//选中的颜色
unselectedContentColor = colorResource(id = R.color.gray),//未选中的颜色
)
HorizontalPager(
count = pages.size,
state = pagerState,//用于控制或观察viewpage状态的状态对象。
modifier = Modifier.padding(top = 4.dp),
itemSpacing = 2.dp
) page ->
Column(modifier = Modifier.fillMaxSize())
Text(
text = "Page: $page",
modifier = Modifier.fillMaxWidth()
)
你不熟悉的只是控件使用而已,里面的参数用几次就都会了,下面在HomeItem中调用此函数。
运行一下,看看效果:
五、修改页面
现在五个页面的内容就只有一个Text,下面我们设置第一个页面为之前写的社会新闻数据,这里首先我们要确定一个事情,那就参数要传递进入TabViewPager函数,如下图所示修改:
然后就是修改页面的显示内容,代码如下:
val dataState = viewModel.result.observeAsState()
when(page)
0 -> dataState.value?.let
ShowNewsList(mNavController, it.getOrNull()!!.newslist)
else ->
Column(modifier = Modifier.fillMaxSize())
Text(
text = "Page: $page",
modifier = Modifier.fillMaxWidth()
)
这里当页面为第一个页面时,我们现实社会新闻数据,其他页面就和之前一样显示页面下标,代码添加位置如下图所示:
还有一个地方要注意,那就是之前我们在ShowNewsList函数中设置的navigationBarsPadding(),挪到TabViewPager函数中,如下图所示:
上面的代码在电脑虚拟机和真机上运行效果不一样,因此我将naviationBarsPadding改成了.padding(0.dp, 0.dp, 0.dp, 50.dp),这个我就不截图了,下面运行一下:
下面我们再运行一下:
六、源码
如果你觉得代码对你有帮助的话,不妨Fork或者Star一下~
GitHub:GoodNews
CSDN:GoodNews_7.rar
以上是关于Android Compose 新闻App网络图片加载TabHorizontalPager的主要内容,如果未能解决你的问题,请参考以下文章
Android Compose 新闻App网络图片加载TabHorizontalPager
Android Compose 新闻App网络数据Compose UI显示加载Room和DataStore使用
Android Compose 新闻App网络数据Compose UI显示加载Room和DataStore使用