第五章 探究Fragment

159 阅读2分钟

第五章 探究Fragment

  1. 添加Fragment

    1. XML中添加

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="horizontal"
          tools:context=".chapter5.FragmentActivity">
      
          <fragment
              android:id="@+id/leftFragment"
              android:name="com.youngly.firstlineofcode.chapter5.LeftFragment"
              android:layout_width="0dp"
              android:layout_height="match_parent"
              android:layout_weight="1" />
      
          <FrameLayout
              android:id="@+id/right_layout"
              android:layout_width="0dp"
              android:layout_height="match_parent"
              android:layout_weight="2" />
      
      </LinearLayout>
      
    2. 动态添加

      class FragmentActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_fragment)
      
              replaceFragment(RightFragment.newInstance())
          }
      
          fun changeFragment(view: View) {
              replaceFragment(AnotherRightFragment.newInstance())
          }
      
          private fun replaceFragment(newInstance: Fragment) {
              val beginTransaction = supportFragmentManager.beginTransaction()
              beginTransaction.replace(R.id.right_layout, newInstance)
              beginTransaction.commit()
          }
      }
      
    3. 实现返回栈

      beginTransaction.addToBackStack(null)
      
  2. 生命周期

    1. 回调方法

      • onAttach(context: Context):当Fragment和Activity建立关联时调用
      • onCreateView():为Fragment创建视图(加载布局)时调用
      • onActivityCreated():确保与Fragment相关联的Activity已经创建完毕时调用
      • onDestoryView():当与Fragment关联的视图被移除时调用
      • onDetach():当Fragment和Activity解除关联时调用
  3. 动态加载布局技巧

    1. 使用限定符

      layout-large文件夹放置平板资源

    2. 使用最小宽度限定符

      最小宽度限定符(smallest-width qualifier)这个对应的是开发者选项中最小宽度

      最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为单位),以这个最小值为临界点,屏幕宽度大于这个值就加载这个目录下的布局。

  4. 最佳实践

    实现一个app,手机端水果列表页面展示水果,点击某个水果跳转到水果详情页面。pad端左侧展示水果列表,右侧显示选中的水果详情。

    1. 实现两个Fragment:水果列表Fragment、水果详情Fragment

      <?xml version="1.0" encoding="utf-8"?>
      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          tools:context=".chapter5.FruitListFragment">
      
          <ListView
              android:id="@+id/fruit_listview"
              android:layout_width="match_parent"
              android:layout_height="match_parent"/>
      
      </FrameLayout>
      
      class FruitListFragment : Fragment() {
          private var fruitList = ArrayList<FruitListActivity.Fruit>()
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              initFruits()
          }
      
          private fun initFruits() {
              repeat(20) {
                  fruitList.add(FruitListActivity.Fruit(R.drawable.apple_pic, "Apple"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.banana_pic, "Banana"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.orange_pic, "Orange"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.watermelon_pic, "Watermelon"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.pear_pic, "Pear"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.grape_pic, "Grape"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.pineapple_pic, "PineApple"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.strawberry_pic, "Strawberry"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.cherry_pic, "Cherry"))
                  fruitList.add(FruitListActivity.Fruit(R.drawable.mango_pic, "Mango"))
              }
          }
      
          override fun onCreateView(
              inflater: LayoutInflater, container: ViewGroup?,
              savedInstanceState: Bundle?
          ): View? {
              return inflater.inflate(R.layout.fragment_fruit_list, container, false)
          }
      
          override fun onActivityCreated(savedInstanceState: Bundle?) {
              super.onActivityCreated(savedInstanceState)
              view?.let {
                  val fruitListView = it.findViewById<ListView>(R.id.fruit_listview)
                  fruitListView.adapter =
                      context?.let { it1 -> FruitAdapter(it1, R.layout.fruit_item, fruitList) }
                  fruitListView.setOnItemClickListener { _, _, position, _ ->
                      (context as FruitActivity).showFruit(
                          fruitList[position].imgId,
                          fruitList[position].name
                      )
                  }
              }
          }
      }
      
      <?xml version="1.0" encoding="utf-8"?>
      <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          xmlns:tools="http://schemas.android.com/tools"
          android:id="@+id/constraint_layout"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          tools:context=".chapter5.FruitFragment">
      
      
          <ImageView
              android:id="@+id/fruit_img"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="268dp"
              android:src="@drawable/apple_pic"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintHorizontal_bias="0.498"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="parent" />
      
          <TextView
              android:id="@+id/fruit_name"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="TextView"
              app:layout_constraintBottom_toBottomOf="parent"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintHorizontal_bias="0.498"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toBottomOf="@+id/fruit_img"
              app:layout_constraintVertical_bias="0.118" />
      </androidx.constraintlayout.widget.ConstraintLayout>
      
      class FruitFragment : Fragment() {
      
          override fun onCreateView(
              inflater: LayoutInflater, container: ViewGroup?,
              savedInstanceState: Bundle?
          ): View? {
              return inflater.inflate(R.layout.fragment_fruit, container, false)
          }
      
          fun refreshView(resourceId: Int, name: String) {
              view?.apply {
                  findViewById<ImageView>(R.id.fruit_img).setImageResource(resourceId)
                  findViewById<TextView>(R.id.fruit_name).text = name
              }
          }
      }
      
    2. 实现Activity

      1. 手机布局

        <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".chapter5.FruitActivity">
        
            <fragment
                android:id="@+id/chat_history"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:name="com.youngly.firstlineofcode.chapter5.FruitListFragment"/>
        
        </androidx.constraintlayout.widget.ConstraintLayout>
        
      2. 平板布局

        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            tools:context=".chapter5.FruitActivity">
        
            <fragment
                android:id="@+id/fruit_list_fragment"
                android:name="com.youngly.firstlineofcode.chapter5.FruitListFragment"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />
        
            <fragment
                android:id="@+id/fruit_fragment"
                android:name="com.youngly.firstlineofcode.chapter5.FruitFragment"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="2" />
        
        </LinearLayout>
        
      3. Activity代码

        class FruitActivity : AppCompatActivity() {
            private var mIsLarge: Boolean = false
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                setContentView(R.layout.activity_fruit)
        
              	// 通过判断右侧Fragment是否存在来判断是否是平板
                mIsLarge = supportFragmentManager.findFragmentById(R.id.fruit_fragment) != null
            }
        
            fun showFruit(resourceId: Int, name: String) {
                if (mIsLarge) {
                    (supportFragmentManager.findFragmentById(R.id.fruit_fragment) as FruitFragment).refreshView(resourceId, name)
                } else {
                    val intent = Intent(this, FruitDetailActivity::class.java)
                    intent.putExtra("resourceId", resourceId)
                    intent.putExtra("name", name)
                    startActivity(intent)
                }
            }
        }
        
  5. Kotlin课堂

    1. 扩展函数

      需求:统计字符串中字母个数

      1. Java中编写Util类,定义函数获取字母个数

      2. Kotlin中扩展函数

        由于希望向String类中添加一个扩展函数,因此创建一个String.kt文件

        fun String.letterCount(): Int {
            var count = 0
            for (char in this) {
                if (char.isLetter())
                    count++
            }
            return count
        }
        
    2. 运算符重载

      运算符重载用的是operator关键字

      +运算符对应的是plus()函数

      下例是不同货币之间相加,得到同一货币

      1. 定义父类

        /**
         * Creater:     yanglei
         * Date:        2021/7/2  下午11:59
         * Desc:
         * rate:汇率
         */
        open class Money(var value: Float, var rate: Float) {
        
            var symbol: String = ""
        
            operator fun plus(money: Money): Money {
                val newMoney = this::class.java.newInstance()
                this::class.java.superclass.getDeclaredField("value").set(newMoney, this.value + money.value * (money.rate / this.rate))
                this::class.java.superclass.getDeclaredField("rate").set(newMoney, this.rate)
                newMoney.symbol = this.symbol
                return newMoney
            }
        
            override fun toString(): String {
                return "${this::class.java.simpleName}($symbol $value)"
            }
        }
        
      2. 定义人名币(汇率以人民币为基准)

        class RMB(value: Float, rate: Float) : Money(value, rate) {
        
            constructor() : this(0f, 0f)
        
            init {
                symbol = "¥"
            }
        }
        
      3. 定义美元

        class Dollar(value: Float, rate: Float) : Money(value, rate) {
            constructor() : this(0f, 0f)
        
            init {
                symbol = "$"
            }
        }
        
      4. 测试

        fun main() {
            val fl = RMB(7f, 1f) + Dollar(1f, 7f)
            println(fl)
        
            val money = Dollar(1f, 7f) + RMB(7f, 1f)
            println(money)
        }
        
      5. 输出

        RMB(¥ 14.0) Dollar($ 2.0)