Android猿

Do one thing at a time,and do well.


  • 首页

  • 归档

  • 标签

两步打造华丽丽的Android引导页(用到RxJava)

发表于 2016-07-27   |     |   阅读次数

上篇文章 :RxJava实践之打造酷炫启动页中,我们尝试了用RxJava实现酷炫的启动页,今天我们再此基础上加入首次使用APP时的引导页功能。效果如下图:


welcome7.gif

思路:思路其实很简单,就是在WelcomeActivity 中setContentView()之前判断是否是首次打开APP,若是,则去启动引导页(WelcomeGuideActivity)并return;若不是,则直接setContentView(),然后启动动画再启动MainActivity。

一、WelcomeActivity中判断是否是第一次启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 判断是否是第一次开启应用
boolean isFirstOpen = SharedPreferencesUtil.getBoolean(this, SharedPreferencesUtil.FIRST_OPEN, true);
// 如果是第一次启动,则先进入功能引导页
if (isFirstOpen) {
Intent intent = new Intent(this, WelcomeGuideActivity.class);
startActivity(intent);
finish();
return;
}

// 如果不是第一次启动app,则正常显示启动屏
setContentView(R.layout.activity_welcome);
ButterKnife.bind(this);
startMainActivity();
}

我们判断是否是第一次打开APP是用了SharedPreferences,我们这里对他进行了一下简单封装,代码如下:

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
/**
* Created by xialo on 2016/7/25.
*/
public class SharedPreferencesUtil {

private static final String spFileName = "welcomePage";
public static final String FIRST_OPEN = "first_open";

public static Boolean getBoolean(Context context, String strKey,
Boolean strDefault) {//strDefault boolean: Value to return if this preference does not exist.
SharedPreferences setPreferences = context.getSharedPreferences(
spFileName, Context.MODE_PRIVATE);
Boolean result = setPreferences.getBoolean(strKey, strDefault);
return result;
}

public static void putBoolean(Context context, String strKey,
Boolean strData) {
SharedPreferences activityPreferences = context.getSharedPreferences(
spFileName, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = activityPreferences.edit();
editor.putBoolean(strKey, strData);
editor.commit();
}

}

二、WelcomeGuideActivity中,我们使用ViewPager以加载多个引导页面使其可以左右滑动

不多说,请看WelcomeGuideActivity.java代码:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* Created by xialo on 2016/7/25.
*/
public class WelcomeGuideActivity extends Activity implements View.OnClickListener {
private ViewPager vp;
private GuideViewPagerAdapter adapter;
private List<View> views;
private Button startBtn;

// 引导页图片资源
private static final int[] pics = { R.layout.guide_view1,
R.layout.guide_view2, R.layout.guide_view3};

// 底部小点图片
private ImageView[] dots;

// 记录当前选中位置
private int currentIndex;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_guide);

views = new ArrayList<View>();

// 初始化引导页视图列表
for (int i = 0; i < pics.length; i++) {
View view = LayoutInflater.from(this).inflate(pics[i], null);

if (i == pics.length - 1) {
startBtn = (Button) view.findViewById(R.id.btn_enter);
startBtn.setTag("enter");
startBtn.setOnClickListener(this);
}

views.add(view);

}

vp = (ViewPager) findViewById(R.id.vp_guide);
adapter = new GuideViewPagerAdapter(views);
vp.setAdapter(adapter);
vp.addOnPageChangeListener(new PageChangeListener());

initDots();

}

@Override
protected void onResume() {
super.onResume();
}

@Override
protected void onPause() {
super.onPause();
// 如果切换到后台,就设置下次不进入功能引导页
SharedPreferencesUtil.putBoolean(WelcomeGuideActivity.this, SharedPreferencesUtil.FIRST_OPEN, false);
finish();
}

@Override
protected void onStop() {
super.onStop();
}

@Override
protected void onDestroy() {
super.onDestroy();
}

