Android 开发小技巧
前言
做了许久的开发,常常有些小细节会打动到我,希望这篇文章可以记录这些分享给大家
布局文件
tools命名空间在预览布局时的应用
在布局编写时常常因查看布局效果会添加一些正式环境不会初始化的属性,比如说 text,visibility... 但是为了初始化效果,这些属性一般会在完成后删除,有时候在维护时为了方便预览再写上,这时可以使用 tools 的命名空间。如
在运行的状态下解析布局文件时就会忽略 tools 属性
android.widget.Space 占位控件
一个占位轻量级控件,绘制过程中会跳过 onDraw() 步骤,使用与分隔不同的控件展示一片空白
Merge 合并标签
此标签可以节省一层布局深度。常常运用在 include 标签之中,一般情况下我们将 include 的根标签用 merge 代替,而不用再新建一个 ViewGroup,同时在自定义继承自系统ViewGroups时在写布局文件时也需要用到,可以避免一层布局深度;可以通过载入一个带有标签的布局文件来自动定义它的子部件
通过 tools:parentTag 可以预览富布局效果
android:duplicateParentState (View属性)
当改属性设置为true时,子View可以复制父View的状态(selected,focused等状态)。比如如果一个ViewGroup是可点击的,那么可以用这个�属性在它被点击的时候让它的子View都改变状态
android:clipChildren (ViewGroup属性)
定义了子View是否仅限于在Padding里绘制。此属性默认设置为true即子View绘制无法超过ViewGroup的padding区域,当设置为false时,那么ViewGroup的子View在绘制的时候会超出它的范围,往往会在做动画的时候需要用到
android:clipToPadding (ViewGroup属性)
定义了ViewGroup是否会裁剪子View调整边缘效果保证padding效果,当ViewGroup设置了padding后该属性默认为true。
运用场景:有时�ScrollView,RecyclerView等会设置一个离顶部toolbar及屏幕底部一定距离来留白,�默认情况下,滚动是在padding范围内的,会出现内容的上下滚动边界离真正的边界有一定的距离。此时只需要将该属性设置为false,滚动时子控件就能�绘制到父控件的padding区域
android:animateLayoutChanges (ViewGroup属性)
ViewGroup中添加或移除View时(对Visibility设置也起作用)设置动画的办法,支持通过setLayoutTransition()自定义动画
android:fillViewport (ScrollView属性)
�该属性�决定了滚动视图是否应该伸展它的内容填补视窗。就是要让ScrollView内部元素的match_parent起作用将该属性设置为true
app:layoutManager (RecyclerView属性)
RecyclerView 可以在 xml 布局文件中设置 LayoutManager,可以不用在代码中创建新的 LayoutManager 实例,RecyclerView 在 style 中已定义
TextView
TextView.setError()
可以设置文字或者文字加上图片,展示一个 popupWindow 效果非常好
TextView去除上下留白
TextView 默认上下是有一定的 padding 的,有时候我们可能不需要上下这部分留白,在 xml 布局文件中加上 includeFontPadding="false"
即可
TextView设置图片
xml布局文件中设置:
或者可以在 �java 代码文件中设置:
Drawable img = ContextCompat.getDrawable(this, R.drawable.icon);
img.setBounds(0,0,100,100);
textView.setCompoundDrawables(img,null,null,null);
/* ********* or ********* */
Drawable img = ContextCompat.getDrawable(this, R.drawable.icon);
textView.setCompoundDrawablesWithIntrinsicBounds(�img,null,null,null);
/* ********* or ********* */
textView.setCompoundDrawablesWithIntrinsicBounds(resId,0,0,0);
TextView在文中设置特殊格式
setText(CharSequence text)
方法可以传入 SpannableString 类展示特殊格式,该类通过 setSpan(Object what, int start, int end, int flags)
方法可以设置各种不同的效果,比如说颜色,背景,点击事件等等,建议通过 SpannableStringBuilder 类得到实例或者 fromHtml(String source)
� 方法得到。
EditView
InputType
可以定义软键盘弹出的类型,在xml布局文件中的EditText标签下直接定义,比如说定义带小数的数字输入
也可以在 java 代码中设置
editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
可以在 xml 文件中设置 android:inputType="textUri"
或者代码中调用 setInputType(InputType.TYPE_TEXT_VARIATION_URI)
实现英文键盘弹出
setKeyListener(KeyListener)
通过 DigitsKeyListener 类,使用 getInstance(String accepted)
方法即可指定EditText可输入字符集
同时也在代码中可以通过 setFilters(InputFilter[] filters)
设置过滤器来实现 EditText 的定向输入。比如说两位小数的输入的自定义 InputFilter
public class DecFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source,
int start, int end, Spanned dest, int dstart, int dend) {
//不能在倒数第三位以前输入点
if (".".equals(source.toString()) && dstart + 2 < dest.length()) return "";
//控制小数位数为两位
String[] splitArray = dest.toString().split("\\.");
if (splitArray.length > 1) {
//如果已经含有两位小数,判断插入的地方是否为小数位,是则过滤
if (splitArray[1].length() == 2 && dstart + 2 >= dest.length()) {
return "";
} else {
return source;
}
}
return source;
}
}
与InputType配合可以实现两位小数输入限制
软键盘适配
为了解决弹出软键盘遮挡 EditText 的冲突,一般会在 manifests 文件对应 activity 标签下添加
但在 EditView 为多行输入且文本高度超过控件高度时,当隐藏键盘后点击超过控件高度的文本位置时,软键盘的弹出会遮盖 EditText,此时需要将 adjustPan 替换成 adjustResize
点击外部隐藏软键盘
可以在activity的基类的 dispatchTouchEvent(MotionEvent ev)
中添加如下方法:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (v != null && (v instanceof EditText)) {
int[] point = {0, 0};
v.getLocationOnScreen(point);
int left = point[0], top = point[1], bottom = top + v.getHeight(), right = left + v.getWidth();
if (!(ev.getRawX() > left && ev.getRawX() < right && ev.getRawY() > top && ev.getRawY() < bottom)) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
v.clearFocus();
}
}
}
return super.dispatchTouchEvent(ev);}
软键盘的监听
Android 系统并没有提供软键盘监听接口,但某些场景却需要对键盘进行监听,此时可以采用特殊的办法,那就是采用 Activity 的
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
当 Activity 的键盘属性是 adjustResize 时,键盘弹出会挤压 activity 的布局,此时可以通过 (bottom - oldBottom > keyHeight) 方法来认为键盘是否弹出,keyHeight 一般认为是屏幕高度的 1/3
RecyclerView
自动测量
在 Support Library 23.2 以后支持自动测量,现在可以非常方便将 Recycler 嵌套在 ScrollView 及其他 ViewGroup 中,可以设置 warp_content 用来自动测量
当嵌套在 ScrollView 中时,因为滑动方向一致导致 RecyclerView 部分会由粘滞感,需要调用方法 setNestedScrollingEnabled(false)
但在高 sdk 上有bug,此时的 RecyclerView 未加载的 item 将不会显示,解决办法是将 ScrollView 替换成 NestedScrollView
自定义View
列举一些对自定义View有帮助的类或方法
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
该方法可以用来清除画布上的内容canvas.clipRect()、clipPath()
该方法可以用来剪切画布区域onDetachedFromWindow
复写该方法中清理与 View 相关的资源getParent().requestDisallowInterceptTouchEvent(true)
方法可以剥夺父 View 对 touch 事件的处理权,可用于滑动冲突ArgbEvaluator.evaluate
用于根据一个起始颜色值和一个结束颜色值以及一个偏移量生成一个新的颜色,�可用于自定义 View 的动画ViewDragHelper
用于自定义 ViewGroup 处理各种事件GestureDetector
用来监听和相应对应的手势事件,比如点击,长按,慢滑动,快滑动ViewConfiguration.getScaledTouchSlop()
触发移动事件的最小距离,这是系统提供的用于自定义 View 处理 touch 事件的时候判断用户是否滑动的最小距离StaticLayout
该类一般用于在自定义 View 中渲染文字Paint.setXfermode(porterDuffXfermode)
在 ApiDemo 里面有专门的介绍,实现了穿透,叠加,覆盖等多种绘制效果,非常实用performClick() 和 performLongClick()
方法可以分别模拟View的点击和长按VelocityTracker
可用于 View 滑动事件速度跟踪
其他
Fragment 类中的 onHiddenChanged(boolean) 方法
该会在 FragmentTransaction 的 hide() 和 show() 调用时被 Fragment 调用,而 Fragment 的其他生命周期方法并不会在此时被调用,所以一般的刷新等操作不能在 onResume() 方法中实现
Fragment.setArguments(Bundle bundle)
在构建 Fragment 的时候不能加参数,我们可以通过将参数传入 Bundle 中,通过此方法传入到 Fragment 实例中(即使在 configuration 改变的时候仍然会导致销毁/重建)
FragmentManager.enableDebugLogging()
可以帮助观察 Fragment 状态
PageTransformer 接口
可以用来定义 ViewPager 页面切换的动画,通过 setPageTransformer(boolean, PageTransformer) 方法实现
Resources 类中的 getIdentifier(name,defType,defPackage)
方法可以通过资源名称获取其ID,可以在多种不同类型资源获取中运用
ViewStub
该类是一个初始化不做任何事情的 View,但是之后可以载入一个布局文件。在慢加载 View 中很适合做占位符。唯一的缺点就是不支持标签,所以如果你不太小心的话,可能会在视图结构中加入不需要的嵌套
View保存为Bitmap
除了ScrollView外可以使用下面方法:
public static Bitmap createBitmap(View v) {
v.setDrawingCacheEnabled(true);
v.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
return bitmap;
}
而ScrollView则需要使用下面方法:
public static Bitmap createBitmap(ScrollView v) {
int width = 0, height = 0;
for (int i = 0; i < v.getChildCount(); i++) {
width += v.getChildAt(i).getWidth();
height += v.getChildAt(i).getHeight();
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
return bitmap;
}
android.text.TextUtils
该类集成了许多关于字符串的常用方法。比如说判断字符串是否为 null 或 "" 的 isEmpty(CharSequence) 方法;判断字符串是否相同的 equals(CharSequence a, CharSequence b) 方法(使用 a.equals(b) 方法需要对 a 做非空判断)等
android.util.Pair
该类可以存储一组数据,但并不是以key-value形式存在,而是两个参数单独存在
android.graphics.PointF
该类可以用来描述坐标点,比起单独的x,y更加方便简洁,还包括了一些简单的坐标计算函数
android.util.SparseArray
当 key 为 int 类型时,SparseArray 可以用来替换 hashMap,它可以避免操作数据池时的大量装箱拆箱过程以便节省内存,提高性能。还有一些继承类 SparseBooleanArray、SparseIntArray 和 SparseLongArray
android.database.DatabaseUtils
类是用于提供操作数据库的�通用方法
java.math.BigDecimal
该类是用于高精度计算的类,可以直接传入字符串,返回�类型和格式可以通过相关方法自定义,较复杂的计算推荐这个类。这个类有一个相关的 DecimalFormat 类,用于字串格式化包括指定位数、百分数、科学计数法等
感谢
Android开发中,有哪些让你觉得相见恨晚的方法、类或接口
awesome-android-tips