那些好玩的 android 小事
本文記錄的是一些在開發(fā)時遇到的好玩的東西同诫,一些容易出錯的地方樟澜,一些迷惑的地方往扔, 雖然記錄的東西很簡單熊户,但是又特別的細節(jié)。
-
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)桩匪。
-
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 以上才會生效) 這個方法.
-
在 自定義 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 則 透明度會有后者決定危虱。
-
圖片的時間戳問題
在 媒體庫里面
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ù)不同的機型會有所不同吧墙歪。
-
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 對 自身的一個限制赞赖;
下面看一個
-
數(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 .解決方案:
手動對 whereCause.append 進行限制鲁捏,如果超過 1000 , 則執(zhí)行 sqlite 刪除語句萧芙,然后接著 另外一個 whereCause 去 添加條件, 再次去執(zhí)行 刪除語句。
-
如果條件可以替換為 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)
-
ConstraintLayout 中的 Group 控件要慎用谋梭!
現(xiàn)在更多的都會使用
ConstraintLayou
t 布局宅静,因為它太強大了,減少了很多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
之間的可見性時完全一樣的掸绞,要么都可見,要么都不可見烫幕!
RecyclerView
的scrollbar
和分割線Item.Decoration
的遮擋問題
有時候纬霞,會出現(xiàn)RecyclerView
的scrollbar
顯示不完全驱显,或者scrollbar
被「分割線」分開的現(xiàn)象,這部分涉及到的內(nèi)容比較多伏恐。詳細在下面這篇文章中:
RecyclerView 的 scrollbar 和 ItemDecoration 的繪制和遮擋問題-
TextView
里面的moveCursorToVisibleOffset()
方法該方法在源碼中注釋很詳細:當
TextView
中的mText
為Spannable
的實例且不只一個字符時翠桦,當文本滾動時「文本太多销凑,可滑動」仅炊,編輯的光標會隨著滾動而移動。源碼如下:/** * 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; }
- To be continued ...
上面是個人在開發(fā)過程中遇到的一些比較好玩的事情,有時候敲代碼蠻枯燥骗爆,發(fā)現(xiàn)的一些小的驚奇的點蔽介,會讓自己很開心虹蓄,就像在沙灘上拾貝一樣,偶爾發(fā)現(xiàn)幾個特別奇特的貝殼外臂, 會特別開心律胀,這也算代碼的魅力吧。 會持續(xù)更新罪佳, 發(fā)現(xiàn)一些好的點都會補充上去~
大家有什么感覺好的點黑低,也可以指出來克握,如有哪里不對的地方, 水平有限娇掏,也請指出來勋眯,謝謝~~~