private void initDots() {
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
dots = new ImageView[pics.length];

// 循环取得小点图片
for (int i = 0; i < pics.length; i++) {
// 得到一个LinearLayout下面的每一个子元素
dots[i] = (ImageView) ll.getChildAt(i);
dots[i].setEnabled(false);// 都设为灰色
dots[i].setOnClickListener(this);
dots[i].setTag(i);// 设置位置tag,方便取出与当前位置对应
}

currentIndex = 0;
dots[currentIndex].setEnabled(true); // 设置为白色,即选中状态

}

/**
* 设置当前view
*
* @param position
*/
private void setCurView(int position) {
if (position < 0 || position >= pics.length) {
return;
}
vp.setCurrentItem(position);
}

/**
* 设置当前指示点
*
* @param position
*/
private void setCurDot(int position) {
if (position < 0 || position > pics.length || currentIndex == position) {
return;
}
dots[position].setEnabled(true);
dots[currentIndex].setEnabled(false);
currentIndex = position;
}

@Override
public void onClick(View v) {
if (v.getTag().equals("enter")) {
enterMainActivity();
return;
}

int position = (Integer) v.getTag();
setCurView(position);
setCurDot(position);
}


private void enterMainActivity() {
Intent intent = new Intent(WelcomeGuideActivity.this,
WelcomeActivity.class);
startActivity(intent);
SharedPreferencesUtil.putBoolean(WelcomeGuideActivity.this, SharedPreferencesUtil.FIRST_OPEN, false);
finish();
}

private class PageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrollStateChanged(int position) {

}

@Override
public void onPageScrolled(int position, float arg1, int arg2) {

}

@Override
public void onPageSelected(int position) {
// 设置底部小点选中状态
setCurDot(position);
}

}
}

我们用了三个页面guide_view1、guide_view2、guide_view3作为引导页面,布局类似,只是guide_view3多了个点击进入的Button。以下是guide_view3.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/guide_img3" />
<Button
android:id="@+id/btn_enter"
android:layout_width="100dp"
android:layout_height="26dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="75dp"
android:background="@drawable/button_shape"
android:text="@string/entry"
android:textColor="@color/white"
android:textSize="18sp"
android:visibility="visible" />

</FrameLayout>

WelcomeGuideActivity中值得注意的是该Button点击事件的处理,在点击Button后我们并没有直接进入MainActivity,而是先把SharedPreferences中标记是否第一次进入的布尔值设为false,而后再次进入WelcomeActivity,此时WelcomeActivity会直接setContentView()然后启动动画,进入MainActivity。

以上,我们华丽丽的引导页就完成了,需要完整代码的请戳 代码传送门

RxJava实践之打造酷炫启动页

发表于 2016-07-20   |     |   阅读次数

之前注意到coding APP启动页很是酷炫,今天我们使用RxJava和属性动画模仿实现其效果。


ezgif.com-video-to-gif(2).gif

一、新建启动页WelcomeActivity

注意,我们这里让WelcomeActivity继承Activity不要继承AppCompatActivity,因为AppCompatActivity会默认去加载主题,造成卡顿

1
2
3
4
5
6
7
8
    public class WelcomeActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
}
}

二、定义引导页布局activity_welcome.xml

不多说直接上代码:

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
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@+id/iv_entry"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/welcomimg1"/>

<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/welcomimg_bg"/>


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="100dp"
android:gravity="center"
android:text="xialong"
android:textColor="@android:color/white"
android:textSize="23sp"/>

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/google_logo"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp"
android:layout_centerInParent="true"
android:tint="@android:color/white" />
</RelativeLayout>

这里我们用了相对布局,在ImageView上覆盖一个View,该View用渐变色背景welcomimg_bg.xml以暗化图片,welcomimg_bg.xml代码如下:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

<gradient
android:angle="90"
android:startColor="@color/black"
android:endColor="@android:color/transparent"
/>

</shape>

其中startColor表示起始颜色,endColor表示结束颜色,angle=90 表示颜色从下往上渐变。

三、随机选取图片并使用RxJava启动动画

