文章目录

  • 扫描Context获取Activity
  • 给drawableRight设置点击事件
  • 限制EditText可输入的字数,超出后提示文案
  • 解决RecycleView布局中GridLayoutManager和StaggeredGridLayoutManager添加头部和底部不占用一行的问题
  • 解决由于RecyclerView有刷新头存在,导致canScrollVertically(-1)时始终返回true的bug
  • 获取RecycleView第一个和最后一个可见Item的位置
  • 修改RadioButton的drawableRight图片与文字相隔的距离太大,导致drawablePadding设置无效
  • 解决RadioButton无法重复点击取消选中的状态
  • 解决手动设置Switch的setChecked方法导致setOnCheckedChangeListener触发响应
  • 避免SwipeRefreshLayout重复下拉导致刷新按钮异常显示
  • TextView的drawableLeft与文本无法一起居中显示
  • 控制子View的状态跟随父View状态变化
  • 重力传感监听
  • 网络状态监听
  • RecycleView#LinearLayoutManager滚动到指定位置并距离顶部xxx偏移量
  • RecycleView水平向左滑动弹性收回
  • 限制EditText的最大字数输入
  • 临时申请root权限
  • WebView内容截屏
  • 修改状态栏为透明
  • 修改状态栏背景颜色
  • 修改状态栏文字颜色(白/黑切换)
  • 代码设置选择器
  • 限制EditText小数点后可以输入几位数
  • 点击非EditText区域隐藏软键盘
  • WebView首页重定向后,canGoBack在首页永远返回true,怎么解决?
  • 动态设置shape的圆角
  • 禁用多点触控
  • 屏蔽dialog的焦点
  • View设置缩放中心点
  • android如何监听应用进入后台,回到前台时做相应逻辑
  • Android 软键盘弹出情况下监听返回键直接退出界面
  • 解决App启动时黑屏或者白屏的问题
  • android启动页图片icon拉伸问题完美解决方案
  • 解决RecycleView#StaggeredGridLayoutManager布局,列表滚动时会出现切换动画的问题
  • gradle.properties常用的几个配置说明
  • Java 得到泛型中得到T.class
  • Android textview字体不随系统字体改变
  • 如何设置Dialog的状态栏和虚拟导航栏为透明
  • RecycleView的GridLayoutManager布局自适应高度
  • 清空ViewPager显示Fragment的时的缓存

扫描Context获取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的引用是否有效,例如:

@Overridepublic 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 */@Overridepublic 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 */@Overridepublic 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 */@Overridepublic 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;                }            });        }    }}

前提是得确定头部和尾部的位置,即isHeaderViewPosition和isFooterViewPosition的逻辑了.通过adapter就可以计算出是否是头部还是尾部的位置了.

