【Toast】關(guān)于Android Toast 的一丁點(diǎn)認(rèn)識(shí)

圖片來(lái)自百度圖片旬陡,如有侵權(quán)粗俱,請(qǐng)聯(lián)系作者刪除

??Android Toast 在項(xiàng)目中是普遍應(yīng)用的一個(gè)控件蜻展,應(yīng)該也是一個(gè)使用非常簡(jiǎn)單的控件魁亦。這里渔隶,有人會(huì)問(wèn),Toast 這么簡(jiǎn)單干嘛還要花時(shí)間去學(xué)習(xí)呢洁奈,項(xiàng)目里直接 Toast.makeText 就可以了啊间唉。我的回答是:“因?yàn)楹?jiǎn)單,所以需要去學(xué)習(xí)利术,去了解”呈野。

為什么我還要去做一個(gè)自定義Toast?

Android Toast 如果在某個(gè)場(chǎng)景交互中印叁,一不小心多次觸發(fā)了 Toast show 結(jié)果是不停地在你屏幕顯示同樣的 Toast 信息被冒。我是個(gè)有時(shí)間潔癖的人,不喜歡因?yàn)槟愣囡@示一次 Toast 信息浪費(fèi)我一秒鐘或兩秒鐘轮蜕,在碎片時(shí)間學(xué)習(xí)中昨悼,我更希望花一秒鐘看到我更喜歡看到的知識(shí),集中精力去得到我想要的東西跃洛。
廢話少扯率触,進(jìn)入主題。
先看看Android 系統(tǒng) Toast 的實(shí)現(xiàn)源碼:
Toast MakeText:

    /**
     * Make a standard toast that just contains a text view.
     *
     * @param context  The context to use.  Usually your {@link android.app.Application}
     *                 or {@link android.app.Activity} object.
     * @param text     The text to show.  Can be formatted text.
     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or
     *                 {@link #LENGTH_LONG}
     *
     */
    public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
        return makeText(context, null, text, duration);
    }
    /**
     * Make a standard toast to display using the specified looper.
     * If looper is null, Looper.myLooper() is used.
     * @hide
     */
    public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
            @NonNull CharSequence text, @Duration int duration) {
        Toast result = new Toast(context, looper);

        LayoutInflater inflate = (LayoutInflater)
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
        TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
        tv.setText(text);

        result.mNextView = v;
        result.mDuration = duration;

        return result;
    }

再看看Toast 布局:

  <?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/res/layout/transient_notification.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="?android:attr/toastFrameBackground">

    <TextView
        android:id="@android:id/message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center_horizontal"
        android:textAppearance="@style/TextAppearance.Toast"
        android:textColor="@color/bright_foreground_dark"
        android:shadowColor="#BB000000"
        android:shadowRadius="2.75"
        />

</LinearLayout>

Toast show 和 cancel 方法:

    /**
     * Show the view for the specified duration.
     */
    public void show() {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }

        INotificationManager service = getService();
        String pkg = mContext.getOpPackageName();
        TN tn = mTN;
        tn.mNextView = mNextView;

        try {
            service.enqueueToast(pkg, tn, mDuration);
        } catch (RemoteException e) {
            // Empty
        }
    }
   /**
     * Close the view if it's showing, or don't show it if it isn't showing yet.
     * You do not normally have to call this.  Normally view will disappear on its own
     * after the appropriate duration.
     */
    public void cancel() {
        mTN.cancel();
    }

??通過(guò)簡(jiǎn)單查看Toast 源碼得知一些信息

  1. Toast 實(shí)現(xiàn)沒(méi)有對(duì)同一條消息顯示進(jìn)行過(guò)濾汇竭,show 方法調(diào)用通知服務(wù) enqueueToast 顯示信息葱蝗。
  2. Toast 布局很簡(jiǎn)單,就一個(gè)LinearLayout 的圓角布局和顯示信息的陰影效果细燎。
android:background="?android:attr/toastFrameBackground"
 android:shadowColor="#BB000000"
 android:shadowRadius="2.75"

顯然两曼,系統(tǒng)的Toast 不滿(mǎn)足我的需求,我需要一個(gè)自定義一個(gè)能夠過(guò)濾相同信息的 Toast 玻驻。

自定義Toast 主要思想:

  1. 創(chuàng)建對(duì)應(yīng)構(gòu)造器悼凑。采用設(shè)計(jì)模式 Builder 模式構(gòu)造一個(gè)需要的Toast。主要針對(duì)有個(gè)性化 Toast 需求提供击狮,如自定義背景顏色佛析,自定義字體顏色,自定義 Toast 背景布局等彪蓬。
  2. 在Toast 上一次顯示后沒(méi)有 cancel 前,界面某個(gè)位置多次觸發(fā)捺萌,只顯示同樣的Toast 信息一次档冬。取顯示信息對(duì)應(yīng)的 hashCode作為key膘茎,緩存對(duì)應(yīng)的Toast 信息,如果我每次傳入的信息都是同樣的則不做顯示酷誓,Handler 控制對(duì)應(yīng)的顯示時(shí)間披坏,即使取消 Toast 顯示,清除上次Toast 顯示信息盐数。
  3. Toast 背景圓角問(wèn)題的一些思考棒拂。Android Toast 圓角布局背景調(diào)用的Android 系統(tǒng) xml 布局,如果動(dòng)態(tài)修改 View 布局顏色會(huì)丟失 圓角玫氢。當(dāng)然帚屉,采用簡(jiǎn)單的自定義一個(gè)圓角布局就可以解決問(wèn)題的,具體圓角布局代碼可參照代碼里 RoundLinearLayout.java漾峡,具體使用方式太簡(jiǎn)單了攻旦,這里不做細(xì)說(shuō)。