最后我们的WelcomeActivity.java长这样:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class WelcomeActivity extends Activity {

@Bind(R.id.iv_entry)
ImageView mIVEntry;

private static final int ANIM_TIME = 2000;

private static final float SCALE_END = 1.15F;

private static final int[] Imgs={
R.drawable.welcomimg1,R.drawable.welcomimg2,
R.drawable.welcomimg3,R.drawable.welcomimg4,
R.drawable.welcomimg5, R.drawable.welcomimg6,
R.drawable.welcomimg7,R.drawable.welcomimg8,
R.drawable.welcomimg9,R.drawable.welcomimg10,
R.drawable.welcomimg11,R.drawable.welcomimg12,};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
ButterKnife.bind(this);

Random random = new Random(SystemClock.elapsedRealtime());//SystemClock.elapsedRealtime() 从开机到现在的毫秒数(手机睡眠(sleep)的时间也包括在内)
mIVEntry.setImageResource(Imgs[random.nextInt(Imgs.length)]);

Observable.timer(1000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Long>()
{

@Override
public void call(Long aLong)
{
startAnim();
}
});
}


private void startAnim() {

ObjectAnimator animatorX = ObjectAnimator.ofFloat(mIVEntry, "scaleX", 1f, SCALE_END);
ObjectAnimator animatorY = ObjectAnimator.ofFloat(mIVEntry, "scaleY", 1f, SCALE_END);

AnimatorSet set = new AnimatorSet();
set.setDuration(ANIM_TIME).play(animatorX).with(animatorY);
set.start();

set.addListener(new AnimatorListenerAdapter()
{

@Override
public void onAnimationEnd(Animator animation)
{

startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
WelcomeActivity.this.finish();
}
});
}
}

这里的RxJava使用了timer操作符,它的意思是延迟执行某个操作,第一个参数表示延迟时间,第二个参数是时间单位。
好了,就酱。

需要完整代码可以戳这里代码传送门

Android Studio最实用快捷键

发表于 2016-05-23   |     |   阅读次数

之前都是用习惯了eclipse的快捷键,从去年(2015)10月份使用Android studio到现在也基本习惯了AS的快捷键,反而越来越感觉AS的快捷键比eclipse强大太多,今天周末就把自己平时最常用的AS快捷键总结出。

一.Log相关

  • 生成TAG
    1
    logt

效果:


TAG.png
  • 打印方法中参数
    1
    logm

效果:


logm.png
  • 打印log.d()

    1
    logd
  • 打印log.e()

    1
    loge

打印其他级别的Log以此类推。

二.代码提示

1
Ctrl + Alt +Space (空格键)

三.代码移动

  • 选中代码,连续按会选中更多

    1
    Ctrl + W
  • 复制当前行到下一行

    1
    Ctrl + D
  • 剪切

    1
    Ctrl + X
  • 删除

    1
    Ctrl + Y
  • 代码向上/下移动

    1
    Ctrl + Shift+ Up/Down
  • 在类中的方法间移动

    1
    Alt + Up/Down
  • 代码向上/下移动

    1
    Ctrl + Shift+ Up/Down

四.代码查看

  • 打开一个文件

    1
    Ctrl + Shift+ N
  • 打开一个类

    1
    Ctrl + N
  • 查看一个变量的声明

    1
    Ctrl + B    //效果同Ctrl + 左击鼠标
  • 查看一个类的父类

    1
    Ctrl + U
  • 查看一个方法的调用

    1
    Ctrl + Alt + H
  • 在类中查看一个方法的实现

    1
    Ctrl + Shift + i
  • 显示类结构图

    1
    Ctrl +  H
  • 代码返回快捷键

    1
    Alt + 向左箭头
  • 代码展示折叠、展开

    1
    Ctrl + -/+
  • 隐藏/打开工程面板

    1
    Alt + 1
  • 高亮错误或警告快速定位

    1
    F2
  • 查找类中的方法或变量

    1
    Ctrl + Shift + Alt + N
  • 显示当前文件结构

    1
    Ctrl + F12
  • 复写父类方法

    1
    Ctrl + O
  • 给选中的代码块添加if、for、try/catch等语句

    1
    Ctrl + Alt + T

五.代码生成

