那些好玩的 android 小事

那些好玩的 android 小事

本文記錄的是一些在開發(fā)時遇到的好玩的東西同诫,一些容易出錯的地方樟澜,一些迷惑的地方往扔, 雖然記錄的東西很簡單熊户,但是又特別的細節(jié)。

  1. View 的 setOnclickListener(...) 與 setClickable

    view.setClickable(false);
    view.setOnclickListener(...);

    則 該 view 仍然為可點擊狀態(tài)蝗罗,因為
    setOnClickListener()里面會把 view 設置為 clickable , 可點擊狀態(tài):

    // view 的 源碼  
    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }
    

    會首先檢查該 view 是否可點擊蝌戒,如果不可點擊,則會把它設置為可點擊狀態(tài)桩匪。

  2. ImageView.setAlpha(int) 與 ImageView.setAlpha(float) 的區(qū)別

    這是一個文檔里友鼻,很容易踩進去的坑。

    setAlpha(int) 是對 image 進行 alpha 進行變化妆档, 范圍是 0 ~ 255;

    setAlpha(float) 是對 view 進行 alpha 進行變化虫碉,范圍是 0f ~ 1f;

    兩個方法 做 透明度變化的對象不同,要千萬注意须板,注意>ぢ选!杰刽!, 如果混用贺嫂,就會出現(xiàn)問題的第喳。

    例如,如果是想利用 float 進行設置曲饱,剛開始設置了 setAlpha(0), 后面都是 setAlpha(float), 則會出現(xiàn) 這個 view 永遠展示不出來的情況, 剛開始設置 setAlpha(0f) 則是正確的扩淀。

    注意:官方已經(jīng)拋棄了 setAlpha(float) 這個方法,推薦使用 setImageAlpha(int) (API 16 以上才會生效) 這個方法.

  3. 在 自定義 view 中驻谆, paint 的 setColor() 與 setAlpha() 的關系

    paint.setColor(#12ffffff)胜臊;
    如果設置的顏色里面包含了 透明度, 則 該畫筆 的透明度 不一定就是 12;

    /**
    * ... ts alpha can be any value, regardless of the values of r,g,b
    */
    public void setColor(@ColorInt int color) {
        nSetColor(mNativePaint, color);
    }
    

    它的 alpha 可能會變化黑忱,因為受 setAlpha 的影響

     /**
     * Helper to setColor(), that only assigns the color's alpha value,
     * leaving its r,g,b values unchanged. Results are undefined if the alpha
     * value is outside of the range [0..255]
     *
     * @param a set the alpha component [0..255] of the paint's color.
     */
    
    public void setAlpha(int a) {
        nSetAlpha(mNativePaint, a);
    }
    
    

    setAlpha() 會覆蓋 setColor 中的 透明度勒魔, 所以 當你做自定義 view 的變換時,如果同時設置了 setColor 和 setAlpha 則 透明度會有后者決定危虱。

  1. 圖片的時間戳問題

    在 媒體庫里面 MediaStore.Images 里面唐全, ImageColumns.DATE_TAKEN, 這項屬性,描述的是該圖片的時間戳弥雹。但是當你修改該圖片后延届,該時間 DATE_TAKEN, 會怎么變化呢?假設原圖片(A)的時間為 2018.01.02 13:00, 那么修改改圖片后厕吉,一般會保留原圖片,生成一個新的圖片(B)运悲,那么這個新的圖片的時間為多少呢项钮?首先猜一猜,要么和原圖一樣署隘,要么是現(xiàn)在修改的時間亚隙。

    但是!Q旅摹恤浪!事實上肴楷,當我去打印這個時間的時候,竟然發(fā)現(xiàn)砂客,修改后的 B 的時間戳呵恢,竟然小于 原圖片 A 的時間!M瘛鳄橘!,也就是說术徊,這個時間 會早于 2018.01.02 13:00 可能是 2018.01.02 12:59.

    這個不是特別會影響功能的地方鲸湃,我也是偶然發(fā)現(xiàn)的子寓,在這里記錄一下笋除,也說不定是錯的株憾,我只測試了我手上的幾款機型,可能根據(jù)不同的機型會有所不同吧墙歪。

  1. padding 與 margin 對同一個控件的影響

    例如:父控件為LinearLayout, 子控件為button贝奇,下面兩種設置的方式效果是一樣的:

     1. 當父控件設置了`padding="8dp"`
         padding 是內(nèi)邊框, 使得該父控件里的子view的空間都會減少8dp
     2. 子控件設置了`layout_margin="8dp"`
         margin 是相對button而言的毕源,使得自身距離父控件各個方向有8dp的距離陕习;
    

    上面兩種,實際button的點擊區(qū)域冻璃,view的繪制區(qū)域都是相同的损合,但是padding后使得linearlayout里content會縮小8dp的距離,而margin則不會影響content的區(qū)域大小跋炕,從而造成一些特定情況下的問題律适。在margin下,button可以顯示設置的陰影棉圈,而padding則沒有足夠的content去顯示陰影眷蜓。

    說的有點不清楚,可能需要特定的情況下德召,才可以發(fā)現(xiàn)區(qū)別,但是福荸, padding 會導致里面 的 子 view button 的大小不能超過 padding 的限制肴掷, 是父 view 對 子view 的限制呆瞻,是被動的; 而 margin 是一個主動的行為颤介,是子 view 對 自身的一個限制赞赖;

    下面看一個

  2. 數(shù)據(jù)庫的操作條數(shù)限制 : 1000 條

    Crash : SQLiteException: Expression tree is too large (maximum depth 1000)
    

    原因: 在 sqlite 語句中 的 篩選條件里面 包含了太多的內(nèi)容項,超過了1000 個辕近,就會 crash; 這個是直接寫在代碼里的话侄,是 sqlite 直接拋出的異常.

    通常會出現(xiàn)在 刪除記錄時年堆,例如盏浇, 篩選條件 whereCause.append(ID + "=" + list.get(i).id), 然后循環(huán)添加 要刪除的對象,如果 list 內(nèi)容太多痒蓬,就會造成 whereCause 十分的龐大滴劲,當超過 1000 深度時,便會 發(fā)生 這個 crash .

    解決方案:

    1. 手動對 whereCause.append 進行限制鲁捏,如果超過 1000 , 則執(zhí)行 sqlite 刪除語句萧芙,然后接著 另外一個 whereCause 去 添加條件, 再次去執(zhí)行 刪除語句。

    2. 如果條件可以替換為 IN 處理

      whereCause = "Table.column._ID IN (ids[1], ids[2], ids[3], ...);
          
      whereCause = "Table.column._ID = ids[1] OR Table.column._ID = ids[2] OR Table.column._ID = ids[3] ...";
          
      上面兩者是等價的动羽, 但是 第一種不會造成 上述 exception运吓, in 只代表一條語句,但是 or 卻有多個 or 出現(xiàn)
      
  3. ConstraintLayout 中的 Group 控件要慎用谋梭!

    現(xiàn)在更多的都會使用 ConstraintLayout 布局宅静,因為它太強大了,減少了很多 view 的層級纤垂。

    在約束布局中磷账,有時會想要同時控制兩個以上的 view 的可見性逃糟,一般我們都是通過 Group 這個官方提供的控件去設置。

    代碼示例如下:

    <android.support.constraint.Group
        android:id="@+id/preview_layout_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:constraint_referenced_ids="preview_image_view, preview_delete_view" />
    

    當我們設置 preview_layout_group.setVisibility(...), 會同時對兩個 view(preview_image_view, preview_delete_view) 同時生效菇肃,比較方便取募。

    但是宁仔,當我們這樣設置的時候,有可能會出現(xiàn)里面子 view 設置setVisibility() 時失效的現(xiàn)象M邸E榇狻!

    假設刽宪,我們設置 preview_layout_group.setVisibility(VISIBLE)界酒, 然后想對里面的 deleteView 設置為不可見,那么實際上是不會生效的庇谆。 deleteView imageView 都是可見的凭疮。

    • 這里跟我們之前設置 view 的可見性不同的是执解,以前一般都是設置了父 view 可見后,在針對個別 view 設置它的不可見新蟆。

    • 如果我們使用了 Group 時琼稻, Group 并不是父 view饶囚。它是一個單獨的控件去控制里面所有關聯(lián) view 的可見性,而且嘀掸,是一種優(yōu)先級比較大的方式去設置了里面子 view 的可見性规惰。

      所以當你設置了 Group 為可見時卿拴,里面的子 view 你設置了不可見梨与,子 view 的設置是不會生效的!T低臁!

    所以要慎重的使用 Group苏研,它其實很實用摹蘑,會很方便控制一些 view 的共同可見性轧飞,但是,當使用的時候大渤,一定要確保里面所有關聯(lián)的子 view 之間的可見性時完全一樣的掸绞,要么都可見,要么都不可見烫幕!

  1. RecyclerViewscrollbar 和分割線 Item.Decoration 的遮擋問題
    有時候纬霞,會出現(xiàn) RecyclerViewscrollbar 顯示不完全驱显,或者 scrollbar 被「分割線」分開的現(xiàn)象,這部分涉及到的內(nèi)容比較多伏恐。詳細在下面這篇文章中:
    RecyclerView 的 scrollbar 和 ItemDecoration 的繪制和遮擋問題

  2. TextView 里面的 moveCursorToVisibleOffset() 方法

    該方法在源碼中注釋很詳細:當 TextView 中的 mTextSpannable 的實例且不只一個字符時翠桦,當文本滾動時「文本太多销凑,可滑動」仅炊,編輯的光標會隨著滾動而移動。源碼如下:

     /**
     * Move the cursor, if needed, so that it is at an offset that is visible
     * to the user.  This will not move the cursor if it represents more than
     * one character (a selection range).  This will only work if the
     * TextView contains spannable text; otherwise it will do nothing.
     *
     * @return True if the cursor was actually moved, false otherwise.
     */
    public boolean moveCursorToVisibleOffset() {
        if (!(mText instanceof Spannable)) {
            return false;
        }
        int start = getSelectionStart();
        int end = getSelectionEnd();
        if (start != end) {
            return false;
        }
    
        // First: make sure the line is visible on screen:
    
        int line = mLayout.getLineForOffset(start);
    
        final int top = mLayout.getLineTop(line);
        final int bottom = mLayout.getLineTop(line + 1);
        final int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom();
        int vslack = (bottom - top) / 2;
        if (vslack > vspace / 4) {
            vslack = vspace / 4;
        }
        final int vs = mScrollY;
    
        if (top < (vs + vslack)) {
            line = mLayout.getLineForVertical(vs + vslack + (bottom - top));
        } else if (bottom > (vspace + vs - vslack)) {
            line = mLayout.getLineForVertical(vspace + vs - vslack - (bottom - top));
        }
    
        // Next: make sure the character is visible on screen:
    
        final int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
        final int hs = mScrollX;
        final int leftChar = mLayout.getOffsetForHorizontal(line, hs);
        final int rightChar = mLayout.getOffsetForHorizontal(line, hspace + hs);
    
        // line might contain bidirectional text
        final int lowChar = leftChar < rightChar ? leftChar : rightChar;
        final int highChar = leftChar > rightChar ? leftChar : rightChar;
    
        int newStart = start;
        if (newStart < lowChar) {
            newStart = lowChar;
        } else if (newStart > highChar) {
            newStart = highChar;
        }
    
        if (newStart != start) {
            Selection.setSelection(mSpannable, newStart);
            return true;
        }
    
        return false;
    }
    

    但是呢谋逻? 當我們不需要該效果毁兆,期望光標不隨著文本的滾動而變化位置阴挣,那么重寫該方法返回 false 即可屯吊。

    @Override
    public boolean moveCursorToVisibleOffset() {
        return false;
    }
    
  1. To be continued ...

上面是個人在開發(fā)過程中遇到的一些比較好玩的事情,有時候敲代碼蠻枯燥骗爆,發(fā)現(xiàn)的一些小的驚奇的點蔽介,會讓自己很開心虹蓄,就像在沙灘上拾貝一樣,偶爾發(fā)現(xiàn)幾個特別奇特的貝殼外臂, 會特別開心律胀,這也算代碼的魅力吧。 會持續(xù)更新罪佳, 發(fā)現(xiàn)一些好的點都會補充上去~

大家有什么感覺好的點黑低,也可以指出來克握,如有哪里不對的地方, 水平有限娇掏,也請指出來勋眯,謝謝~~~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末客蹋,一起剝皮案震驚了整個濱河市讶坯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辆琅,老刑警劉巖婉烟,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件似袁,死亡現(xiàn)場離奇詭異,居然都是意外死亡扬霜,警方通過查閱死者的電腦和手機著瓶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門材原,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谭羔,“玉大人,你說我怎么就攤上這事客叉』案妫” “怎么了沙郭?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵病线,是天一觀的道長鲤嫡。 經(jīng)常有香客問我绑莺,道長纺裁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任栋豫,我火速辦了婚禮,結果婚禮上谚殊,老公的妹妹穿的比我還像新娘丧鸯。我一直安慰自己,他們只是感情好络凿,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布骡送。 她就那樣靜靜地躺著,像睡著了一般絮记。 火紅的嫁衣襯著肌膚如雪摔踱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天怨愤,我揣著相機與錄音派敷,去河邊找鬼撰洗。 笑死篮愉,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的差导。 我是一名探鬼主播试躏,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼设褐!你這毒婦竟也來了颠蕴?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤助析,失蹤者是張志新(化名)和其女友劉穎犀被,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體外冀,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡寡键,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了雪隧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片西轩。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡员舵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遭商,到底是詐尸還是另有隱情固灵,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布劫流,位于F島的核電站,受9級特大地震影響丛忆,放射性物質(zhì)發(fā)生泄漏祠汇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一熄诡、第九天 我趴在偏房一處隱蔽的房頂上張望可很。 院中可真熱鬧,春花似錦凰浮、人聲如沸我抠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菜拓。三九已至,卻和暖如春笛厦,著一層夾襖步出監(jiān)牢的瞬間纳鼎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工裳凸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贱鄙,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓姨谷,卻偏偏與公主長得像逗宁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子梦湘,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

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