Android常用代码-自定义View和ViewGroup

一、自定义View

自定义属性

  • 以ZzHorizontalProgressBar为例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//attrs.xml
<declare-styleable name="ZzHorizontalProgressBar">
<!--大小-->
<attr name="zpb_padding" format="dimension" />
<!--颜色-->
<attr name="zpb_bg_color" format="color|reference" />
<attr name="zpb_pb_color" format="color|reference" />
<attr name="zpb_second_pb_color" format="color|reference" />
<!--整数-->
<attr name="zpb_max" format="integer" />
<attr name="zpb_progress" format="integer" />
<attr name="zpb_second_progress" format="integer" />
<!--布尔-->
<attr name="zpb_show_second_progress" format="boolean" />
<!--枚举-->
<attr name="zpb_show_second_point_shape" format="enum">
<enum name="point" value="0"/>
<enum name="line" value="1"/>
</attr>
</declare-styleable>

Android-TV开发-RecyclerView刷新焦点丢失以及局部刷新问题

问题1

使用GridLayoutManager时,多选的情况下,点击item刷新后,焦点被抢问题;

  • 解决方式
1
2
3
4
5
6
7
8
9
holder.setText(R.id.tv_name, data.get(position).getcName())
.setChecked(R.id.cb_choose, data.get(position).isChoosed())
.setOnClickListener(R.id.ll_cb, new View.OnClickListener() {
@Override
public void onClick(View v) {
data.get(position).setChoosed(!data.get(position).isChoosed());
notifyItemChanged(position); //关键代码
}
});

Android常用代码-横竖屏切换

自动切换

  • Android Manifest在需要切换的Activity中添加
1
2
android:configChanges="orientation|keyboardHidden|layoutDirection|screenSize|screenLayout"
android:screenOrientation="sensor"
  • res添加layout-land和layout-port文件夹,分别放两套布局。

  • Activity代码中实现

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(newConfig.orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){
//切换到竖屏
setContentView(R.layout.activity_main);
}else{
//切换到横屏
setContentView(R.layout.activity_main);
}
}

Android疑难杂症-7.0系统PopupWindow#showAsDropDown()显示异常

问题描述

1
2
3
final PopupWindow popupWindow = new PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
//... ...
popupWindow.showAsDropDown(anchor);

上述代码在7.0手机上不会在anchor下方弹出,而是在屏幕最上方弹出,7.0以下手机则没问题;
高度MATCH_PARENT时才会这样,WRAP_CONTENT时不会。

原因

  • 7.0系统的一个bug;

Android常用代码-EditText各种样式背景

底部变色直线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:bottom="1px" android:state_focused="true">
<layer-list>
<item>
<shape>
<solid android:color="@color/colorPrimary" />
</shape>
</item>
<item android:bottom="1px">
<shape>
<solid android:color="@android:color/white" />
</shape>
</item>
</layer-list>
</item>
<item android:bottom="1px" android:state_pressed="false">
<layer-list>
<item>
<shape>
<solid android:color="#ddd" />
</shape>
</item>
<item android:bottom="1px">
<shape>
<solid android:color="@android:color/white" />
</shape>
</item>
</layer-list>
</item>
</selector>

Android常用代码-发送验证码倒计时

使用RxJava优雅的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
btnVerifyCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
btnVerifyCode.setEnabled(false);
Observable.interval(0, 1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
.limit(31)
.map(new Func1<Long, Long>() {
@Override
public Long call(Long aLong) {
return 30 - aLong;
}
})
.doOnSubscribe(new Action0() {
@Override
public void call() {
btnVerifyCode.setEnabled(false);
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
btnVerifyCode.setEnabled(true);
btnVerifyCode.setText("重新发送");
}
})
.subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
btnVerifyCode.setText("重新发送("+aLong + " s )");
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
ToastUtils.showCustomBgToast("获取失败,错误信息:" + throwable.getMessage() + "");
}
});
}
});

Android常用代码-底部弹出PopupWindow

关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 显示自定义底部弹出PopupWindow
*
* @param parent 传根布局就好了
* @param contentView PopupWindow内容
* @param bgColor 背景颜色(窗体变暗效果)
* @param focusable 是否点击空白区域取消(非全屏时可以)和返回键关闭
* @param fullScreen 是否全屏
* @param onDismissListener 取消监听
*/
public void showBottomPopupWindow(View parent, View contentView, int bgColor, boolean focusable, boolean fullScreen, PopupWindow.OnDismissListener onDismissListener) {
hideBottomDialog();
AutoUtils.auto(contentView);
popupWindow = new PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, fullScreen ? ViewGroup.LayoutParams.MATCH_PARENT : ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setContentView(contentView);
// 设置弹出窗体可点击
popupWindow.setFocusable(focusable);
// 设置弹出窗体的背景
popupWindow.setBackgroundDrawable(new ColorDrawable(bgColor));
if (onDismissListener != null) {
popupWindow.setOnDismissListener(onDismissListener);
}
//设置弹出窗体显示时的动画,从底部向上弹出
popupWindow.setAnimationStyle(R.style.ZzAnimationDialog);
popupWindow.showAtLocation(parent, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
}
/**
* 隐藏自定义底部弹出PopupWindow
*/
public void hideBottomDialog() {
if (popupWindow != null) {
popupWindow.dismiss();
popupWindow = null;
}
}