1. 程式人生 > >實用小技巧(持續更新)

實用小技巧(持續更新)

掃描Activity

public static Activity scanForActivity(Context ctx) {
    if (ctx == null)
        return null;
    else if (ctx instanceof Activity)
        return (Activity) ctx;
    else if (ctx instanceof ContextWrapper)
        return scanForActivity(((ContextWrapper) ctx).getBaseContext());
return null; }

一般用於在Dialog中show的時候判斷Activity的引用是否有效,例如:

@Override
public void show() {
    Activity activity = UIUtils.scanForActivity(getContext());
    if (null != activity && !activity.isFinishing())
        super.show();
}

給drawableRight設定點選事件

例如EditText右側有一個刪除按鈕是通過drawableRight屬性設定的,此時如果想讓其響應點選事件,這可以通過判斷點選的座標位置與刪除按鈕的位置對比,下面是通過處理點選刪除按鈕刪除EditText框的內容

/**
 * 給EditText的右側drawableRight屬性的圖片設定點選事件
 *
 * @param editText
 */
public static void registerEditRightDrawableClickListener(final EditText editText) {
    editText.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // et.getCompoundDrawables()得到一個長度為4的陣列,分別表示左上右下四張圖片
Drawable drawable = editText.getCompoundDrawables()[2]; //如果右邊沒有圖片,不再處理 if (drawable == null) return false; //如果不是按下事件,不再處理 if (event.getAction() != MotionEvent.ACTION_UP) return false; if (event.getX() > editText.getWidth() - editText.getPaddingRight() - drawable.getIntrinsicWidth()) { editText.setText(""); return true; } return false; } }); }

限制EditText可輸入的字數,超出後提示文案

 /**
  * 限制EditText可輸入的字數,超出後提示文案
  *
  * @param editText 目標view
  * @param maxLength 最大字數
  * @param msg 提示文案
  * @param callback 回撥介面
  */
 public static void registerEditMaxTextShow(final EditText editText, final int maxLength, final String msg, final Callback callback) {
     editText.addTextChangedListener(new TextWatcher() {
         @Override
         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
         }
         @Override
         public void onTextChanged(CharSequence s, int start, int before, int count) {
         }
         @Override
         public void afterTextChanged(Editable s) {
             String currMsg = editText.getText().toString().trim();
             if (null != callback) callback.onEditTextChange(currMsg);
             if (currMsg.length() > maxLength) {
                 ToastUtils.showShort(msg);
                 int editStart = editText.getSelectionStart();
                 int editEnd = editText.getSelectionEnd();
                 s.delete(editStart - 1, editEnd);
                 String finalMsg = s.toString();
                 editText.removeTextChangedListener(this);
                 editText.setText(finalMsg);
                 editText.setSelection(finalMsg.length());
                 if (null != callback) callback.onEditTextChange(finalMsg);
                 editText.addTextChangedListener(this);
             }
         }
     });
 }
 //回撥介面
 public interface Callback {
     void onEditTextChange(String msg);
 }

解決RecycleView佈局中GridLayoutManager和StaggeredGridLayoutManager新增頭部和底部不佔用一行的問題

重寫RecyclerView.Adapter的2個方法

/**
 * 解決GridLayoutManager新增頭部和底部不佔用一行的問題
 *
 * @param recyclerView
 */
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
    RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
    if (manager instanceof GridLayoutManager) {
        final GridLayoutManager gridManager = ((GridLayoutManager) manager);
        gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                return (isHeaderViewPosition(position) || isFooterViewPosition(position))
                        ? gridManager.getSpanCount() : 1;
            }
        });
    }
    mAdapter.onAttachedToRecyclerView(recyclerView);
}
/**
 * 解決StaggeredGridLayoutManager新增頭部和底部不佔用一行的問題
 *
 * @param holder
 */
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
    super.onViewAttachedToWindow(holder);
    ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
    int position = holder.getLayoutPosition();
    if (lp != null
            && lp instanceof StaggeredGridLayoutManager.LayoutParams
            && (isHeaderViewPosition(position) || isFooterViewPosition(position))) {
        StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
        p.setFullSpan(true);
    }
    mAdapter.onViewAttachedToWindow(holder);
}

重寫RecycleView的setLayoutManager方法

/**
 * 解決GridLayoutManager新增頭部和底部不佔用一行的問題
 *
 * @param layout
 */
@Override
public void setLayoutManager(LayoutManager layout) {
    super.setLayoutManager(layout);
    if (mWrapAdapter != null) {
        if (layout instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) layout);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return (mWrapAdapter.isHeaderViewPosition(position) || mWrapAdapter.isFooterViewPosition(position))
                            ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }
}