1
Ctrl + J       //可生成 if、for、foreach、findViewById、View.Gone、Toast等代码

Ctrl+j.png

六.代码查找、替换

  • 查找文本

    1
    Ctrl + F
  • 替换文本

    1
    Ctrl + R

七.代码格式化

  • 代码格式化
    1
    Ctrl + Shift + L

以上,欢迎交流补充。

Android屏幕录制并转换gif

发表于 2016-05-06   |     |   阅读次数

最近需要手机录制gif图片,找了好多软件也没理想的,最后确定了先通过命令screenrecord 录制MP4视频再转gif的方案。分享出来和大家交流,谁有更好的方案请告诉我(啧啧,这像钓鱼贴)。

之前没注意到Android studio的Android Monitor选项卡有个录制视频的按钮,经@一息尚存和@Wing_Li提醒才发现还真有这么个东东(AS真人性化,有木有觉得啊)。如下图

studioscreenrecord.png

不习惯用命令方式的可以直接点击那个按钮录制视频。下面介绍命令的方式。

screenrecord 命令介绍

Android4.4(API level 19)以上支持screenrecord命令,首先我们在Android studio中打开terminal

terminal.png

输入

1
adb shell screenrecord --help

看到如下结果,详细解释看后面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
C:\Users\xialo\Desktop\WelcomPage>adb shell screenrecord --help
Usage: screenrecord [options] <filename>

Records the device's display to a .mp4 file.

Options:
--size WIDTHxHEIGHT
Set the video size, e.g. "1280x720". Default is the device's main
display resolution (if supported), 1280x720 if not. For best results,
use a size supported by the AVC encoder.
--bit-rate RATE
Set the video bit rate, in megabits per second. Default 4Mbps.
--time-limit TIME
Set the maximum recording time, in seconds. Default / maximum is 180.
--rotate
Rotate the output 90 degrees.
--verbose
Display interesting information on stdout.
--help
Show this message.

Recording continues until Ctrl-C is hit or the time limit is reached.

由上面我们看出,screenrecord基本的使用方式为:

1
screenrecord [options] <filename>

其中options是可选参数,主要包含:–size,–bit-rate,–time-limit,–rotate,–verbose,–help等。下面简单示例常用参数的使用:

  • –size 指定视频分辨率大小
    1
    adb shell screenrecord --size 1280x720 /sdcard/test.mp4

说明:录制视频,分辨率为1280x720(注意,这里是字母x,不是星号,否则会出错),如果不指定默认使用手机的分辨率,为获得最佳效果,请使用设备上的高级视频编码(AVC)支持的大小

  • –bit-rate 指定视频的比特率
    1
    adb shell screenrecord --bit-rate 5000000 /sdcard/test.mp4

说明:指定视频的比特率为5Mbps,如果不指定,默认为4Mbps. 你可以增加比特率以提高视频质量或为了让文件更小而降低比特率

  • –time-limit 限制录制时间
    1
    adb shell screenrecord  --time-limit 30 /sdcard/demo.mp4

说明:限制视频录制时间为30s,如果不限制,默认180s


用screenrecord 命令录制视频

我们用USB链接手机,继续在Android studio的terminal中输入命令

1
adb shell screenrecord --size 480x640 /sdcard/test.mp4

这里我们没有指定录制时间,所以录制完成后点击关闭terminal即可,这时,我们的SD卡根目录会出现刚刚录制的视频test.mp4

test.jpg


mp4转gif

这里我们用http://ezgif.com/ 在线将mp4转换为gif,傻瓜式操作,这里不再赘述。

mp4togif.png

收工。

Android动态设置主题(使用RxBus模式)

发表于 2016-03-07   |     |   阅读次数

之前写过一篇文章:RxBus的实现及简单使用。今天我们尝试使用RxBus动态切换主题。

一、定义主题颜色

color.xml

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
41
42
43
44
45
46
47
48
49
50
51
52
53
<color name="red_primary">#F44336</color>
<color name="red_primary_dark">#D32F2F</color>
<color name="red_accent">#F44336</color>