自定義相關(guān)代碼展示:

private void initCustomToast(CustomToastBuilder builder) {
        runnable = RUNNABLES.get(text.hashCode());
        if (isNull(runnable)) {
            customToast = new CustomToast(mContext);
            runnable = new ToastRunnable(customToast);
            RUNNABLES.put(text.hashCode(), runnable);
            long showTime = builder.showTime;
            if (showTime > DEFAULT_SHOW_TIME){
                mHander.postDelayed(runnable, showTime);
            }else {
                mHander.postDelayed(runnable, DEFAULT_SHOW_TIME);
            }
            customToast.show(builder.customToastCreator,builder.text,builder.textResId);
        }
    }
 public void show(CharSequence text) {
        if (!text.equals(TEXTS.get(text.hashCode()))) {
            TEXTS.put(text.hashCode(), text);
            systemToast = new SystemToast(mContext);
            runnable = new ToastRunnable(systemToast);
            mHander.postDelayed(runnable, DEFAULT_SHOW_TIME);
            systemToast.show(text);
        }
    }
private class ToastRunnable implements Runnable {

        private BaseToast toast;

        public ToastRunnable(BaseToast toast) {
            this.toast = toast;
        }

        @Override
        public void run() {
            toast.cancel();
            TEXTS.remove(toast.getText().hashCode());
            RUNNABLES.remove(toast.getText().hashCode());
            toast = null;
            runnable = null;
        }
    }

圓角布局:

 @SuppressLint("WrongConstant")
    private void drawRoundDrawable() {
        Log.d(TAG, "drawRoundDrawable: "+cornesRadius);
        if (null == gradientDrawable) {
            return;
        }
        if (cornesRadius != 0) {
            gradientDrawable.setCornerRadius(cornesRadius);
            gradientDrawable.setGradientType(GradientDrawable.RECTANGLE);
        } else if (null != radii) {
            gradientDrawable.setCornerRadii(radii);
            gradientDrawable.setGradientType(GradientDrawable.RECTANGLE);
        }
        setBackgroundDrawable();
    }

自定義 Toast 如何使用生逸,代碼(Kotlin)如下:

1. 最簡(jiǎn)單的使用

JToast.getInstance(this).show("show 一個(gè)牢屋!") 

2. 構(gòu)造器的使用

var creator = SystemToastCreator.build()
                    .shadowColor(Color.parseColor("#2F4F4F"))
                    .shadowRadius(15f)
                    .setTextColor(Color.parseColor("#ffffff"))
                    .creator()
 JToast.build()
                    .systemToastBuilder()
                    .setToastCreator(creator)
                    .setShowTime(2000)
                    .setText("show creator!")
                    .show(this)
var customCreator = CustomToastCreator.build()
                    .setCustomView(R.layout.layout_toast)
                    .setTextColor(Color.WHITE)
                    .setBackgroundRound(true)
                    .creator()
JToast.build()
                    .customToastBuilder()
                    .setToastCreator(customCreator)
                    .setShowTime(2000)
                    .setText("show customCreator!",R.id.message)
                    .show(this)

我自定義的代碼都太簡(jiǎn)單了,這里就不太啰嗦了槽袄。不懂的也隨時(shí)可以聯(lián)系我烙无。

??總結(jié): 我總感覺(jué)我的實(shí)現(xiàn)方式不太友好,并不完善遍尺,歡迎各位評(píng)論區(qū)提出你們寶貴的建議截酷,或直接GitHub 把你們的想法提交。非常感謝各位大神的批評(píng)指正狮鸭!

最后給出 GitHub 鏈接: JToast

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末合搅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子歧蕉,更是在濱河造成了極大的恐慌灾部,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惯退,死亡現(xiàn)場(chǎng)離奇詭異赌髓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)催跪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)锁蠕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人懊蒸,你說(shuō)我怎么就攤上這事荣倾。” “怎么了骑丸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵舌仍,是天一觀的道長(zhǎng)妒貌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)铸豁,這世上最難降的妖魔是什么灌曙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮节芥,結(jié)果婚禮上在刺,老公的妹妹穿的比我還像新娘。我一直安慰自己头镊,他們只是感情好蚣驼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拧晕,像睡著了一般隙姿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厂捞,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天输玷,我揣著相機(jī)與錄音,去河邊找鬼靡馁。 笑死欲鹏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的臭墨。 我是一名探鬼主播赔嚎,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胧弛!你這毒婦竟也來(lái)了尤误?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤结缚,失蹤者是張志新(化名)和其女友劉穎损晤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體红竭,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尤勋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茵宪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片最冰。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖稀火,靈堂內(nèi)的尸體忽然破棺而出暖哨,到底是詐尸還是另有隱情,我是刑警寧澤凰狞,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布鹿蜀,位于F島的核電站箕慧,受9級(jí)特大地震影響服球,放射性物質(zhì)發(fā)生泄漏茴恰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一斩熊、第九天 我趴在偏房一處隱蔽的房頂上張望往枣。 院中可真熱鬧,春花似錦粉渠、人聲如沸分冈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)雕沉。三九已至,卻和暖如春去件,著一層夾襖步出監(jiān)牢的瞬間坡椒,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工尤溜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倔叼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓宫莱,卻偏偏與公主長(zhǎng)得像丈攒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子授霸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容