解決由於RecyclerView有重新整理頭存在,導致canScrollVertically(-1)時始終返回true的bug


@Override
public boolean canScrollVertically(int direction) {
    if (direction < 1) {
        boolean original = super.canScrollVertically(direction);
        if (!original || getChildAt(0) != null && getChildAt(0).getTop() >= 0) {
            return false;
        } else {
            return true;
        }
    }
   return super.canScrollVertically(direction);
}

獲取RecycleView第一個和最後一個可見Item的位置

 /**
  * 獲取第一個可見的item位置
  * @return
  */
 public int getFirstVisiablePosition() {
     LayoutManager layoutManager = getLayoutManager();
     int firstVisibleItemPosition;
     if (layoutManager instanceof GridLayoutManager) {
         firstVisibleItemPosition = ((GridLayoutManager) layoutManager).findFirstVisibleItemPosition();
     } else if (layoutManager instanceof StaggeredGridLayoutManager) {
         int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
         ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(into);
         firstVisibleItemPosition = findMin(into);
     } else {
         firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
     }
     return firstVisibleItemPosition;
 }
 

/**
 * 獲取可見列表內最後一個item的位置
 *
 * @return
 */
public int getLastVisibleItemPosition() {
    int lastVisibleItemPosition;
    LayoutManager layoutManager = getLayoutManager();
    if (layoutManager instanceof GridLayoutManager) {
        lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
    } else if (layoutManager instanceof StaggeredGridLayoutManager) {
        int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
        ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
        lastVisibleItemPosition = findMax(into);
    } else {
        lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
    }
    return lastVisibleItemPosition;
}

private int findMin(int[] firstPositions) {
     int min = firstPositions[0];
     for (int value : firstPositions) {
         if (value < min) {
             min = value;
         }
     }
     return min;
 }
 private int findMax(int[] lastPositions) {
     int max = lastPositions[0];
     for (int value : lastPositions) {
         if (value > max) {
             max = value;
         }
     }
     return max;
 }

修改RadioButton的drawableRight圖片與文字相隔的距離太大,導致drawablePadding設定無效

重寫AppCompatRadioButton的onDraw方法

@Override
protected void onDraw(Canvas canvas) {
    //得到Drawable集合  分別對應 左上右下
    Drawable[] drawables = getCompoundDrawables();
    if (drawables != null) {
        //獲取右邊圖片,修改drawableRight的圖片緊貼著文字
        Drawable drawableRight = drawables[2];
        if (drawableRight != null) {
            //獲取文字佔用長寬
            int textWidth = (int) getPaint().measureText(getText().toString());
            int textHeight = (int) getPaint().getTextSize();
            //獲取圖片實際長寬
            int drawableWidth = drawableRight.getIntrinsicWidth();
            int drawableHeight = drawableRight.getIntrinsicHeight();
            //setBounds修改Drawable在View所佔的位置和大小,對應引數同樣的 左上右下()
            int bodyWidth = textWidth + drawableWidth + getCompoundDrawablePadding();
            int left = (bodyWidth - getWidth()) / 2;
            int right = left + drawableWidth;
            drawableRight.setBounds(left, 0, right, drawableHeight);
        }
    }
    super.onDraw(canvas);
}

解決RadioButton無法重複點選取消選中的狀態

重寫AppCompatRadioButton的toggle方法

@Override
public void toggle() {
    setChecked(!isChecked());
    if (!isChecked()) {
        if (null != getParent() && getParent() instanceof RadioGroup)
            ((RadioGroup) getParent()).clearCheck();
    }
}

解決手動設定Switch的setChecked方法導致setOnCheckedChangeListener觸發響應

mPushSwt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (buttonView.isPressed()) { //避免程式碼設定setChecked狀態導致回撥監聽
            //do sth...
        }
    }
});

避免SwipeRefreshLayout重複下拉導致重新整理按鈕異常顯示

重寫SwipeRefreshLayout的onStartNestedScroll方法

 @Override
 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
     //避免重複下拉重新整理導致動畫異常
     return !isRefreshing() && super.onStartNestedScroll(child, target, nestedScrollAxes);
 }

更新於2019-01-03


TextView的drawableLeft與文字無法一起居中顯示

TextView設定的文字預設是存在一個上下間距的,也就是上下空白,當我們在使用drawableLeft的時候,這個預設的空白會使TextView中的文字向下偏移,當你的drawableLeft使用的icon很小,文字的size也很小的時候,即使你設定了android:gravity=“center”,也能很明顯的看到你的TextView中的文字基本上是與icon處於底邊對其,而不是居中對其

只要TextView中加上android:includeFontPadding=“false” 這個屬性屬性就可以了!


更新於2019-01-08