<color name="pink_primary">#E91E63</color>
<color name="pink_primary_dark">#C2185B</color>
<color name="pink_accent">#E91E63</color>

<color name="brown_primary">#795548</color>
<color name="brown_primary_dark">#5D4037</color>
<color name="brown_accent">#795548</color>


<color name="blue_primary">#2196F3</color>
<color name="blue_primary_dark">#1976D2</color>
<color name="blue_accent">#2196F3</color>

<color name="blue_grey_primary">#607D8B</color>
<color name="blue_grey_primary_dark">#455A64</color>
<color name="blue_grey_accent">#607D8B</color>

<color name="yellow_primary">#FFEB3B</color>
<color name="yellow_primary_dark">#FBC02D</color>
<color name="yellow_accent">#FFEB3B</color>

<color name="deep_purple_primary">#673AB7</color>
<color name="deep_purple_primary_dark">#512DA8</color>
<color name="deep_purple_accent">#673AB7</color>


<color name="green_primary">#4CAF50</color>
<color name="green_primary_dark">#388E3C</color>
<color name="green_accent">#4CAF50</color>

<color name="deep_orange_primary">#FF5722</color>
<color name="deep_orange_primary_dark">#E64A19</color>
<color name="deep_orange_accent">#FF5722</color>

<color name="grey_primary">#9E9E9E</color>
<color name="grey_primary_dark">#616161</color>
<color name="grey_accent">#9E9E9E</color>

<color name="cyan_primary">#00BCD4</color>
<color name="cyan_primary_dark">#0097A7</color>
<color name="cyan_accent">#00BCD4</color>

<color name="amber_primary">#FFC107</color>
<color name="amber_primary_dark">#FFA000</color>
<color name="amber_accent">#FFC107</color>

<color name="primary">#2196F3</color>
<color name="primary_dark">#1E88E5</color>
<color name="accent">@color/primary</color>

二、定义主题样式

styles.xml

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<style name="RedTheme" parent="AppTheme">
<item name="colorPrimary">@color/red_primary</item>
<item name="colorPrimaryDark">@color/red_primary_dark</item>
<item name="colorAccent">@color/red_accent</item>
</style>

<style name="PinkTheme" parent="AppTheme">
<item name="colorPrimary">@color/pink_primary</item>
<item name="colorPrimaryDark">@color/pink_primary_dark</item>
<item name="colorAccent">@color/pink_accent</item>
</style>

<style name="BrownTheme" parent="AppTheme">
<item name="colorPrimary">@color/brown_primary</item>
<item name="colorPrimaryDark">@color/brown_primary_dark</item>
<item name="colorAccent">@color/brown_accent</item>
</style>


<style name="BlueTheme" parent="AppTheme">
<item name="colorPrimary">@color/blue_primary</item>
<item name="colorPrimaryDark">@color/blue_primary_dark</item>
<item name="colorAccent">@color/blue_accent</item>
</style>


<style name="BlueGreyTheme" parent="AppTheme">
<item name="colorPrimary">@color/blue_grey_primary</item>
<item name="colorPrimaryDark">@color/blue_grey_primary_dark</item>
<item name="colorAccent">@color/blue_grey_accent</item>
</style>


<style name="YellowTheme" parent="AppTheme">
<item name="colorPrimary">@color/yellow_primary</item>
<item name="colorPrimaryDark">@color/yellow_primary_dark</item>
<item name="colorAccent">@color/yellow_accent</item>
</style>


<style name="DeepPurpleTheme" parent="AppTheme">
<item name="colorPrimary">@color/deep_purple_primary</item>
<item name="colorPrimaryDark">@color/deep_purple_primary_dark</item>
<item name="colorAccent">@color/deep_purple_accent</item>
</style>


<style name="GreenTheme" parent="AppTheme">
<item name="colorPrimary">@color/green_primary</item>
<item name="colorPrimaryDark">@color/green_primary_dark</item>
<item name="colorAccent">@color/green_accent</item>
</style>

<style name="DeepOrangeTheme" parent="AppTheme">
<item name="colorPrimary">@color/deep_orange_primary</item>
<item name="colorPrimaryDark">@color/deep_orange_primary_dark</item>
<item name="colorAccent">@color/deep_orange_accent</item>
</style>

