游戏页面排完版了
接下来就建立下方蓝色的分页吧
分页的功能在swift内叫 Tab Bar Controller
我们先把他拉进画面
此时我们会看到预设的Tab Bar 有预设了两个画面
不需要留情~ 删掉那两个画面
接下来按住control後从 Tab Bar Controller
拉到 游戏画面
同时将游戏画面
左边的小箭头
拉到 Tab Bar Controller
上
这个小箭头代表程序进入的第一个View
然後我们点选 Tab Bar Controller
设定一下属性
属性 | 对齐 | 设定 |
---|---|---|
Image Tint | 无 | System Orange Collor |
Bar Tint | 无 | System Teal Color |
Background | 无 | System Teal Color |
回到 游戏画面 点选下方的 Bar Item
设定Title为游戏, image为 gamecontroller
此时画面多了Bar Item 因此游戏页面
下方白色区块需要推高一点
点选gameFootrt的Autolayout设定
将Bottom -> BottomOf Parent
的设定多推40
接下来在拉一个 Table View Controller页面
来显示游戏纪录
设定Bar Item的Title为 游戏纪录
然後两大页面完成
接下来打算点选游戏纪录时
会开启一个View来显示游戏纪录详情
於是我们在拉一个View Controller
被设定背景为 System Yellow Color
还後新增三个Label
如图片显示文字
AutoLayout都是距离边框20
这边就不再详细说明了
下一步我们按着 control
从游戏纪录
画面拉到 纪录详情
画面
然後点选show
此时会建立一条 Segue
来达到换页的效果
此时点选两个页面中的 Segue
并给他一个ID "showDetail"
经过一系列设定
关於画面Tab分页的设定就都完成搂!
至於 纪录详情
页面如何进入
下个章节再来说明
kotlin 也提供了一种导航框架
来处理分页问题
只是稍微复杂一点点
我们往下看吧
以下是使用Safe Args前
需要先知道的知识点
我们现在想要的画面是
下方有两颗分页按钮
分别可到 游戏画面
与 游戏纪录
画面
同时游戏纪录又
可以点击
跳到游戏详情
画面
整理一下吧
元件名称 | 数量 | 说明 |
---|---|---|
Active | 1 | 最外层包一切 |
NavHostFragment | 1 | 挂载在Active内, 用来显示Fragment |
BottomNavigationView | 1 | 挂载在Active内, 用来切换Fragment |
Navigation Graph | 1 | 设定页面导航 |
Menu | 1 | 设定按钮选单 |
Fragment | 3 | 游戏页, 游戏纪录, 纪录详情 |
准备开始动手
首先安装依赖
先到顶级build.gradle(Project:chick_bb)
dependencies {
...
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5"
...
}
在到应用级build.gradle(Module:chick_bb.app)
plugins {
...
id 'androidx.navigation.safeargs.kotlin'
...
}
dependencies {
...
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
...
}
然後SYNCK 同步完成後
就可以往下搂~
Android所需步骤多又繁杂
看清楚搂
首先在res内新增一个资料夹叫menu
再menu内新增一个menu File叫 menu_bottom_nav
进入 menu_bottom_nav 从上方拉入两个Menu item
设定如下
属性 | 值 |
---|---|
icon | @android:drawable/ic_menu_myplaces |
id | gameFragment |
title | 游戏 |
属性 | 值 |
---|---|
icon | @android:drawable/ic_menu_day |
id | historyFragment |
title | 纪录 |
第一个重点来了!!
导航要顺利关联的重点在id
接下来menu
, Navigation Graph
, Fragment
的id
全都要一样, 才能完成导航喔
接下来回到 active_main.xml
新增NavHostFragment
与BottomNavigationView
在添加 NavHostFragment
会跳出画面
要你选择 Navigation Graph
理所当然的~我们不会有
那就来新增吧
点选左上的+ 并新增
命名为 nav_graph
此时回产生一个nav_graph 点选OK
此时进入 res/navigation/nav_graph
此画面可建立导航地图
点选上方的+图示
选择create new destination
接下来就产生 Fragment 了
我们先分别产生 GameFragment
与 HistoryFragment
此时会产生四个档案
GameFragment.kt
HistoryFragment.kt
fragment_game.xml
fragment_history.xml
nav_graph 内会出现两个画面
有房子的是预设第一个显示的 Fragment
请依序将他们两个的id设定为 gameFragment
与 historyFragment
并进入fragment_game.xml
与fragment_history.xml
将最外层的 FrameLayout转成 ConstraintLayout
接下来将
fragment_game.xml
最外层 id 设定成 gameFragment
fragment_history.xml
最外层 id 设定成 historyFragment
此时确认一下
menu
, Navigation Graph
, Fragment
的id
都要一样
此时回到active_main.xml 检查一下
并设定 NavHostFragment
与BottomNavigationView
元件
nav_host_fragment(NavHostFragment)
属性 | 对齐 | 设定 |
---|---|---|
id | 无 | nav_host_fragment |
name | 无 | androidx.navigation.fragment.NavHostFragment |
layout_width | 无 | 0dp |
layout_height | 无 | 0dp |
defaultNavHost | 无 | true |
navGraph | 无 | @navigation/nav_graph |
Start -> StartOf | parent | 0dp |
End -> EndOf | parent | 0dp |
Top -> TopOf | parent | 0dp |
Bottom -> BottomOf | bottom_nav | 0dp |
bottom_nav(BottomNavigationView)
属性 | 对齐 | 设定 | |
---|---|---|---|
id | 无 | bottom_nav | |
layout_width | 无 | 0dp | |
layout_height | 无 | 50dp | |
menu | 无 | @menu/menu_bottom_nav | |
Start -> StartOf | parent | 0dp | |
End -> EndOf | parent | 0dp | |
Bottom -> BottomOf | parent | 0dp |
画面设定好了
接下来必须把 bottom_nav 导航的功能
绑定到 nav_host_fragment 上面
进入 MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 绑定 bottom_nav 与 nav_host_fragment
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
findViewById<BottomNavigationView>(R.id.bottom_nav)
.setupWithNavController(navController)
}
这样就完成绑定搂
接下来搬移画面与资料
进入 active_main.xml
切换到 code模式
将除了 nav_host_fragment
与 bottom_nav
之外的元件剪下
通通贴到 fragment_game.xml 内
进入 MainActive 将动画的方法复制到 GameFragment
这边带入一个 Fragment 知识点
Fragment 实际上是 active的一个片段
所以动画程序中的 findViewById
是不能使用的
甚至在Fragment 也是没有 view 可以直接使用的
竟然这样 我就来顺便来开启
Android 一个很方便的功能 view binding
首先进入 build.gradle 有 .app的那个
加入
buildFeatures {
viewBinding true
}
接着进入另一个 build.gradle
於dependencies加入
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5"
填入後画面右上方会出现 Sync Now 点下去让他同步
回到 GameFragment 预设 Fragment模板上
有一些我们暂时不需要的程序
我们来将程序修改一下
package com.test.chickbb
import android.animation.Keyframe
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.test.chickbb.databinding.FragmentGameBinding
class GameFragment : Fragment() {
// FragmentGameBinding 是自动产生的类别 用来绑定视图
private var _binding: FragmentGameBinding? = null
// FragmentGameBinding 预设下有可能是null ,
// 透过这个get 方便在正确取资料时 不用加上问号
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentGameBinding.inflate(inflater, container, false)
// 执行动画
setChickAnimation()
return binding.root
}
override fun onDestroy() {
super.onDestroy()
// 离开画面要移除参照
_binding = null
}
fun setChickAnimation() {
// translationX
val pvhtranslationX = PropertyValuesHolder.ofKeyframe("translationX",
Keyframe.ofFloat(0f, 0f),
Keyframe.ofFloat(.1f, -33f),
Keyframe.ofFloat(.2f, -66f),
Keyframe.ofFloat(.3f, -99f),
Keyframe.ofFloat(.4f, -66f),
Keyframe.ofFloat(.5f, -33f),
Keyframe.ofFloat(.6f, 0f),
Keyframe.ofFloat(.7f, 40f),
Keyframe.ofFloat(.8f, 100f),
Keyframe.ofFloat(.9f, 40f),
Keyframe.ofFloat(1f, 0f)
)
// translationY
val pvhtranslationY = PropertyValuesHolder.ofKeyframe("translationY",
Keyframe.ofFloat(0f, 0f),
Keyframe.ofFloat(.1f, -20f),
Keyframe.ofFloat(.2f, 0f),
Keyframe.ofFloat(.3f, -20f),
Keyframe.ofFloat(.4f, 0f),
Keyframe.ofFloat(.5f, -20f),
Keyframe.ofFloat(.6f, 0f),
Keyframe.ofFloat(.7f, -20f),
Keyframe.ofFloat(.8f, 0f),
Keyframe.ofFloat(.9f, -20f),
Keyframe.ofFloat(1f, 0f)
)
// rotation
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation",
Keyframe.ofFloat(0f, 10f),
Keyframe.ofFloat(.1f, -10f),
Keyframe.ofFloat(.2f, 10f),
Keyframe.ofFloat(.3f, -10f),
Keyframe.ofFloat(.4f, 10f),
Keyframe.ofFloat(.5f, -10f),
Keyframe.ofFloat(.6f, 10f),
Keyframe.ofFloat(.7f, -10f),
Keyframe.ofFloat(.8f, 10f),
Keyframe.ofFloat(.9f, -10f),
Keyframe.ofFloat(1f, 10f)
)
// scaleX
val pvhScaledBy = PropertyValuesHolder.ofKeyframe("scaleX",
Keyframe.ofFloat(0f, 1f),
Keyframe.ofFloat(.1f, 1f),
Keyframe.ofFloat(.2f, 1f),
Keyframe.ofFloat(.3f, 1f),
Keyframe.ofFloat(.4f, -1f),
Keyframe.ofFloat(.5f, -1f),
Keyframe.ofFloat(.6f, -1f),
Keyframe.ofFloat(.7f, -1f),
Keyframe.ofFloat(.8f, -1f),
Keyframe.ofFloat(.9f, 1f),
Keyframe.ofFloat(1f, 1f)
)
// 透过 binding 取得 ggView
val ggView = binding.ggView
// 设定 ggView 关键影格
ObjectAnimator.ofPropertyValuesHolder(ggView,
pvhtranslationY,
pvhtranslationX,
pvhRotation,
pvhScaledBy).apply {
duration = 4000 // 动画持续四秒
repeatCount = ObjectAnimator.INFINITE // 无限重播
start() // 开始播放
}
}
}
Fragment与Active 生命徵期略有不同
要特别注意一下
取元件的方法也修改成 binding.ggView
到这边 原本动画应该可以执行
而且下方换页也应该要正常搂
目前Fragment 只有两个
差最後一个
我们进入 Navigation Graph
新增一个 showDetailFragment
然後在 historyFragment 右边有个蓝点点
从 historyFragment 拉到 showDetailFragment
整个导航地图将会变成这样
完成~ 接下来开始写游戏搂
这样代表可以在 historyFragment 里面
透过某个方法跳页到 showDetailFragment
这样整个tab暂时先设定完成了
到tab分页这边开始
开始感受到Swift与Kotlin之间比较明显的差异了
Swift整个功能是准备好的
你只要拉到画面上 稍微设定一下就完成了
Kotlin要设定很多东西
主要是很多小细节 只要漏了
功能就会无法运作
但最终达成的效果几乎是一样的
只是差在开发其顺不顺手而已
今天篇幅大爆炸!
累死我了/︿\
铁人赛进入的23天
在一周後就不用天天发文了
怎麽突然感觉....有点空虚 ( ・◇・)?
哇赛!我找虐啊!!
自虐啊我~
算了加油加油~剩下最後一周
冲刺!
<<: Day 16:Next 布景客制化 - 让副标题显示於标题内
当广告跑一阵子後,你可以会对於名词有点困惑,它们各别代表什麽意思呢? 今天就来做比较深入的了解,这样...
大家都怎麽藏电脑里的秘密档案呢? 最多人用的方法应该是设隐藏资料夹吧! 但是这个方法已经深植人心,改...
「灵异现象」 Windows SMB 用 Domain name 能通,用 IP 不能通 灵异现象系...
看完这篇文章你会得到的成果图 前言 这篇我们要来学一个新的东西 QProgressBar! QPro...
透过前面的内容大家知道表格空间是一个抽象的概念,对系统表格空间来说,对应着档案系统中一个或多个档案;...