解决由于RecyclerView有刷新头存在,导致canScrollVertically(-1)时始终返回true的bug

 @Override public boolean canScrollVertically(int direction) {      if (direction < 1) {          boolean original = super.canScrollVertically(direction);          int firstVisiblePosition = getFirstVisiblePosition();          if (!original || getChildAt(0) != null && getChildAt(0).getTop() >= 0) {              LayoutManager layoutManager = getLayoutManager();              if (layoutManager instanceof LinearLayoutManager) {                  return firstVisiblePosition > 0;              } else if (layoutManager instanceof StaggeredGridLayoutManager) {                  int spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();                  return firstVisiblePosition > spanCount;              } else if (layoutManager instanceof GridLayoutManager) {                  int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();                  return firstVisiblePosition > spanCount;              }          } 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方法

@Overrideprotected 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方法

@Overridepublic 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” 这个属性属性就可以了!

控制子View的状态跟随父View状态变化

代码设置 :
setDuplicateParentStateEnabled(true)

布局设置:
android:duplicateParentState="true"

更新于2019-01-08

重力传感监听

public class MySensorHelper {    private static final String TAG = MySensorHelper.class.getSimpleName();    private OrientationEventListener mLandOrientationListener;    private OrientationEventListener mPortOrientationListener;    public interface Callback {        void onOrientationChange(int orientation);    }    public MySensorHelper(final Activity activity, final Callback callback) {        this.mLandOrientationListener = new OrientationEventListener(activity, 3) {            public void onOrientationChanged(int orientation) {                Log.d(MySensorHelper.TAG, "mLandOrientationListener");                if (orientation < 100 && orientation > 80 || orientation < 280 && orientation > 260) {                    Log.e(MySensorHelper.TAG, "转到了横屏");                    if (callback != null) {                        Log.e(MySensorHelper.TAG, "转到了横屏##################");                        callback.onOrientationChange(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);                    }                }            }        };        this.mPortOrientationListener = new OrientationEventListener(activity, 3) {            public void onOrientationChanged(int orientation) {                Log.w(MySensorHelper.TAG, "mPortOrientationListener");                if (orientation < 10 || orientation > 350 || orientation < 190 && orientation > 170) {                    Log.e(MySensorHelper.TAG, "转到了竖屏");                    if (callback != null) {                        Log.e(MySensorHelper.TAG, "转到了竖屏!!!!!!!!!!!!!!!!!!!!!!");                        callback.onOrientationChange(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);                    }                }            }        };        this.enable();    }    //禁用切换屏幕的开关    public void disable() {        Log.e(TAG, "disable");        this.mPortOrientationListener.disable();        this.mLandOrientationListener.disable();    }    //开启横竖屏切换的开关    public void enable() {        this.mPortOrientationListener.enable();        this.mLandOrientationListener.enable();    }}

网络状态监听

public class NetworkConnectChangedReceiver extends BroadcastReceiver {    private static final String TAG = "Network";    private Callback mCallback;    public abstract static class Callback {        /** * wifi是否打开 * * @param isEnable */        public void isWifiEnable(boolean isEnable) {        }        /** * 各种状态监听 * * @param wifi * @param mobile * @param all */        public void isAvailable(boolean wifi, boolean mobile, boolean all) {        }    }    public NetworkConnectChangedReceiver(Callback callback) {        this.mCallback = callback;    }    public IntentFilter getIntentFilter() {        IntentFilter filter = new IntentFilter();        filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");        filter.addAction("android.net.wifi.WIFI_STATE_CHANGED");        filter.addAction("android.net.wifi.STATE_CHANGE");        return filter;    }    @Override    public void onReceive(Context context, Intent intent) {        // 这个监听wifi的打开与关闭,与wifi的连接无关        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);            Log.e(TAG, "wifiState" + wifiState);            switch (wifiState) {                case WifiManager.WIFI_STATE_DISABLED:                    mCallback.isWifiEnable(false);                    break;                case WifiManager.WIFI_STATE_DISABLING:                    break;                case WifiManager.WIFI_STATE_ENABLING:                    break;                case WifiManager.WIFI_STATE_ENABLED:                    mCallback.isWifiEnable(true);                    break;                case WifiManager.WIFI_STATE_UNKNOWN:                    break;                default:                    break;            }        }        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {            ConnectivityManager manager = (ConnectivityManager) context                    .getSystemService(Context.CONNECTIVITY_SERVICE);            Log.i(TAG, "CONNECTIVITY_ACTION");            NetworkInfo activeNetwork = manager.getActiveNetworkInfo();            if (activeNetwork != null) { // connected to the internet                if (activeNetwork.isConnected()) {                    if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {                        // connected to wifi                        Log.e(TAG, "当前WiFi连接可用 ");                        mCallback.isAvailable(true, false, true);                    } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {                        // connected to the mobile provider's data plan                        Log.e(TAG, "当前移动网络连接可用 ");                        mCallback.isAvailable(false, true, true);                    }                } else {                    Log.e(TAG, "当前没有网络连接,请确保你已经打开网络 ");                    mCallback.isAvailable(false, false, false);                }            } else {   // not connected to the internet                Log.e(TAG, "当前没有网络连接,请确保你已经打开网络 ");                mCallback.isAvailable(false, false, false);            }        }    }}

使用方式

private NetworkConnectChangedReceiver mConnectChangedReceiver;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    mConnectChangedReceiver = new NetworkConnectChangedReceiver(new NetworkConnectChangedReceiver.Callback() {        @Override        public void isAvailable(boolean wifi, boolean mobile, boolean all) {            if (wifi) {                //dosth..            }else if(mobile){            //dosth...}        }    });    registerReceiver(mConnectChangedReceiver, mConnectChangedReceiver.getIntentFilter());}@Overrideprotected void onDestroy() {    super.onDestroy();    unregisterReceiver(mConnectChangedReceiver);}

更新于2019-01-10

RecycleView#LinearLayoutManager滚动到指定位置并距离顶部xxx偏移量

 LinearLayoutManager layoutManager = (LinearLayoutManager) mRv.getLayoutManager(); int itemWidth = DisplayUtils.dip2px(mContext, 51);//item的宽度 //item位于中心显示的偏移量 int pinkPx = (int) ((Env.screenWidth - 2 * mRv.getPaddingLeft() - itemWidth) * 0.5f); //定位到指定的position并且该position对应的item距离RecycleView顶部的距离是pinkPx  layoutManager.scrollToPositionWithOffset(currIndex, pinkPx);

#更新于2019-01-17

RecycleView水平向左滑动弹性收回

重写RecycleView的onTouchEvent方法

private float downTouch;    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                downTouch = event.getX();                break;            case MotionEvent.ACTION_MOVE:                float moveTouch = event.getX();                if (!canScrollHorizontally(1)) {                    int deltaX = (int) (downTouch - moveTouch);                    if (deltaX > 10) {                    //向左滑动到底后,修改其右内边距不断递增                        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight() + deltaX / 3, getPaddingBottom());                    }                } else {                //恢复原位                    setPadding(getPaddingLeft(), getPaddingTop(), 0, getPaddingBottom());                }                downTouch = moveTouch;                break;            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:            //恢复原位                setPadding(getPaddingLeft(), getPaddingTop(), 0, getPaddingBottom());                break;        }        return super.onTouchEvent(event);    }

如果还需要实现回滚完毕后跳去新页面,则可以监听其滚动,当滚动停止的时候就可以跳去新页面了.
例如:

OverScrollRecycleView osRv = findViewById(R.id.rv_over_scroll);osRv.addOnScrollListener(new RecyclerView.OnScrollListener() {    @Override    public void onScrollStateChanged(RecyclerView rv, int newState) {             if (newState == RecyclerView.SCROLL_STATE_IDLE && !rv.canScrollHorizontally(1)) {            Intent intent = new Intent(mContext, NextActivity.class);            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);//避免打开同一个Activity多次            startActivity(intent);        }    }});

#更新于2019-01-24

限制EditText的最大字数输入

例如限制EditText最大只能输入150个字,超出后提示文案

private class LengthInputFilter extends InputFilter.LengthFilter {               public LengthInputFilter(int max) {            super(max);        }        @Override        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {            CharSequence s = super.filter(source, start, end, dest, dstart, dend);            if (s != null) {            //getMax是LengthFilter的内部方法,返回的是构造方法传入的max                ToastUtils.show(mContext, "不能超过" + getMax()+ "字", Toast.LENGTH_SHORT);            }            return s;        }    }

使用方式如下:

 mInputEdt.setFilters(new InputFilter[]{new LengthInputFilter(150)});

更新于2019-01-26

临时申请root权限

前提是设备已经root过了.

public void testRoot() {        try {            Process su = Runtime.getRuntime().exec("su");            OutputStream outputStream = su.getOutputStream();            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);            dataOutputStream.writeBytes("\n");            dataOutputStream.flush();        } catch (IOException e) {            e.printStackTrace();        }    }

更新于2019-01-30

WebView内容截屏

/** * Android 5.0以下版本 * 此方法用在5.0以上时需在创建webView之前调用enableSlowWholeDocumentDraw()方法关闭优化才能截取到这个WebView内容 * 对WebView进行截屏 * * @param webView * @return */    public static Bitmap getWebViewLongBitmpKitKat(WebView webView) {        Picture picture = webView.capturePicture();        int width = picture.getWidth();        int height = picture.getHeight();        if (width > 0 && height > 0) {            Bitmap bitmap = Bitmap.createBitmap(webView.getWidth(), (int) (webView.getContentHeight() * webView.getScale()), Bitmap.Config.RGB_565);            Canvas canvas = new Canvas(bitmap);            picture.draw(canvas);            return bitmap;        }        return null;    }

修改状态栏为透明

/** * 修改状态栏为透明效果 */    public static void setStatusBarTrans(Activity activity) {        //5.0及以上,修改完后,布局会延伸到状态栏        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            Window window = activity.getWindow();            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);            window.setStatusBarColor(Color.TRANSPARENT);        }        //4.4到5.0        else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            WindowManager.LayoutParams localLayoutParams = activity.getWindow().getAttributes();            localLayoutParams.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS |                    localLayoutParams.flags;        }    }

修改状态栏背景颜色

/** * 修改状态栏颜色,支持4.4以上版本 * * @param activity * @param colorId */    public static void setStatusBarColor(Activity activity, int colorId) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            Window window = activity.getWindow();            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);            window.setStatusBarColor(activity.getResources().getColor(colorId));        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            //使用SystemBarTint库使4.4版本状态栏变色,需要先将状态栏设置为透明            WindowManager.LayoutParams localLayoutParams = activity.getWindow().getAttributes();            localLayoutParams.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS |                    localLayoutParams.flags;//需要引入依赖包 compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'            SystemBarTintManager tintManager = new SystemBarTintManager(activity);            tintManager.setStatusBarTintEnabled(true);            tintManager.setStatusBarTintResource(colorId);        }    }

修改状态栏文字颜色(白/黑切换)

 /** * android 4.4及以上修改状态栏文字的颜色 * 修改状态栏文字颜色,这里小米,魅族区别对待。 */    public static void setLightStatusBar(final Activity activity, final boolean dark) {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            switch (RomUtils.getLightStatusBarAvailableRomType()) {                case RomUtils.AvailableRomType.MIUI:                    setMIUIStatusBarLightMode(activity, dark);                    break;                case RomUtils.AvailableRomType.FLYME:                    setFlymeLightStatusBar(activity, dark);                    break;                default:                    setAndroidNativeLightStatusBar(activity, dark);                    break;            }        }    }    /** * 小米系统下状态栏文字颜色的修改 * * @param activity * @param dark true:黑色 false: 白色 * @return */    public static boolean setMIUIStatusBarLightMode(Activity activity, boolean dark) {        boolean result = false;        Window window = activity.getWindow();        if (window != null) {            Class clazz = window.getClass();            try {                int darkModeFlag = 0;                Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");                Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");                darkModeFlag = field.getInt(layoutParams);                Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);                if (dark) {                    extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体                } else {                    extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体                }                result = true;                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && RomUtils.isMiUIV7OrAbove()) {                    //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上                    if (dark) {                        activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);                    } else {                        activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);                    }                }            } catch (Exception e) {            }        }        return result;    }    /** * 魅族系统状态栏文字颜色修改 * * @param activity * @param dark true:黑色 false: 白色 * @return */    private static boolean setFlymeLightStatusBar(Activity activity, boolean dark) {        boolean result = false;        if (activity != null) {            try {                WindowManager.LayoutParams lp = activity.getWindow().getAttributes();                Field darkFlag = WindowManager.LayoutParams.class                        .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");                Field meizuFlags = WindowManager.LayoutParams.class                        .getDeclaredField("meizuFlags");                darkFlag.setAccessible(true);                meizuFlags.setAccessible(true);                int bit = darkFlag.getInt(null);                int value = meizuFlags.getInt(lp);                if (dark) {                    value |= bit;                } else {                    value &= ~bit;                }                meizuFlags.setInt(lp, value);                activity.getWindow().setAttributes(lp);                result = true;            } catch (Exception e) {            }        }        return result;    }   /** * 修改状态栏文字颜色 * @param activity * @param dark true:深色,false:白色 */    private static void setAndroidNativeLightStatusBar(Activity activity, boolean dark) {        View decor = activity.getWindow().getDecorView();        if (dark) {            //设置字体为深色            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //6.0+                decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);            }else{ //6.0以下无法修改状态栏文字的颜色,只能通过修改状态栏颜色为暗色来区分白色的字体                setStatusBarColor(activity, R.color.color_10Black); //调用前面例子的方法            }        } else {            //恢复字体为白色            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //6.0+                decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);            }else{ //6.0以下无法修改状态栏文字的颜色,默认就是白色,将之前设置状态栏的颜色去掉                setStatusBarColor(activity, R.color.full_transparent);            }        }    }

更新于2019-02-28

代码设置选择器

1.文字颜色选择器

//选择器状态是二维数组,负数表示false,正数表示trueint[][] states = new int[][]{         new int[]{-android.R.attr.state_selected}, // unselected         new int[]{android.R.attr.state_selected}  // selected }; //对应状态的颜色值 int[] colors = new int[]{         getResources().getColor(R.color.color_121C35),         getResources().getColor(R.color.color_FF3B3B) }; //设置文字颜色选择器ColorStateList TextView textView = new TextView(getContext()); textView.setTextColor(new ColorStateList(states, colors));

2.图片背景选择器

//创建图片选择器StateListDrawable stateListDrawable = new StateListDrawable();    //添加状态和对应的图片,同样状态是负数表示false,反之表示true    stateListDrawable.addState(new int[]{-android.R.attr.state_checked}, getDrawable(android.R.drawable.ic_item_normal));    stateListDrawable.addState(new int[]{android.R.attr.state_checked}, getDrawable(android.R.drawable.ic_item_checked));    //直接设置背景为图片选择器    ImageView imageView = new ImageView(getContext());    imageView.setImageDrawable(stateListDrawable);

更新于2019-03-05

限制EditText小数点后可以输入几位数

/** * 保留多少位小数 * * @param expectPriceEdt * @param remainCount 保留几位小数,例如保留2位小数,那么小数点后只能输入2位数 */    public static void formatNumInput(EditText expectPriceEdt, final int remainCount) {        expectPriceEdt.addTextChangedListener(new TextWatcher() {            public void afterTextChanged(Editable edt) {                String temp = edt.toString();                int posDot = temp.indexOf(".");                if (posDot <= 0) return;                if (temp.length() - posDot - 1 > remainCount) {                    edt.delete(posDot + 3, posDot + 4);                }            }            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {            }            public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {            }        });    }

点击非EditText区域隐藏软键盘

//点击其他区域隐藏软键盘后还是否需要响应当次的点击事件    private boolean clickShouldRspAfterSoftInputHide;//重写Activity的事件分发方法,点击输入框以外的区域隐藏软键盘    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            View v = getCurrentFocus();            if (isShouldHideInput(v, ev)) {                if (hideInputMethod(v) && !clickShouldRspAfterSoftInputHide) {               /**直接返回true表示不会向下继续分发事件了 如果点击的view还需要响应事件,那么clickShouldRspAfterSoftInputHide设置为true **/                    return true;                 }            }        }        return super.dispatchTouchEvent(ev);    }//判断是否要隐藏软键盘    public boolean isShouldHideInput(View v, MotionEvent event) {        if (v != null && (v instanceof EditText)) {            int[] leftTop = {0, 0};            v.getLocationInWindow(leftTop);//获取控件在屏幕的坐标            int left = leftTop[0], top = leftTop[1], bottom = top + v.getHeight(), right = left                    + v.getWidth();            if (event.getRawX() > left && event.getRawX() < right                    && event.getRawY() > top && event.getRawY() < bottom) {                // 点击的范围是当前EditText,不用隐藏软键盘                return false;            } else {                return true;//需要隐藏软键盘            }        }        return false;    }    public Boolean hideInputMethod(View v) {        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);        if (imm != null) {            return imm.hideSoftInputFromWindow(v.getWindowToken(), 0);        }        return false;    }

更新于2019-03-07

WebView首页重定向后,canGoBack在首页永远返回true,怎么解决?

@Override    public void onBackPressed() {        //后退        if (mWebView.canGoBack()) {                       WebBackForwardList list = mWebView.copyBackForwardList();            if (list.getCurrentIndex() ==0) {                //如果首页重定向后,初始地址会变成data:text/html;charset=utf-8;base64,                String firstUrl = list.getItemAtIndex(0).getUrl();                if (!URLUtil.isNetworkUrl(firstUrl)) {                    //避免首次进入重定向的时候退不出webview                    super.onBackPressed();                    return;                }            }            mWebView.goBack();        } else {            super.onBackPressed();        }    }

更新于2019-03-08

动态设置shape的圆角

假设布局里面已经给View设置了一个shape作为背景图片了,如果我想在代码中修改它的圆角的话,可以通过这种方式修改:

//圆角为8dp final int dp8 = DisplayUtils.dip2px(mContext, 8); //先找到设置了shape的viewConstraintLayout item= findViewById(R.id.cl_content);//获取shape图形GradientDrawable drawable = (GradientDrawable) item.getBackground();//左上,右上,右下,左下 必须传8个值,每2个为一个方向drawable.setCornerRadii(new float[]{dp8, dp8, dp8, dp8, dp8, dp8, dp8, dp8});

更新于2019-03-13

禁用多点触控

两种方式:

1、禁用全局多点触控:

在application引用的Theme中添加以下代码:

  <item name="android:windowEnableSplitTouch">falseitem>  <item name="android:splitMotionEvents">falseitem>

2、如果要单独对某个界面禁用,则需要的在相应的xml或代码中添加:

android:splitMotionEvents="false"
rootLayout.setMotionEventSplittingEnabled(false);

注意:必须是需要禁止多点触控的控件的上层父类中添加! 父类的父类加了无效。 另外,该属性实在Android API level 11 之后才有的。

更新于2019-03-25

屏蔽dialog的焦点

window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

View设置缩放中心点

用过ScaleAnimation的人都知道,可以直接在构造方法中设置,但是如果是使用ObjectAnimator或者是直接setScaleX和setScaleY的方式那要怎么设置缩放中心点呢??

答案是使用View的setPivotX和setPivotY方法单独设置,源码如下:

/** * Sets the x location of the point around which the view is * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. * By default, the pivot point is centered on the object. * Setting this property disables this behavior and causes the view to use only the * explicitly set pivotX and pivotY values. * * @param pivotX The x location of the pivot point. * @see #getRotation() * @see #getScaleX() * @see #getScaleY() * @see #getPivotY() * * @attr ref android.R.styleable#View_transformPivotX */    public void setPivotX(float pivotX) {        if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {            invalidateViewProperty(true, false);            mRenderNode.setPivotX(pivotX);            invalidateViewProperty(false, true);            invalidateParentIfNeededAndWasQuickRejected();        }    } /** * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. * Setting this property disables this behavior and causes the view to use only the * explicitly set pivotX and pivotY values. * * @param pivotY The y location of the pivot point. * @see #getRotation() * @see #getScaleX() * @see #getScaleY() * @see #getPivotY() * * @attr ref android.R.styleable#View_transformPivotY */    public void setPivotY(float pivotY) {        if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {            invalidateViewProperty(true, false);            mRenderNode.setPivotY(pivotY);            invalidateViewProperty(false, true);            invalidateParentIfNeededAndWasQuickRejected();        }    }

例如设置右下角为缩放中心点可以这样弄target.setPivotX(target.getWidth());target.setPivotY(target.getHeight());

更新于2019-04-15

android如何监听应用进入后台,回到前台时做相应逻辑

详情看这里

更新于2019-04-17

Android 软键盘弹出情况下监听返回键直接退出界面

详情看这里

更新于2019-04-23

解决App启动时黑屏或者白屏的问题

将启动图通过样式的方式设置

<style name="AppTheme.Splash" parent="@style/Theme.AppCompat.NoActionBar"> "android:windowFullscreen">true "android:windowNoTitle">true  "android:windowBackground">@drawable/app_launcher_360  "android:background">@null style>

然后在启动Activity使用该样式

<activity android:name=".module.main.LaunchActivity" android:alwaysRetainTaskState="true" android:screenOrientation="portrait" android:theme="@style/AppTheme.Splash">       <intent-filter>        <action android:name="android.intent.action.MAIN"/>        <category android:name="android.intent.category.LAUNCHER"/>    intent-filter>activity>

然后LaunchActivity就不需要做任何操作了,如果启动图还有广告图的话,那只需要在布局中添加广告图的布局,代码中书写广告的

加载逻辑就可以了,无需关心默认的启动图,因为广告图显示的时候会自动覆盖默认的的启动图.

例如:

protected void initView() {   mTimerTv = findViewById(R.id.tv_timer);//计时器   mLaunchAdIv = findViewById(R.id.iv_launch_ad);//启动图广告   if (null != mLaunchAdv && URLUtil.isNetworkUrl(mLaunchAdv.image)) {       ImageLoadUtils.disPlay(mLaunchAdv.image, mLaunchAdIv);//加载启动图       showLaunchAd(); //显示启动图布局   } else {       dealLaunchNormal();//处理正常跳转   }}//正常跳转private void dealLaunchNormal() {   if (isFirstInstall) { //首次安装       jump2Guide(); //进入新手引导   } else {       jump2Main(); //进入首页   }}

更新于2019-04-23

android启动页图片icon拉伸问题完美解决方案

查看详情

更新于2019-04-26

解决RecycleView#StaggeredGridLayoutManager布局,列表滚动时会出现切换动画的问题

由于瀑布流布局,每个item的高度都是不定的,所以当滑动了很多页的时候,滚出屏幕的item已经回收掉了,而当再次滑动回到列表顶部的时候,由于item需要重新布局,所以会看到切换动画, 解决办法如下:

步骤一: 去掉切换动画

StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE); //禁止瀑布流切换动画,问题是顶部会留白mRecyclerView.setLayoutManager(layoutManager);mRecyclerView.setAdapter(new MyAdapter(mContext, mData));

步骤二:解决顶部留白的问题

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {   boolean hasNotify = true;    int topLastVisibleItemPosition = -1;//上次刷新时,最后一个可见item的位置    @Override    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {        super.onScrollStateChanged(recyclerView, newState);        //获取实时滚动的列表top和bottom可见位置        int firstVisiblePosition = mRecyclerView.getFirstVisiblePosition();        int lastVisibleItemPosition = mRecyclerView.getLastVisibleItemPosition();        //解决顶部留白的问题        if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE                && !mRecyclerView.canScrollVertically(-1)) {            if (mRecyclerView.getAdapter() != null && !hasNotify) {                hasNotify = true;                topLastVisibleItemPosition = lastVisibleItemPosition;                //刷新列表,留白就看不到了.                mRecyclerView.getAdapter().notifyDataSetChanged();                LogUtils.e("cys", "置顶刷新");            }        }        // 当前列表最后一个可见item的位置如果大于上次刷新时的位置,所以列表已经向上拖拽过了,这个时候才需要重置变量hasNotify         if (firstVisiblePosition > topLastVisibleItemPosition) {            hasNotify = false; //避免重复刷新列表            LogUtils.e("cys", "重置hasNotify = false");        }    }});

更新于2019/05/16

gradle.properties常用的几个配置说明

org.gradle.jvmargs=-Xmx1536m : 用来加快gradle的编译!

android.enableAapt2=false

Error:java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception:

android.useDeprecatedNdk=true

Error:(12, 0) Error: NDK integration is deprecated in the current plugin.
Consider trying the new experimental plugin.
For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.
Set “android.useDeprecatedNdk=true” in gradle.properties to continue using the current NDK integration.

android.injected.testOnly=false
让debug包也可以下载安装.

Java 得到泛型中得到T.class

Class <T> entityClass = (Class <T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 

更新于2019/06/4

Android textview字体不随系统字体改变

方式1:把textview的字体大小设置为PX为单位,原因是px不随系统而改变。

方式2:在BaseActivity重写 getResources()方法,具体代码如下

//字体不随系统字体改变@Override public Resources getResources() {     Resources resources = super.getResources();     Configuration config = new Configuration();     config.setToDefaults();     resources.updateConfiguration(config, resources.getDisplayMetrics());     return resources; }

更新于2019/06/12

如何设置Dialog的状态栏和虚拟导航栏为透明

方式一:
在style文件中添加自定义样式,并继承@android:style/Theme.Dialog

<item name="android:windowTranslucentStatus">trueitem><item name="android:statusBarColor">@android:color/transparentitem><item name="android:windowTranslucentNavigation">trueitem>

然后,自定义的Dialog的构造方法中使用该样式
super(context, R.style.myDialog);

方式二:
代码设置,在自定义的Dialog中加入这段代码

Window window = getWindow();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    //导航栏透明    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);    //状态栏透明,这个其实也可以不用设置,上面那条flag也有这个效果    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);}

需要强调一点的是,导航栏是在App页面的最上面的,所以透明后,是可以看到dialog的背景的.

更新于2019/06/27

RecycleView的GridLayoutManager布局自适应高度

package com.juchaozhi.classification;import android.content.Context;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;/** * 自适应高度的GridLayoutManager * Created by mChenys on 2019/7/24. */public class WrapHeightGridLayoutManager extends GridLayoutManager {    private int mChildPerLines;//每一行的子View 个数    private int[] mMeasuredDimension = new int[2];    public WrapHeightGridLayoutManager(Context context, int spanCount) {        super(context, spanCount);        this.mChildPerLines = spanCount;    }    @Override    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {        final int heightMode = View.MeasureSpec.getMode(heightSpec);        final int widthSize = View.MeasureSpec.getSize(widthSpec);        final int heightSize = View.MeasureSpec.getSize(heightSpec);        int height = 0;        for (int i = 0; i < getItemCount(); ) {            measureScrapChild(recycler, i,                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),                    mMeasuredDimension);            height = height + mMeasuredDimension[1];//累计每一行的高度            i = i + mChildPerLines;        }        if (height < heightSize) {            switch (heightMode) {                case View.MeasureSpec.EXACTLY:                    height = heightSize;                case View.MeasureSpec.AT_MOST:                case View.MeasureSpec.UNSPECIFIED:            }            setMeasuredDimension(widthSize, height + getPaddingTop() + getPaddingBottom());        } else {            // If child view is more than screen size, there is no need to make it wrap content. We can use original onMeasure() so we can scroll view.            super.onMeasure(recycler, state, widthSpec, heightSpec);        }    }    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,                                   int heightSpec, int[] measuredDimension) {        View view = recycler.getViewForPosition(position);        // For adding Item Decor Insets to view        super.measureChildWithMargins(view, 0, 0);        if (view != null) {            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,                    getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view), p.width);            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,                    getPaddingTop() + getPaddingBottom() + getPaddingBottom() + getDecoratedBottom(view), p.height);            view.measure(childWidthSpec, childHeightSpec);            // Get decorated measurements            measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;            measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;            recycler.recycleView(view);        }    }}

更新于2019/07/27

清空ViewPager显示Fragment的时的缓存

if (mContentVp.getAdapter() != null) {     Class<? extends FragmentManager> aClass = getChildFragmentManager().getClass();     try {         Field f = aClass.getDeclaredField("mAdded");         f.setAccessible(true);         ArrayList<Fragment> list = (ArrayList) f.get(getChildFragmentManager());         list.clear();         f = aClass.getDeclaredField("mActive");         f.setAccessible(true);         SparseArray<Fragment> array = (SparseArray) f.get(getChildFragmentManager());         array.clear();     } catch (Exception e) {         e.printStackTrace();     } }

这个得从FragmentPagerAdapter的instantiateItem方法查看

public Object instantiateItem(ViewGroup container, int position) {    if (mCurTransaction == null) {        mCurTransaction = mFragmentManager.beginTransaction();    }    final long itemId = getItemId(position);    // Do we already have this fragment?    String name = makeFragmentName(container.getId(), itemId);    Fragment fragment = mFragmentManager.findFragmentByTag(name);    if (fragment != null) {        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);        mCurTransaction.attach(fragment);    } else {        fragment = getItem(position);        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);        mCurTransaction.add(container.getId(), fragment,                makeFragmentName(container.getId(), itemId));    }    if (fragment != mCurrentPrimaryItem) {        fragment.setMenuVisibility(false);        fragment.setUserVisibleHint(false);    }    return fragment;}

定位到这一句mFragmentManager.findFragmentByTag(name);,继续查找FragmentManager的实现类FragmentManagerImpl
中的findFragmentByTag方法

public Fragment findFragmentByTag(String tag) {    if (tag != null) {        // First look through added fragments.        for (int i=mAdded.size()-1; i>=0; i--) {            Fragment f = mAdded.get(i);            if (f != null && tag.equals(f.mTag)) {                return f;            }        }    }    if (mActive != null && tag != null) {        // Now for any known fragment.        for (int i=mActive.size()-1; i>=0; i--) {            Fragment f = mActive.valueAt(i);            if (f != null && tag.equals(f.mTag)) {                return f;            }        }    }    return null;}

观察mAdded和mActive 变量,他们就是用来存储Fragment的容器

final ArrayList<Fragment> mAdded = new ArrayList<>();SparseArray<Fragment> mActive;

所以如果想要ViewPager重新初始化已加载的Fragment的话,就得通过反射清空这2个容器.

更新于2019/08/7

更多相关文章

  1. Android(安卓)7.0 Audio :通话中的音频调用接口
  2. CMake相关问题解决记录
  3. eclipse 中设置android emulator 选项
  4. Android(安卓)TextView当中设置超链接、颜色、字体
  5. 无法在Android(安卓)Studio中设置断点
  6. 安卓新技术学习资料整理 常更新哦~
  7. android Application Component研究之Activity(一)
  8. 14天学会安卓开发(第十一天)Android图形技术
  9. android Gradle例如:“style attribute 'android:attr/keyboardNa

随机推荐

  1. Android成长记(1)-----android环境搭建与
  2. Android WebView JavaScript交互
  3. Android四种布局
  4. android系统权限大全
  5. Android基础之CursorAdapter 的用法与获
  6. Android MediaProvider详解(基础篇)
  7. android QQ好友分享
  8. Android FTP客户端使用,快速上传文件
  9. Cocos2dx setup Eclipse environment for
  10. Android 之shape