<style name="GreyTheme" parent="AppTheme">
<item name="colorPrimary">@color/grey_primary</item>
<item name="colorPrimaryDark">@color/grey_primary_dark</item>
<item name="colorAccent">@color/grey_accent</item>
</style>

<style name="CyanTheme" parent="AppTheme">
<item name="colorPrimary">@color/cyan_primary</item>
<item name="colorPrimaryDark">@color/cyan_primary_dark</item>
<item name="colorAccent">@color/cyan_accent</item>
</style>

<style name="AmberTheme" parent="AppTheme">
<item name="colorPrimary">@color/amber_primary</item>
<item name="colorPrimaryDark">@color/amber_primary_dark</item>
<item name="colorAccent">@color/amber_accent</item>
</style>

三、在需要的地方弹出主题选择对话框

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
private void showThemeChooseDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("设置主题");
Integer[] res = new Integer[]{R.drawable.red_round, R.drawable.brown_round, R.drawable.blue_round,
R.drawable.blue_grey_round, R.drawable.yellow_round, R.drawable.deep_purple_round,
R.drawable.pink_round, R.drawable.green_round, R.drawable.deep_orange_round,
R.drawable.grey_round, R.drawable.cyan_round};
List<Integer> list = Arrays.asList(res);
ColorsListAdapter adapter = new ColorsListAdapter(MainActivity.this, list);
adapter.setCheckItem(MyThemeUtils.getCurrentTheme(MainActivity.this).getIntValue());
GridView gridView = (GridView) LayoutInflater.from(MainActivity.this).inflate(R.layout.colors_panel_layout, null);
gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
gridView.setCacheColorHint(0);
gridView.setAdapter(adapter);
builder.setView(gridView);
final AlertDialog dialog = builder.show();
gridView.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
dialog.dismiss();
int value = MyThemeUtils.getCurrentTheme(MainActivity.this).getIntValue();
if (value != position) {
PreferenceUtils.getInstance(MainActivity.this).saveParam("change_theme_key", position);
changeTheme(MyThemeUtils.Theme.mapValueToTheme(position));
}
}
}

);
}

对话框圆形颜色选项
在drawable下新建red_round.xml,其他主题颜色类似

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="@color/red_primary"/>
</shape

四、主题选择框中颜色适配器及其xml

主题选择框中颜色适配器ColorsListAdapter

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
41
42
43
44
45
46
47
48
49
50
51
52
53
public class ColorsListAdapter extends BaseAdapter {

private int checkItem;
Context context;
List<Integer> list;

public ColorsListAdapter(Context context, List<Integer> list) {
this.context = context;
this.list = list;
}


@Override
public int getCount() {
return list.size();
}

@Override
public Object getItem(int position) {
return list.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.colors_image_layout, null);
holder = new Holder();
holder.imageView1 = (ImageView) convertView.findViewById(R.id.img_1);
holder.imageView2 = (ImageView) convertView.findViewById(R.id.img_2);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
holder.imageView1.setImageResource(list.get(position));
if (checkItem == position) {
holder.imageView2.setImageResource(R.drawable.ic_done_white);
}
return convertView;
}
public void setCheckItem(int checkItem) {
this.checkItem = checkItem;
}
static class Holder {
ImageView imageView1;
ImageView imageView2;
}
}

colors_image_layout.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/transparent"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img_1"
android:layout_gravity="center"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageView
android:id="@+id/img_2"
android:layout_gravity="center"
android:layout_width="20dp"
android:layout_height="20dp" />
</FrameLayout>

五、使用RxBus发布事件和处理事件

发布

1
2
3
private void changeTheme(MyThemeUtils.Theme theme) {
RxBus.getInstance().post(new RxbusEvent(theme));
}

接收

1
2
3
4
5
6
7
rxSbscription=RxBus.getInstance().toObserverable(RxbusEvent.class)
.subscribe(new Action1<RxbusEvent>() {
@Override
public void call(RxbusEvent rxbusEvent) {
changeTheme(rxbusEvent.getTheme());
}
});

