Fragment
手机和平板屏幕尺寸不同,容易导致在手机上可正常使用的界面,在平板上被过度拉扯
Fragment是一种可以嵌入在activity中的UI片段,它能让程序更加充分利用大屏幕
例:按之前学到的知识来说,点击新闻n跳转到新闻n的详情页,是一个activity跳转到另一个activity,当这样的行为发生在平板上时可能会导致标题和内容被过度拉伸,出现大量空白区域。现可将标题和内容分别做成两个Fragment放入详情页的activity中
Fragment的简单使用
- 设计Fragement的xml文件,跟以前一样
- 创建Fragment子类,加载上一步创建的布局
- 在需要插入的activity中添加fragment标签,并引入fragment布局
//与之前学习的布局一样
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="24sp"
android:text="This is right fragment"
/>
</LinearLayout>
//加载设计好的布局
class LeftFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.left_fragment, container, false)
}
}
//在需要插入的activity布局添加fragment标签,并填入完整包名
<fragment
android:id="@+id/leftFrag"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
动态载入Fragment
不同点在于将fragment标签换为framelayout标签(应该换成其他布局也可以)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
//通过按钮动态载入
replaceFragment(AnotherRightFragment())
}
replaceFragment(RightFragment())
}
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = supportFragmentManager
//开启事务
val transaction = fragmentManager.beginTransaction()
//可添加/替换Fragment,传入容器id(布局id)和待添加的fragemnt实例
transaction.replace(R.id.rightLayout, fragment)
//提交事务
transaction.commit()
}
}
在fragment中实现返回栈
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.rightLayout, fragment)
//接受一个名字描述栈的状态,一般为null
transaction.addToBackStack(null)
transaction.commit()
}
Fragment和activity的交互
即互相可调用自己的方法
//activity访问fragment里的方法
//从布局里面获取fragment实例
val fragment = supportFragmentManager.findFragmentById(R.id.leftFrag) as LeftFragment
//插件也支持findFragmentById()
val fragment = leftFrag as LeftFragment
//fragment访问activity里的方法
//此处隐含getActivity(),获取的是context对象
val activity = activity
if(activity!=null){
val mainActivity = activity as MainActivity
}
Fragment的生命周期
- 运行状态:当一个fragment关联的activity处于运行状态时,该fragment也处于运行状态。
- 暂停状态:当一个activity进入暂停状态时,与它关联的fragment就会进入暂停状态。
- 停止状态:当一个activity进入停止状态时,与它相关联的fragment就会进入停止状态,与其关联的fragment就会进入停止状态或者通过调用。FragmentTransacton()的remove()、replace()方法将fragment从activity中移除,且事务提交前调用了addToBackStack(),此时fragment也会进入停止状态。处于停止状态的fragment是对用户不可见的,甚至可能会被系统回收。
- 销毁状态:fragment总是依附于activity而存在,因此当activity被销毁时,依附的fragment就会进入销毁状态。或者通过调用FragmentTransaction的remove、replace方法将fragment从activity中移除,且事务提交前没有调用addToBackStack()方法,这时的fragment也会进入销毁状态。
Fragment的回调方法
activity有的,fragment基本都有,还有自己附加了一些回调方法
- onAttach():当fragment和activity建立关联时调用
- onCreateView():为fragment创建视图(加载布局)时调用
- onActivityCreated():确保与fragment相关联的activity已经创建完毕时调用
- onDestroyView():与fragment关联的视图被移除时调用
- onDetach():当fragment和activity解除关联时调用
- 启动程序后,fragment被加载到屏幕上,依次执行
- onAttach()、
- onCreate()、
- onCreateView()、
- onActivityCreated()、
- onStart()、
- onResume()。
- 当前fragment被替换,进入停止状态
- onPause()
- onStop()
- onDestroyView()
若事务提交时没有调用addToBackStack()方法,fragment进入销毁状态,执行以下方法 - onDestroy()
- onDetach()
- 按back,返回fragment
- onCreateView()
- onActivityCreated()
- onStart()
- onResume()
- 退出程序时
- onPause()
- onStop()
- onDestroyView()
- onDestroy()
- onDettach()
动态加载布局的技巧
使用限定符
平板一般比手机多个功能,就是分页,一屏两页,因此需要为这些设备设计特别的布局
如:large,专供大屏幕设备
在res下创建layout-large文件夹,并创建为平板设计的布局,布局取同名activity,即手机上能正常显示的activity名,在此处取同名,表示当用平板打开activity时,打开这个特别版。
- 最小宽度限定符 sw,layout_sw600dp//activity_main,即当设备屏幕宽度大于600时运行此activity
拓展函数
kotlin十分支持拓展函数,因此可以学习下,kotlin的拓展函数带有面向对象的思想,不再是面向对象的写出单独函数,而是向类中写入函数,丰富api
如计算字符串中的字母数量
可以将其写入string类中
创建与类名相同的.kt文件 String.kt
//包名,方法名
fun String.lettersCount(): Int {
var count = 0
for (char in this) {
if (char.isLetter()) {
count++
}
}
return count
}
- 运算符重载
class Money(val value: Int) {
//operaor为关键字
operator fun plus(money: Money): Money {
val sum = value + money.value
return Money(sum)
}
operator fun plus(newValue: Int): Money {
val sum = value + newValue
return Money(sum)
}
通过对照表,重载对应函数即可