java tag和flt区别,这些年,我爬过的 Android 坑 | 持续更新
如何理解非主線程可以更新UI
谷歌在 viewRootImpl 中檢查更新ui的線程
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
復(fù)制代碼
在執(zhí)行onCreate的時(shí)候這個(gè)判斷并沒(méi)有執(zhí)行到
dialogFragment 全屏?xí)r左右留空的解決方案
在 fragment#onResume 中重新調(diào)整 window 布局
android.view.WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
復(fù)制代碼
dialogFragment 全屏?xí)r狀態(tài)欄出現(xiàn)黑色布局的解決方案
在主題中設(shè)置
true
復(fù)制代碼
此時(shí) window 為 wrap_content,如果出現(xiàn)左右空白,則考慮使用上個(gè)問(wèn)題的方案。
recyclerview 調(diào)用 notifyItemRemoved 方法移除某個(gè) Item 之后因?yàn)橐?position 引起 crash 的原因
`notifyItemRemoved`方法并不會(huì)移除列表的數(shù)據(jù)源的數(shù)據(jù)項(xiàng)導(dǎo)致數(shù)據(jù)源中的數(shù)據(jù)與列表Item數(shù)目不一致,需要同步刷新數(shù)據(jù)源。
recyclerview 局部刷新Item時(shí)會(huì)因?yàn)槟J(rèn)動(dòng)畫(huà)導(dǎo)致閃爍的解決方案
因?yàn)閞ecyclerview存在ItemAnimator,且在刪除/更新/插入Item時(shí)會(huì)觸發(fā),可設(shè)置不支持該動(dòng)畫(huà)即可。
((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
復(fù)制代碼
recyclerview 中的 item 出現(xiàn)莫名的偏移滾動(dòng)
這個(gè)問(wèn)題經(jīng)過(guò)定位存在于 viewholder 中的某個(gè) view 可能提前獲取到焦點(diǎn)。 同時(shí)在。alibaba-vlayout 庫(kù)中也發(fā)現(xiàn)有人反饋改問(wèn)題。 issues-255 解決的方法是在 Recyclerview中外層父布局中添加 android:descendantFocusability="blocksDescendants" 用于父布局覆蓋 Recyclerview 優(yōu)先搶占焦點(diǎn)。
recyclerview 內(nèi)容超過(guò)一屏?xí)r,findFistCompletelyVisibleItemPosition 會(huì)返回 -1 的原因
原因是在 findOneVisibleChild 計(jì)算出來(lái)的 start 和 end 已經(jīng)超過(guò)了 reclclerview 的 start 和 end.經(jīng)過(guò)研究源碼得到以下。
findFirstCompletelyVisibleItemPosition -> -1
findLastCompletelyVisibleItemPosition -> -1
findFirstVisibleItemPosition -> 正常
findLast
復(fù)制代碼
textview 中富文本點(diǎn)擊事件攔截了長(zhǎng)按事件的解決方案
這個(gè)問(wèn)題常見(jiàn)于消息列表中,某條消息使用了ClickableSpan用于處理富媒體的點(diǎn)擊事件,同時(shí)這個(gè)消息又需要支持長(zhǎng)按復(fù)制。由于LinkMovementMethod方法在onTouchEvent一直返回true,可以通過(guò)自定義View.onTouchListener來(lái)替換setMovenmentMethod達(dá)到效果。
public class ClickMovementMethod implements View.OnTouchListener {
private LongClickCallback longClickCallback;
public static ClickMovementMethod newInstance() {
return new ClickMovementMethod();
}
@Override
public boolean onTouch(final View v, MotionEvent event) {
if (longClickCallback == null) {
longClickCallback = new LongClickCallback(v);
}
TextView widget = (TextView) v;
// MovementMethod設(shè)為空,防止消費(fèi)長(zhǎng)按事件
widget.setMovementMethod(null);
CharSequence text = widget.getText();
Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = spannable.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_DOWN) {
v.postDelayed(longClickCallback, ViewConfiguration.getLongPressTimeout());
} else {
v.removeCallbacks(longClickCallback);
link[0].onClick(widget);
}
return true;
}
} else if (action == MotionEvent.ACTION_CANCEL) {
v.removeCallbacks(longClickCallback);
}
return false;
}
private static class LongClickCallback implements Runnable {
private View view;
LongClickCallback(View view) {
this.view = view;
}
@Override
public void run() {
// 找到能夠消費(fèi)長(zhǎng)按事件的View
View v = view;
boolean consumed = v.performLongClick();
while (!consumed) {
v = (View) v.getParent();
if (v == null) {
break;
}
consumed = v.performLongClick();
}
}
}
}
textView.setOnTouchListener(ClickMovementMethod.newInstance());
復(fù)制代碼
如何禁止 ViewPager 的滑動(dòng)
重寫(xiě)ViewPager onTouchEvent 和 onInterceptTouchEvent 并返回false,不處理任何滑動(dòng)事件
@Override
public boolean onTouchEvent(MotionEvent arg0) {
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
return false;
}
復(fù)制代碼
如何仿蘑菇街/馬蜂窩 Viewpager 裝載圖片之后切換時(shí)動(dòng)態(tài)變更高度
imageViewPager 為普通的 Viewpager 對(duì)象
imageListInfo為存放圖片信息的list,imageShowHeight為業(yè)務(wù)需要顯示高度,通過(guò)切換時(shí)動(dòng)態(tài)計(jì)算調(diào)整
imageViewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
imageViewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//根據(jù)viewpager的高度,拉伸顯示圖片的寬度調(diào)整高度。
ViewGroup.LayoutParams layoutParams = imageViewPager.getLayoutParams();
layoutParams.height = imageListInfo.imageShowHeight[0];
imageViewPager.setLayoutParams(layoutParams);
}
});
imageViewPager.setAdapter(imagePagerAdapter);
imageViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == imageListInfo.getImageListSize() - 1) {
return;
}
int height = (int) (imageListInfo.imageShowHeight[position] * (1 - positionOffset) + imageListInfo.imageShowHeight[position + 1] * positionOffset);
ViewGroup.LayoutParams params = imageViewPager.getLayoutParams();
params.height = height;
imageViewPager.setLayoutParams(params);
}
@Override
public void onPageSelected(int position) {
if (!clickListBySelf) {
toSelectIndex(imageListInfo.selected, position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
復(fù)制代碼
如何控制 appbarLayout 隨時(shí)定位到某個(gè)位置
```
CoordinatorLayout.Behavior behavior =((CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams()).getBehavior();
if (behavior instanceof AppBarLayout.Behavior) {
AppBarLayout.Behavior appBarLayoutBehavior = (AppBarLayout.Behavior) behavior;
int topAndBottomOffset = appBarLayoutBehavior.getTopAndBottomOffset();
if (topAndBottomOffset != 0) {
appBarLayoutBehavior.setTopAndBottomOffset(0);
}
```
如何禁止 appbarLayout 滾動(dòng)
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
@Override
public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
return false;
}
});
復(fù)制代碼
edittext 未能響應(yīng) onClickListener 事件的解決方案
Edittext監(jiān)聽(tīng)未獲取焦點(diǎn)的Edittext的點(diǎn)擊事件,第一次點(diǎn)擊觸發(fā)OnFocusChangeListener,在獲取焦點(diǎn)的情況下才能響應(yīng)onClickListener
使用 listview 或gridview 的處理 item 的 state_selected 事件是無(wú)效的解決方案
在xml布局中對(duì)listview或gridview設(shè)置Android:choiceMode="singleChoice",并使用state_activated狀態(tài)來(lái)代替state_selected狀態(tài)。(2016.12.10)
解決5.0以上Button自帶陰影效果的方案
在xml定義的Button中,添加以下樣式定義
style="?android:attr/borderlessButtonStyle"
復(fù)制代碼
針對(duì) onSingleTapUp 和 onSIngleTapConfirmed 的使用區(qū)別
前者在按下并抬起時(shí)發(fā)生,后者有一個(gè)附加條件時(shí)Android會(huì)確保點(diǎn)擊之后在短時(shí)間內(nèi)沒(méi)有再次點(diǎn)擊才會(huì)觸發(fā)。常用于如果需要監(jiān)聽(tīng)單擊和雙擊事件。
如何使用layer-list畫(huà)三角形
//左
android:fromDegrees="45"
android:pivotX="85%"
android:pivotY="135%">
android:width="16dp"
android:height="16dp" />
//右
android:fromDegrees="45"
android:pivotX="15%"
android:pivotY="-35%">
android:width="16dp"
android:height="16dp" />
//上/正
android:fromDegrees="45"
android:pivotX="-40%"
android:pivotY="80%">
android:width="16dp"
android:height="16dp"/>
//下
android:fromDegrees="45"
android:pivotX="135%"
android:pivotY="15%">
android:width="16dp"
android:height="16dp"/>
復(fù)制代碼
總結(jié)
以上是生活随笔為你收集整理的java tag和flt区别,这些年,我爬过的 Android 坑 | 持续更新的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: php表单写入数据库,php表单写入数据
- 下一篇: php 隐藏的id,隐藏你的 ID 吧!