1. 程式人生 > >使用Kotlin實現百思不得姐彈出選單

使用Kotlin實現百思不得姐彈出選單

最近學習kotlin ,kotlin 確實是一門非常nice的語言,從它的書寫到它的語法,都有吸引人的地方,學習一門新的語言最好的方法就是運用這門語言了,為了學習kotlin ,仿寫百思不得 姐 ,今天將不得姐的彈出選單記錄一下,先看一下效果
這裡寫圖片描述

好了 下面使用kotlin 完成一下

一、實現思路

就使用最簡單的思路,首先將它用普通佈局搭建出來,在加入動畫,就可以完成了,OK ,kotlin 基本上百分之九十和Java相似,很好理解的一門語言,在Android開發中呢,它是完全相容的,並且為適配程式設計師的過渡期,做了和Java的呼叫,也就是說,我們這些沒有很多時間來學習kotlin 的人來說,相容開發是最好的選擇,說多了,,,,嗯嗯,佈局搭建是和Java開發的時候一樣的,

二、實現過程

下面是佈局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/contentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerHorizontal="true"
    android:alpha="0.9"
    android:gravity="center_horizontal"
>
<LinearLayout android:id="@+id/ll_close" android:layout_width="match_parent" android:layout_height="48dp" android:layout_alignParentBottom="true" android:background="@android:color/white" android:gravity="center"> <TextView android:layout_width
="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="8dp" android:text="@string/send_cancel" />
</LinearLayout> <LinearLayout android:id="@+id/voice_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/ll_close" android:layout_alignLeft="@+id/video_window" android:layout_centerHorizontal="true" android:layout_marginBottom="80dp" android:layout_marginTop="40dp" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/send_voice" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@string/send_voice" android:textColor="#606060" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/link_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/ll_close" android:layout_centerHorizontal="true" android:layout_marginBottom="80dp" android:layout_marginTop="40dp" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/send_link" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@string/send_link" android:textColor="#606060" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/music_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/ll_close" android:layout_centerHorizontal="true" android:layout_marginBottom="80dp" android:layout_marginLeft="40dp" android:layout_toRightOf="@id/link_window" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/send_music_album" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@string/send_music" android:textColor="#606060" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/photo_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/voice_window" android:layout_centerHorizontal="true" android:layout_marginLeft="40dp" android:layout_marginRight="40dp" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/send_picture" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@string/send_pic" android:textColor="#606060" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/video_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/voice_window" android:layout_centerHorizontal="true" android:layout_toLeftOf="@+id/photo_window" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/send_video_uninstall" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@string/send_video" android:textColor="#606060" android:textSize="15sp" /> </LinearLayout> <LinearLayout android:id="@+id/satin_window" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/voice_window" android:layout_centerHorizontal="true" android:layout_toRightOf="@+id/photo_window" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/send_text" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@string/send_satin" android:textColor="#606060" android:textSize="15sp" /> </LinearLayout> </RelativeLayout>

OK ,佈局完了之後,我們在分析一下,上面UI中的中間的按鈕,出發事件之後,是彈出來了一個佈局,覆蓋整體UI的佈局,那他是什麼呢?PopupWindow ,對沒錯 就是PopupWindow ,那我們要怎麼寫呢?
看程式碼

/**
 * Created by mr.kong on 2017/11/17.
 */
class WritePostsPopWindow : PopupWindow, View.OnClickListener {
    private lateinit var rootView: View
    private lateinit var contentView: RelativeLayout
    private lateinit var mContext: Activity

    constructor(mContext: Activity) : super() {
        this.mContext = mContext
    }

    fun showMoreWindow(anchor: View) {
        //獲取LayoutInflater 物件 在kotlin中優點之一,不用指定定義的變數的型別,執行程式碼
        //的時候,程式碼會更具其值確定其型別
        val inflater = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        rootView = inflater.inflate(R.layout.fragment_write_posts, null)
        //獲取螢幕的寬高
        val height = mContext.windowManager.defaultDisplay.height
        val width = mContext.windowManager.defaultDisplay.width
        //PopupWindow設定佈局
        setContentView(rootView)
        this.width = width
        //高度使用減掉狀態列的高度
        this.height = (height - ScreenUtils.getStatusHeight(mContext)).toInt()
        //找到我們的根佈局節點
        contentView = rootView.findViewById(R.id.contentView)
        //取消按鈕
        val close = rootView.findViewById<LinearLayout>(R.id.ll_close)
        close.setBackgroundColor(0xFFFFFFFF.toInt())
        close.setOnClickListener(this)
        showAnimation(contentView)
        setBackgroundDrawable(mContext.resources.getDrawable(R.drawable.translucence_with_white))
        isOutsideTouchable = true
        isFocusable = true
        showAtLocation(anchor, Gravity.BOTTOM, 0, 0)

    }

