美文网首页
使用compose+paging3+jsoup实现双色球数据分页

使用compose+paging3+jsoup实现双色球数据分页

作者: 随心随弈走 | 来源:发表于2021-04-09 21:47 被阅读0次

    双色球走势图是比较大的,图表可拖动可缩放是很硬性的要求,而我在实现这个功能时又遇到了很大的困难,不过最终还是完成了,所以在此重新记录一下。
    1,首先在google官网中找到在compose中实施拖动和缩放动作的代码
    2,套用在这篇文章中:Compose+Paging3+Retrofit实现列表分页加载
    下面重新贴上主要的相关代码
        implementation "dev.chrisbanes.accompanist:accompanist-coil:0.6.0"//coil
        implementation 'org.jsoup:jsoup:1.13.1' //jsoup
        implementation "androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha02"
        implementation "androidx.paging:paging-runtime:3.0.0-beta02"
        implementation "androidx.paging:paging-compose:1.0.0-alpha08"
    

    LotteryActivity

    class LotteryActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
               LeftModeScreen()
            }
        }
    }
    

    LotteryViewModel

    class LotteryViewModel: ViewModel() {
        val lotterys = Pager(PagingConfig(pageSize = 50)){
            LotteryPagingSource(LotteryRepository)
        }.flow.cachedIn(viewModelScope)
    }
    
    

    LotteryData

    data class Lottery(
        val code :String,   //开奖号码
        val issue :String,//期号
    ) : Serializable
    

    LotteryRepository

    object LotteryRepository {
    
        private const val TARGET_URL = "https://datachart.500.com/ssq/history/newinc/history.php"
    
        suspend fun getLotterys(page: Int): MutableStateFlow<List<Lottery>> {
    
            val lotterys = MutableStateFlow<List<Lottery>>(listOf())
            val lotteryList: MutableList<Lottery> = mutableListOf()
    
            withContext(Dispatchers.IO) {
                val doc =
                    //"https://datachart.500.com/ssq/history/newinc/history.php?start=21001&end=21200"
                    Jsoup.connect(TARGET_URL + "?start=${page}001&end=${page}200").get()
                val element: Element = doc.getElementById("tdata")
                val elements: Elements = element.select("tr.t_tr1")
                elements.forEach { item ->
                    val aaa: Elements = item.select("td")
                    if (!aaa.isNullOrEmpty()) {
                        val bbb = Lottery(
                            code = aaa[1].text() + "," +
                                    aaa[2].text() + "," +
                                    aaa[3].text() + "," +
                                    aaa[4].text() + "," +
                                    aaa[5].text() + "," +
                                    aaa[6].text() + "  " +
                                    aaa[7].text(),
                            issue = aaa[0].text()
                        )
                        lotteryList.add(bbb)
                    }
                }
                lotterys.value = lotteryList
            }
            return lotterys
        }
    }
    

    LotteryPagingSource

    class LotteryPagingSource(private val repository: LotteryRepository) :
        PagingSource<Int, Lottery>() {
    
        private val year = TimeUtils.nowTime.substring(2, 4).toInt()//取年份最后两位 (2021 => 21)
    
        override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Lottery> {
            return try {
                val page = params.key ?: year//一个年份的开奖数据为一页
                val response = repository.getLotterys(page)
                LoadResult.Page(
                    data = response.value,
                    prevKey = null,
                    nextKey = if (page > 3) page - 1 else null//"3"为2003年,双色球从2003年开始的,
                )
            } catch (e: Exception) {
                LoadResult.Error(e)
            }
        }
    
        override fun getRefreshKey(state: PagingState<Int, Lottery>): Int? {
            return null
        }
    }
    

    TimeUitls

    object TimeUtils {
    
        val nowTime: String
            get() {
                val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.CHINESE)
                val date = Date(System.currentTimeMillis())
                return simpleDateFormat.format(date)
            }
    }
    

    下面是一些与compose相关的页面代码,由于添加了手势动作和数据加载错误处理,代码比较多,这里就不一一贴出来了,只贴主要的,部分缺少的可以在文章开头的那篇文章中找到,还有一些找不到的就自己实现吧。这是一个进行中的项目,代码根据需要随时在变化。
    Compose+Paging3+Retrofit实现列表分页加载

    @Composable
    fun LeftModeScreen() {
        val showPop = remember { mutableStateOf(false) }
        Row(modifier = Modifier.fillMaxSize()) {
            LeftMenuColumn(showPop)//左侧菜单栏
            SaleTrasformable{ LotteryList() }//右侧走势图,可拖动,可缩放
        }
        if (showPop.value) {
            HandModePop(showPop)//切换左右手模式
        }
    }
    
    //使组件可拖动、缩放和旋转
    @Composable
    fun SaleTrasformable(
        content: @Composable () -> Unit
    ) {
        val offsetX = remember { mutableStateOf(0f) }
        val offsetY = remember { mutableStateOf(0f) }
        var width by remember { mutableStateOf(0f) }
        val scale = remember { mutableStateOf(1f) }
        val rotation = remember { mutableStateOf(0f) }
        val offset = remember { mutableStateOf(Offset.Zero) }
        val state = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
            scale.value *= zoomChange//缩放
            offset.value += offsetChange//拖动
            // rotation.value += rotationChange//旋转
        }
        Column(
            modifier = Modifier
                .wrapContentWidth()
                // .background(Color(34, 43, 44, 50))
                .clipToBounds() //放大缩小时,内容限定在这个Column内
                .graphicsLayer(
                    scaleX = scale.value,
                    scaleY = scale.value,
                    // rotationZ = rotation.value,
                    translationX = offset.value.x,
                    translationY = offset.value.y
                )
                .transformable(state = state)
                .onSizeChanged { width = it.width.toFloat() }
                .offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
                .pointerInput(Unit) {
                    forEachGesture {
                        awaitPointerEventScope {
                            val down = awaitFirstDown()
                            val change =
                                awaitHorizontalTouchSlopOrCancellation(down.id) { change, over ->
                                    val originalX = offsetX.value
                                    val newValue =
                                        (originalX + over).coerceIn(0f, width - 50.dp.toPx())
                                    change.consumePositionChange()
                                    offsetX.value = newValue
                                }
                            if (change != null) {
                                horizontalDrag(change.id) {
                                    val originalX = offsetX.value
                                    val newValue = (originalX + it.positionChange().x)
                                        .coerceIn(0f, width - 50.dp.toPx())
                                    it.consumePositionChange()
                                    offsetX.value = newValue
                                }
                            }
                        }
                    }
                }
        ) {
            content()//内容过多,用这种方式可另起一个Composable
        }
    }
    
    //妥善处理数据加载过程中的各种异常
    @Composable
    fun LotteryList(viewModel: LotteryViewModel = viewModel()) {
    
        val lotterys = viewModel.lotterys.collectAsLazyPagingItems()
    
        when (lotterys.loadState.refresh) {
            is LoadState.NotLoading -> //正常加载数据
                LazyColumn(
                    Modifier.fillMaxSize(),
                    reverseLayout = true//反转数据
                ) {
                    itemsIndexed(lotterys) { _, lottery ->
                        LotteryItem(lottery = lottery!!)
                    }
                    when (lotterys.loadState.append) {//划到了数据边界
                        is LoadState.Error -> item {//没取不到新数据,重试
                            Row(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .padding(8.dp),
                                verticalAlignment = Alignment.CenterVertically,
                                horizontalArrangement = Arrangement.Center,
                            ) {
                                Button(onClick = {
                                    lotterys.retry()
                                }) {
                                    Text(text = "重试")
                                }
                            }
                        }
                        is LoadState.Loading -> item {//加载中
                            LoadingPage()
                        }
                    }
                }
            is LoadState.Error -> ErrorPage { lotterys.refresh() }//网络错误
            is LoadState.Loading -> LoadingPage()//加载中
        }
    }
    
    //将数据的各个字段填入到相应的组件中
    @Composable
    fun LotteryItem(lottery: Lottery) {
       // DrawCanvas()
        Box(
            modifier = Modifier
                .padding(start = 16.dp, top = 8.dp, bottom = 8.dp)
            //.clickable(onClick = {})
        ) {
            Row(modifier = Modifier.fillMaxWidth()) {
                Column(
                    modifier = Modifier.padding(start = 8.dp)
                ) {
                    Text(
                        lottery.code,//开奖号码
                        style = TextStyle(color = Color.Black, fontSize = 16.sp),
                        modifier = Modifier.padding(end = 8.dp),
                        maxLines = 1
                    )
                }
                Column(
                    modifier = Modifier.padding(start = 8.dp)
                ) {
                    Text(
                        lottery.issue,//期号
                        style = TextStyle(color = Color.Black, fontSize = 16.sp),
                        modifier = Modifier.padding(end = 8.dp),
                        maxLines = 1
                    )
                }
            }
        }
    }
    
    

    最后,再一次特别的感谢这篇文章的作者,《Compose+Paging3+Retrofit实现列表分页加载》,正是因为它的及时出现,我又可以愉快地进行下一步的代码编写了,感觉离我的设想越来越近了,也越来越相信那个设想是我力所能及的。

    相关文章

      网友评论

          本文标题:使用compose+paging3+jsoup实现双色球数据分页

          本文链接:https://www.haomeiwen.com/subject/vvewkltx.html