六、用到的工具类

PreferenceUtils

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class PreferenceUtils {
private SharedPreferences sharedPreferences;

private SharedPreferences.Editor shareEditor;

private static PreferenceUtils preferenceUtils = null;

public static final String NOTE_TYPE_KEY = "NOTE_TYPE_KEY";

public static final String EVERNOTE_ACCOUNT_KEY = "EVERNOTE_ACCOUNT_KEY";

public static final String EVERNOTE_NOTEBOOK_GUID_KEY = "EVERNOTE_NOTEBOOK_GUID_KEY";

private PreferenceUtils(Context context){
sharedPreferences = context.getSharedPreferences("ThemeSetting", Context.MODE_PRIVATE);
shareEditor = sharedPreferences.edit();
}

public static PreferenceUtils getInstance(Context context){
if (preferenceUtils == null) {
synchronized (PreferenceUtils.class) {
if (preferenceUtils == null) {
preferenceUtils = new PreferenceUtils(context.getApplicationContext());
}
}
}
return preferenceUtils;
}

public String getStringParam(String key){
return getStringParam(key, "");
}

public String getStringParam(String key, String defaultString){
return sharedPreferences.getString(key, defaultString);
}

public void saveParam(String key, String value)
{
shareEditor.putString(key,value).commit();
}

public boolean getBooleanParam(String key){
return getBooleanParam(key, false);
}

public boolean getBooleanParam(String key, boolean defaultBool){
return sharedPreferences.getBoolean(key, defaultBool);
}

public void saveParam(String key, boolean value){
shareEditor.putBoolean(key, value).commit();
}

public int getIntParam(String key){
return getIntParam(key, 0);
}

public int getIntParam(String key, int defaultInt){
return sharedPreferences.getInt(key, defaultInt);
}

public void saveParam(String key, int value){
shareEditor.putInt(key, value).commit();
}

public long getLongParam(String key){
return getLongParam(key, 0);
}

public long getLongParam(String key, long defaultInt){
return sharedPreferences.getLong(key, defaultInt);
}

public void saveParam(String key, long value){
shareEditor.putLong(key, value).commit();
}

public void removeKey(String key){
shareEditor.remove(key).commit();
}
}

MyThemeUtils

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class MyThemeUtils {

public static void changTheme(Activity activity, Theme theme) {
if (activity == null)
return;
int style = R.style.RedTheme;
switch (theme) {
case BROWN:
style = R.style.BrownTheme;
break;
case BLUE:
style = R.style.BlueTheme;
break;
case BLUE_GREY:
style = R.style.BlueGreyTheme;
break;
case YELLOW:
style = R.style.YellowTheme;
break;
case DEEP_PURPLE:
style = R.style.DeepPurpleTheme;
break;
case PINK:
style = R.style.PinkTheme;
break;
case GREEN:
style = R.style.GreenTheme;
break;
case DEEP_ORANGE:
style = R.style.DeepOrangeTheme;
break;
case GREY:
style = R.style.GreyTheme;
break;
case CYAN:
style = R.style.CyanTheme;
break;
case AMBER:
style = R.style.AmberTheme;
break;
default:
break;
}
activity.setTheme(style);
}

public static Theme getCurrentTheme(Context context) {
int value = PreferenceUtils.getInstance(context)
.getIntParam("change_theme_key", 0);
return MyThemeUtils.Theme.mapValueToTheme(value);
}

public enum Theme {
RED(0),
BROWN(1),
BLUE(2),
BLUE_GREY(3),
YELLOW(4),
DEEP_PURPLE(5),
PINK(6),
GREEN(7),
DEEP_ORANGE(8),
GREY(9),
CYAN(10),
AMBER(11);

private int mValue;

Theme(int value) {
this.mValue = value;
}

public static Theme mapValueToTheme(final int value) {
for (Theme theme : Theme.values()) {
if (value == theme.getIntValue()) {
return theme;
}
}
// If run here, return default
return RED;
}

static Theme getDefault() {
return RED;
}

public int getIntValue() {
return mValue;
}
}
}

