Day18 - 使用ViewBinding取代Kotlin Android Extension

今天是预料之外的内容。

Kotlin在1.4.20-M2版本中弃用了Kotlin Android Extension,先前开发时没特别注意到这个资讯,只有觉得Android Studio自某版本开始没有自动加入apply plugin: 'kotlin-android-extensions'感到有些奇怪。最近了解了一下相关资讯後决定把目前在做的专案都改成使用ViewBinding

相关资讯

开始使用

在Gradle内加入

android {
    // ...
    buildFeatures {
        viewBinding true
    }
    // ...
}

并将有使用到kotlinx.android.synthetic的import都移除掉。

ViewBinding in Activity

先宣告Binding物件,Binding物件的名称会根据layout.xml的名称来自动产生,比如activity_main.xml就会产生为ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

    }
}

接着在onCreate中呼叫Binding物件的inflate方法来初始化,并且将setContentView中传入的内容改为inflate後的root。

最後使用到layout内的View时需从binding呼叫。

原本:

public fun showLoading(msg: String) {
    loadingLayout.visibility = View.VISIBLE
    loadingMsg.text = msg
}

修改後:

public fun showLoading(msg: String) {
    binding.loadingLayout.visibility = View.VISIBLE
    binding.loadingMsg.text = msg
}

ViewBinding in Fragment

class SearchArticleFragment : Fragment() {
    private var _binding: FragmentSearchArticleBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Inflate the layout for this fragment
        _binding = FragmentSearchArticleBinding.inflate(inflater, container, false)
        return binding.root
    }
    
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

Fragment的ViewBinding物件在inflate时需传入所属的parent。另外要注意在onDestroyView的时候将_binding设回null,避免Memory Leak。

ViewBinding in RecyclerView.Adapter

在RecyclerView.Adapter中使用时需要修改ViewHolder,将原本传入View的部分改为传入ViewBinding物件,super的部分则传入binding.root即可:

inner class ViewHolder(private val binding: ItemSearchArticleResultBinding) :
    RecyclerView.ViewHolder(binding.root) {

    init {
        itemView.setOnClickListener {
            onArticleClickListener?.invoke(articleList[adapterPosition])
        }
    }

    fun bindView(article: Article) {
        binding.number.text = article.number
        binding.author.text = article.author
        binding.title.text = article.title
        binding.date.text = article.date
    }
}

RecyclerView.onCreateViewHolder对应修改:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(
    ItemSearchArticleResultBinding
        .inflate(LayoutInflater.from(parent.context), parent, false)
)

ViewBinding for dynamic View item

Day09时我用了PopupWindow来显示看板的搜寻结果,过程中有另外inflate子View的部分,这边在使用ViewBinding时也需要做一点修改,原本的程序码连结内有就不重复贴了。

修改後程序码
// ...
val boardResultBinding = LayoutSearchBoardResultBinding.inflate(
    LayoutInflater.from(requireContext()),
    null,
    false
)

val height = if (boardList.isEmpty()) {
    boardResultBinding.noResultLabel.visibility = View.VISIBLE
    boardResultBinding.recyclerView.visibility = View.GONE
    120f.dpToPx(requireContext())
} else {
    val adapter = SearchBoardResultAdapter(boardList)
    adapter.onBoardClickListener = { board ->
        popupWindow?.dismiss()
        binding.searchBoardInput.setText(board)
    }
    boardResultBinding.recyclerView.setHasFixedSize(true)
    boardResultBinding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
    boardResultBinding.recyclerView.adapter = adapter
    360f.dpToPx(requireContext())
}

popupWindow = PopupWindow(
    boardResultBinding.root, // view
    ViewGroup.LayoutParams.MATCH_PARENT, // width
    height, // height
    true // focusable
)
// ...

<<:  【从实作学习ASP.NET Core】Day21 | 前台 | 用检视元件建立选单

>>:  [Day 20] Facial Recognition: OpenCV + Dlib可以一次满足

基本操作 - 帐务

取得信用帐户资讯 # futopt_account - 期货,选择权帐号 account_marg...

【Day5】注册画面 X Firestore Database

昨天我们已经把登入画面做好了,大家有没有觉得万事起头难呢? 既然我们已经有登入画面了,当然要有注册...

TypeScript 能手养成之旅 Day 10 物件型别-扩充型别-列举(Enum)

前言 上集我们介绍到 Enum 基础用法,今天将来讲解其它用法。 字串列举(String enum)...

Day 57. 系列完结心得

嗨,我是Bear。 遵守在Day30时与自己的约定,於年前写完所有设计模式。 稍晚会将目录更新至Da...

AI ninja project [day 1] 介绍

可以先来说说现在外面的AI工作需求, 从104来看可以发现每个AI的工作几乎都有至少10个人在应徵,...