Android 开发中不得不知道的 Tips 集合
来源:互联网 发布:淘宝零点抢购怎么抢 编辑:程序博客网 时间:2024/05/16 04:47
1.你还在写Drawable来实现Imageview的点击效果?
很多时候我们需要给ImageView添加点击效果,例如title上的back按钮。
通常来讲,UI那边会给我们两张图,一张选中效果,一张nomal效果;我们会风骚的撸一个Drawable
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 按压时 --> <item android:drawable="@mipmap/btn_enter_pressed" android:state_pressed="true" /> <!-- 默认时 --> <item android:drawable="@mipmap/btn_enter_normal" /></selector>
然后在布局文件中把Imageview的background属性设置成你写的Drawable文件。例如:
<ImageView android:id="@+id/tv_login" android:layout_width="60dp" android:layout_height="60dp" android:background="@drawable/back_click" />
这样当然没问题,毕竟都是大家熟悉的套路。不料,你突然接到了一个需求,为了支持动态换肤,这个back的图片需要从网络上获取,并且仍然需要支持点击效果。顿时,无数程序猿心中众多那个啥在奔腾。
解决方案:
继承ImageView,监听OnTouchListener的事件,动态设置setColorFilter
public class ClickImageView extends AppCompatImageView { public ClickImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public ClickImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ClickImageView(Context context) { super(context); init(); } private void init() { setOnTouchListener(onTouchListener); } private OnTouchListener onTouchListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: setColorFilter(null); break; case MotionEvent.ACTION_DOWN: changeLight(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_CANCEL: setColorFilter(null); break; default: break; } return false; } }; private void changeLight() { int brightness = -80; ColorMatrix matrix = new ColorMatrix(); matrix.set(new float[]{1, 0, 0, 0, brightness, 0, 1, 0, 0, brightness, 0, 0, 1, 0, brightness, 0, 0, 0, 1, 0}); setColorFilter(new ColorMatrixColorFilter(matrix)); }}
布局文件中这么搞妥了
<你的包名.ClickImageView android:id="@+id/iv_share" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/act_ic_share" />
2.WebView加载视频or音频时候的二次元世界
现在APP里面怎么能少的了WebView的舞台呢?不过加载如下网页的时候会有坑
没错,这个网页里面有视频,用户播放视频,然后点击了返回键,此时如果直接finish掉当前的WebActivity时会出现灵异的现象:刚才看的视频仍然在播放,仍然会有声音发出。除非你exit掉咱们的App。
解决方案:
在WebActivity中控制一下WebView,亲测有效
@Override protected void onResume() { super.onResume(); wb_content.onResume(); } @Override protected void onDestroy() { super.onDestroy(); wb_content.destroy(); //手动销毁WebView } @Override protected void onPause() { super.onPause(); wb_content.onPause(); }
3.是时候从Rxjava1换到Rxjava2啦
还没玩过Rxjava的同学们建议直接从Rxjava2学起,现在还在奋斗在Rxjava1的同学们建议尽快转到Rxjava2的战线。Rxjava1很快就停止更新了。废话不多说,直接祭出官方wiki
https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0
4.控制Recyclerview滑动的问题
很多场景下,产品需要我们通过代码控制Recyclerview滑动到第几个position,例如:用户下拉刷新当天节目列表,我们应该计算当前时间播放的是第几个节目,然后滑动到这个position,注:此时这个position应该居于屏幕的中间
解决方案:
这里只说一下LinearLayoutManager下的解决方式
public class CenterLayoutManager extends LinearLayoutManager { public CenterLayoutManager(Context context) { super(context); } public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext()); smoothScroller.setTargetPosition(position); startSmoothScroll(smoothScroller); } private static class CenterSmoothScroller extends LinearSmoothScroller { CenterSmoothScroller(Context context) { super(context); } @Override public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2); } }}
然后使用Recyclerview的时候,设置LayoutManager为CenterLayoutManager。需要滚动到第几个item直接调用
recyclerview.smoothScrollToPosition(position);
就妥啦。效果如下。
1.sp还是dp?
众所周知,官方建议我们字体的单位使用sp,这样用户在“系统设置”中调整了系统字体大小的时候,我们app中的字体会随着系统字体的大小而改变。So,众猿机智的在布局文件中写下了以下代码
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="this is text" android:textSize="15sp" />
当然上述TextView不会有什么问题,因为这货height是自适应的。但是很多情境下,例如ListView或者Recyclerview的item中,高度是固定的时候,sp就会有适配问题,例如
解决方案:
在Application中重写onConfigurationChanged 强制字体不随着系统改变而改变(微信也是这么干的)
@Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig.fontScale != 1)//非默认值 getResources(); super.onConfigurationChanged(newConfig); } @Override public Resources getResources() { Resources res = super.getResources(); if (res.getConfiguration().fontScale != 1) {//非默认值 Configuration newConfig = new Configuration(); newConfig.setToDefaults(); //设置默认 res.updateConfiguration(newConfig, res.getDisplayMetrics()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { createConfigurationContext(newConfig); } else { res.updateConfiguration(newConfig, res.getDisplayMetrics()); } } return res; }
2.使用PhotoView+Viewpager崩溃问题
这几天碰到一个诡异的问题,PhotoView+Viewpager开发图集效果的时候,在三星Galxy系列手机上手指放大的时候没问题,手指捏合的时候出现java.lang.IllegalArgumentException: pointerIndex out of range 异常然后闪退。Google了一波,说是三星系统的Bug。。。我等应用层开发汪总不见得给每个三星用户修改一下底层代码吧。
解决方案:
自定义一个Viewpager,重写onInterceptTouchEvent函数,在里面捕获IllegalArgumentException就妥了。
public class PhotoViewPager extends android.support.v4.view.ViewPager { public PhotoViewPager(Context context) { super(context); } public PhotoViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent ev) { try { return super.onTouchEvent(ev); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } return false; }}
布局文件中用PhotoViewPager代替系统原生的ViewPager就好啦。
3.什么?DatePickerDialog有Bug?
项目中用到了修改用户生日的功能,打算直接用DatePickerDialog来做一个时间选择起,然后诡异的事情发生了。用户选择完时间之后onDateSelect的回调函数竟然执行了两次。原来4.1跟4.2版本有个系统Bug,这时候我们需要重新定义一个DatePickerDialog来屏蔽onStop方法。
public class RepairDatePickDialog extends DatePickerDialog { public RepairDatePickDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { super(context, callBack, year, monthOfYear, dayOfMonth); // TODO Auto-generated constructor stub } public RepairDatePickDialog(Context context, int theme, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { super(context, theme, callBack, year, monthOfYear, dayOfMonth); // TODO Auto-generated constructor stub } protected void onStop() { // TODO Auto-generated method stub }}
4.浏览器中打开自家App的那些套路
大体的需求是用户分享出去连接,被分享的用户在浏览器中打开此连接,如果该用户设备上有我们的app则吊起app,如果没有则通知用户去下载我们的app
之前写过一片博客,详细的介绍了这种Deeplink的实现方式,请移步
https://juejin.im/entry/590fe2d8ac502e006cf9e3e4/detail
github地址
https://github.com/weixinjie/DeepLink
5.Android路由机制浅析
大厂的客户端里面都用了路由来实现页面之前的跳转,引入路由机制并不全是为了页面之间的解耦合,更多的是为了配合运营的套路。例如:大部分app里面都有Banner,这个Banner不一定全是打开Webview。有的Banner item打开的是充值页面,有的Banner item打开的是用户详情页面等。当然你可以为了Banner来写一个Map集合,每次用户点击Banner的时候Switch一下type,然后打开相应的页面,但是如果用户在浏览器中Deeplink到本地客户端呢?是不是也要实现一套Map?如果是在Webview中与js交互打开各个页面呢?是不是还要实现一套Map?
推荐一个很好用的路由框架
https://github.com/mzule/ActivityRouter
后期我会献上这个库的源码解析。
- Android 开发中不得不知道的 Tips 集合
- 熟悉Android开发不得不知道的技巧
- 熟悉Android开发不得不知道的技巧
- Android开发你不知道的TIPS
- Android开发不得不搜集的工具类集合
- IOS 开发不得不知道的网络知识
- Android Studio不得不知道的快捷键
- Spring中不得不知道的知识
- 学习iOS开发,你不得不知道的6个概念
- 前端开发不得不知道的十大ES6新特性
- 前端开发不得不知道的十大ES6新特性
- LinkedME|Android移动开发者不得不知道的技术 Deep Linking
- Android 7 强势来袭开发者们不得不知道的细节
- 关于Info.plist中你不得不知道的一点
- java 中Long和Integer不得不知道的秘密
- MySQL中关于JSON你不得不知道的那些事!
- MySQL中关于JSON你不得不知道的那些事!
- Android探索之旅(第十三篇)Android开发人员不得不知道的小工具(持续收录中......)
- TLD 详细解析之整体框架
- 金融数据类——美国对冲基金持仓
- 前端技术流程
- Tensorboard 直方图Summary使用指南
- 判断给定的一串字符是否为“回文”。所谓“回文”是指顺读和倒读都一样的字符串。
- Android 开发中不得不知道的 Tips 集合
- beetl中sql的in语句
- Object Detection with Discriminatively Trained Part Based Models(使用判别训练的部件模型进行目标检测 )
- 题目1062:分段函数
- 多表查询2
- log4j2.xml的完整
- Map遍历方式汇总
- EF中System.Data.Entity.Internal.AppConfig的类型初始值设定项引发异常
- docker 配置可以运行spark的容器并运行