基类BaseActivity,主题的初始化。注意,需要变换主题的Activity需继承BaseActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class BaseActivity extends AppCompatActivity {
protected PreferenceUtils preferenceUtils;

@Override
protected void onCreate(Bundle savedInstanceState) {
preferenceUtils = PreferenceUtils.getInstance(this);
initTheme();
super.onCreate(savedInstanceState);
}

private void initTheme() {
MyThemeUtils.Theme theme = MyThemeUtils.getCurrentTheme(this);
MyThemeUtils.changTheme(this, theme);
}
}

参考:
https://github.com/lguipeng/Notes

RxBus的实现及简单使用

发表于 2016-03-01   |     |   阅读次数

RxJava目前已经很火了,如果你尚未了解请看这里。对于RxJava这里不多做介绍。
RxBus并不是一个库,而是一种模式。相信大多数开发者都使用过EventBus,作为事件总线通信库,如果你的项目已经加入RxJava和EventBus,不妨用RxBus代替EventBus,以减少库的依赖。

一、添加RxJava和RxAndroid依赖

1
2
3
//RxJava and RxAndroid
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'

二、新建RxBus类

不多说直接上代码:

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import rx.Observable;
import rx.subjects.PublishSubject;
import rx.subjects.SerializedSubject;
import rx.subjects.Subject;

/**
* Created by xialo on 2016/6/28.
*/
public class RxBus {

private static volatile RxBus mInstance;

private final Subject bus;


public RxBus()
{
bus = new SerializedSubject<>(PublishSubject.create());
}

/**
* 单例模式RxBus
*
* @return
*/
public static RxBus getInstance()
{

RxBus rxBus2 = mInstance;
if (mInstance == null)
{
synchronized (RxBus.class)
{
rxBus2 = mInstance;
if (mInstance == null)
{
rxBus2 = new RxBus();
mInstance = rxBus2;
}
}
}

return rxBus2;
}


/**
* 发送消息
*
* @param object
*/
public void post(Object object)
{

bus.onNext(object);

}

/**
* 接收消息
*
* @param eventType
* @param <T>
* @return
*/
public <T> Observable<T> toObserverable(Class<T> eventType)
{
return bus.ofType(eventType);
}
}

1、Subject同时充当了Observer和Observable的角色,Subject是非线程安全的,要避免该问题,需要将 Subject转换为一个 SerializedSubject,上述RxBus类中把线程非安全的PublishSubject包装成线程安全的Subject。
2、PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。
3、ofType操作符只发射指定类型的数据,其内部就是filter+cast

三、创建你需要发送的事件类

我们这里用StudentEvent举例

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
/**
* Created by xialo on 2016/6/28.
*/
public class StudentEvent {
private String id;
private String name;

public StudentEvent(String id, String name) {
this.id = id;
this.name = name;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

四、发送事件

1
RxBus.getInstance().post(new StudentEvent("007","小明"));

五、接收事件

1
2
3
4
5
6
7
rxSbscription=RxBus.getInstance().toObserverable(StudentEvent.class)
.subscribe(new Action1<StudentEvent>() {
@Override
public void call(StudentEvent studentEvent) {
textView.setText("id:"+ studentEvent.getId()+" name:"+ studentEvent.getName());
}
});

注:rxSbscription是Sbscription的对象,我们这里把RxBus.getInstance().toObserverable(StudentEvent.class)赋值给rxSbscription以方便生命周期结束时取消订阅事件

六、取消订阅

1
2
3
4
5
6
7
@Override
protected void onDestroy() {
if (!rxSbscription.isUnsubscribed()){
rxSbscription.unsubscribe();
}
super.onDestroy();
}

参考:
http://wuxiaolong.me/2016/04/07/rxbus/
http://www.jianshu.com/p/ca090f6e2fe2

xialong

xialong

探索Android

6 日志
4 标签
GitHub 微博
  • 鸿洋
  • 郭霖
© 2015 - 2016 xialong
由 Hexo 强力驱动
主题 - NexT.Mist