    private fun showAnimation(contentView: ViewGroup) {
        //contentView 是我們剛才獲得的根節點 獲取在這個節點中的所有的 子節點的個數
        var childCount: Int = contentView.childCount
        KLogger.i("view", "    " + childCount)
        //kotlin 的迴圈的一種方法(有好幾種,每一種都有對應的優點和不足)
        for (i in 0..childCount) {
            val view = contentView.getChildAt(i)
            if (view != null) {
                if (view.id == R.id.ll_close) { //忽略取消控制元件
                    continue
                }
                //設定所有一級選單的點選事件
                view.setOnClickListener(this)
                view.visibility = View.INVISIBLE
                //延遲顯示每個子檢視
                //使用rxjava和rxAndroid 完成延遲操作 在不同時間中開始動畫 出現彈出時先後的效果
                Observable.timer(i * 50.toLong(), TimeUnit.MILLISECONDS)
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            view.visibility = View.VISIBLE
                            /**
                             * ofFloat()
                             * arg1:view 物件
                             * arg2:動畫改變的型別
                             * arg3:args4: 依次是開始透明度和結束透明度
                             */
                            val fadeAnim: ValueAnimator = ObjectAnimator.ofFloat(view, "translationY", 600F, 0F)
                            //設定動畫的時間
                            fadeAnim.duration = 300
                            fadeAnim.start()
                        }
            }

        }

    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.video_window -> {
                Toast.makeText(mContext, "video_window", Toast.LENGTH_LONG).show()
            }
            R.id.link_window -> {
                Toast.makeText(mContext, "video_window", Toast.LENGTH_LONG).show()
            }
            R.id.voice_window -> {
                Toast.makeText(mContext, "video_window", Toast.LENGTH_LONG).show()
            }
            R.id.photo_window -> {
                Toast.makeText(mContext, "video_window", Toast.LENGTH_LONG).show()
            }
            R.id.satin_window -> {
                Toast.makeText(mContext, "video_window", Toast.LENGTH_LONG).show()
            }
            R.id.music_window -> {
                Toast.makeText(mContext, "video_window", Toast.LENGTH_LONG).show()
            }
            R.id.ll_close -> {
                if (isShowing) {
                    closeAnimation(contentView)
                }
            }
        }
    }

    /**
     * 關閉動畫
     */
    private fun closeAnimation(contentView: RelativeLayout) {
        for (i in 0..contentView.childCount) {
            val view = contentView.getChildAt(i)
            if (view != null) {
                if (view.id == R.id.ll_close) { //忽略取消控制元件
                    continue
                }
                //設定所有一級選單的點選事件
                view.setOnClickListener(this)
                view.visibility = View.INVISIBLE

                //延遲顯示每個子檢視
                Observable.timer(((contentView.childCount - i - 1) * 30).toLong(), TimeUnit.MILLISECONDS)
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe {
                            view.visibility = View.VISIBLE
                            val fadeAnim: ValueAnimator = ObjectAnimator.ofFloat(view, "translationY", 0F, 600F)
                            fadeAnim.duration = 200

                            fadeAnim.run {
                                start()
                                addListener(object : Animator.AnimatorListener {
                                    override fun onAnimationRepeat(animation: Animator?) {
                                        //動畫迴圈播放的時候
                                    }

                                    override fun onAnimationEnd(animation: Animator?) {
                                        //動畫結束的時候
                                        view.visibility = View.INVISIBLE
                                    }

                                    override fun onAnimationCancel(animation: Animator?) {
                                        //動畫被取消的時候
                                    }

                                    override fun onAnimationStart(animation: Animator?) {
                                        //動畫開始的時候呼叫
                                    }

                                })
                            }

                        }
                //將個別的取出來 再延時顯示 製造效果
                if (view.id == R.id.video_window) {
                    Observable.timer(((contentView.childCount - i) * 30 + 80).toLong(), TimeUnit.MILLISECONDS)
                            .subscribeOn(Schedulers.newThread())
                          .observeOn(AndroidSchedulers.mainThread())
                            .subscribe({
                                dismiss()
                            })
                }
            }
       }
    }
}

使用

 R.id.main_writ_posts_btu -> {
                val writePostsPopWindow = WritePostsPopWindow(this)
                writePostsPopWindow.showMoreWindow(v)
            }

上面程式碼中的註釋很詳細,至此 完成了不得姐的彈出選單的效果 ,其實kotlin 語言最後方式就是在邊寫邊學中學習