การสร้าง Custom View จาก Layout XML ( รวม 2 TextView เป็น 1 InfoCardView )

(บทความนี้ผมสรุปจาก http://www.akexorcist.com/2016/12/introduction-to-custom-view-part-2.html )
ไม่ได้เขียนขึ้นเองครับ ใครอยากอ่านรายละเอียดเต็มๆตามไปอ่านลิงค์ ^ ได้เลยครับ

สรุป วิธีนี้ก็คือต้องการสร้างเป็น Custom View ตัวใหม่ขึ้นมา
โดยมี View อยู่ข้างในหลายๆตัว เพื่อให้ควบคุมสั่งงานจาก Custom View ตัวเดียวไปเลย
แทนที่จะไปนั่งควบคุม View แต่ละตัวให้โค้ดมันวุ่นวาย




Example : InfoCardView


widget_info_card.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff7200"
        android:padding="16dp"
        android:textColor="#ffffff"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:padding="16dp"
        android:textColor="#333333"
        android:textSize="16sp" />

</LinearLayout>



สร้าง Custom View สำหรับ InfoCardView

แนะนำว่าให้สืบทอดคลาสจาก FrameLayout
เพราะว่าการสร้าง Custom View ด้วยวิธีนี้คือการสร้าง Layout XML ที่ต้องการ
แล้วเอามาแปะใน Custom View ดังนั้น FrameLayout จึงเหมาะสมที่สุด

InfoCardView.kt

class InfoCardView : FrameLayout, View.OnClickListener {

    var tvTitle : TextView? = null
    var tvContent : TextView? = null
    private var infoClickListener: InfoClickListener? = null

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        setup()
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        setup()
    }


         private fun setup() {
        inflate(context, R.layout.widget_info_card, this)
        bindView()
        setupView()
    }

    private fun bindView() {
        tvTitle = findViewById(R.id.tv_title)
        tvContent = findViewById(R.id.tv_content)

    }

    private fun setupView() {
        tvTitle?.setOnClickListener(this)
        tvContent?.setOnClickListener(this)

    }



     // สร้างฟังก์ชั่นไว้รอใช้งานใน MainActivity.kt
    fun setTitle(title: String) {
        tvTitle?.text = title
    }
    fun setContent(content: String) {
        tvContent?.text = content
    }
    fun setInfoClickListener(listener: InfoClickListener) {
        this.infoClickListener = listener
    }

    // ดักการคลิกของผู้ใช้ใน layout file : widget_info_card.xml
    override fun onClick(view: View) {
        if (view === tvTitle) {
            onTitleClick()
        } else if (view === tvContent) {
            onContentClick()
        }
    }


     // สร้าง Listener Onclick ให้ View
    private fun onTitleClick() {
        if (infoClickListener != null) {
            infoClickListener!!.onTitleClick()
        }
    }
    private fun onContentClick() {
        if (infoClickListener != null) {
            infoClickListener!!.onContentClick()
        }
    }


    // สร้าง interface ไว้ใช้งานใน MainActivity.kt     interface InfoClickListener {
        fun onTitleClick()
        fun onContentClick()
    }

}



MainActivity.kt

class MainActivity : AppCompatActivity(), InfoCardView.InfoClickListener {   // Implement  InfoClickListener interface

    private var icvAndroidVersion : InfoCardView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        bindView()
        setupView()
    }


    private fun bindView() {
        icvAndroidVersion = findViewById<InfoCardView>(R.id.icv_android_version)
    }
    // เรียกใช้งาน ฟังก์ชั่นใน  InfoCardView.kt
    private fun setupView() {
        icvAndroidVersion?.setTitle(getString(R.string.nougat_title))
        icvAndroidVersion?.setContent(getString(R.string.nougat_content))
        icvAndroidVersion?.setInfoClickListener(this)
    }


    // แสดง Pop up เมื่อคลิกที่ View : Title     
    override fun onTitleClick() {
        Toast.makeText(this, "onTitleClick", Toast.LENGTH_LONG).show()
    }

     // แสดง Pop up เมื่อคลิกที่ View : Content     
     override fun onContentClick() {
        Toast.makeText(this, "onContentClick", Toast.LENGTH_LONG).show()
    }

}


ลองเรียกใช้งานเพื่อดูผลลัพธ์การทำงาน

<com.example.trymycustomview.InfoCardView
      android:id="@+id/icv_android_version"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />


อ่านต้นฉบับ + รายละเอียดแบบเต็มๆ
http://www.akexorcist.com/2016/12/introduction-to-custom-view-part-2.html