Android学习之旅:第一天

采用依葫芦画瓢的方式来学习android的开发,准备逐步的开发出《一封》这个app

本片主要记录了SplashActivity的开发过程

I. 前置

主要copy两个开源项目

  1. JianshuApp
  2. SUESNews

上面两个工程,第二个用到的依赖比较少,实现的基本功能也都很ok,而第一个里面则用了很多有意思的第三方框架,但是目前我看不太懂,所以第一版以SUESNews作为主要的学习目标

所以,第一版的目标是:

  • 实现基本功能
  • 完成主体业务逻辑

II. Splash页面开发

一般来将,进入app之前,会进入一个类似首屏页的页面(比如12306的显示广告啥的),那么第一件事情就是做这个了

1. 做什么

这个页面,主要显示的东西比较简单了

  • 上边是一个图片,右上角一个倒计时
  • 下边显示的应用信息,版本等

业务逻辑:

  • 显示广告(😄),点击进入相应的详情页
  • 判断是否登录,若未登录,则进入登录页
  • 若已经登录,则进入主APP

2. 开动

a. 全屏

进入的首页,所以状态栏,标题啥的都不要,主要的逻辑如下

styles.xml 文件中新增

1
2
3
4
<style name="AppTheme.FullScreen">
<item name="windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>

其次,就是在定义的Activity中,使用对应的style

AndroidManifest.xml

1
2
3
4
5
6
7
<activity android:name=".ui.SplashActivity"
android:theme="@style/AppTheme.FullScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

b. xml实现

activity_splash.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
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:context="com.yihui.yifeng.ui.SplashActivity">

<ImageView
android:id="@+id/image_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignBottom="@+id/title_text"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="52dp"
android:scaleType="centerCrop" />


<ImageView
android:id="@+id/image_info_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignTop="@+id/title_text"
android:layout_centerHorizontal="true"
android:scaleType="centerCrop" />

<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/version_text"
android:layout_centerHorizontal="true"
android:layout_marginBottom="17dp"
android:text="@string/app_name"
android:textColor="@color/text_color"
android:textSize="@dimen/text_size_title_bigger"
android:textStyle="bold" />

<TextView
android:id="@+id/version_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="11dp"
android:textColor="@color/secondary_text"
android:textSize="@dimen/text_size_subhead"
android:textStyle="bold"
tools:text="Copyright @2017-2018 一封 | 小灰灰技术支持" />

</RelativeLayout>

运行截图如下:

A7108014-E6AC-4327-91F2-A89F07EEFE53.png

上面这个布局,是直接使用可视化的拖拽的,所以操作起来挺蛋疼的,而且最终的结果也不太好,下面单独的开一节来研究下这个布局的东西了

c. Activity的实现

上面是xml的配置,当然还得有对应的实体类了,大部分逻辑是直接从参考的工程中copy过来的,所以相关的动画配置,图片也是直接扣过来的

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
public class SplashActivity extends Activity {

private ImageView mBackgroundImage;

private ImageView infoBgImg;

private TextView mTitleText;

private TextView mVersionText;

private int[] ary = new int[] {R.drawable.pic_background_1, R.drawable.pic_background_2, R.drawable.pic_background_3, R.drawable.pic_background_4};

private int getBgDrawable() {
return ary[new Random().nextInt(ary.length)];
}


private void initInfoBg() {
infoBgImg = findViewById(R.id.image_info_bg);
infoBgImg.setImageDrawable(getResources().getDrawable(ary[0]));
}


private void initAdBg() {
mBackgroundImage = findViewById(R.id.image_background);
mBackgroundImage.setImageDrawable(getResources().getDrawable(getBgDrawable()));

Animation animImage = AnimationUtils.loadAnimation(this, R.anim.image_welcome);
mBackgroundImage.startAnimation(animImage);
animImage.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}

@Override
public void onAnimationEnd(Animation animation) {
//动画结束时打开首页
startActivity(new Intent(SplashActivity.this, MainActivity.class));
overridePendingTransition(R.anim.activity_slide_in, R.anim.no_anim);
finish();
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});
}


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

// 下半的提示文案信息
initInfoBg();


// 上半的广告动画
initAdBg();
}
}

todo

登录状态判断,如果未登录,则应该跳转到登录页面;否则才是跳转到主页

III. 知识点小结

上面只是实现了一个简单的应用开启页面,但也涉及了几个有趣的知识点,下面来深入一下

1. RelativeLayout 布局

控件的位置是按照相对位置来计算的,后一个控件在什么位置依赖于前一个控件的基本位置,是布局最常用,也是最灵活的一种布局

常见的属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
第一类:属性值为true或false
android:layout_centerHrizontal 水平居中
android:layout_centerVertical 垂直居中
android:layout_centerInparent 相对于父元素完全居中
android:layout_alignParentBottom 贴紧父元素的下边缘
android:layout_alignParentLeft 贴紧父元素的左边缘
android:layout_alignParentRight 贴紧父元素的右边缘
android:layout_alignParentTop 贴紧父元素的上边缘  

第二类:属性值必须为id的引用名“@id/id-name”
android:layout_below 在某元素的下方
android:layout_above 在某元素的的上方
android:layout_toLeftOf 在某元素的左边
android:layout_toRightOf 在某元素的右边
android:layout_alignTop 本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft 本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight 本元素的右边缘和某元素的的右边缘对齐

第三类:属性值为具体的像素值,如30dip,40px
android:layout_marginBottom 离某元素底边缘的距离
android:layout_marginLeft 离某元素左边缘的距离
android:layout_marginRight 离某元素右边缘的距离
android:layout_marginTop 离某元素上边缘的距离

所以可以简单的修改一下上面的布局,相对布局的样式就两个,上面一个图,下面一个图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<ImageView
android:id="@+id/image_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!-- 注意这一行 -->
android:layout_alignBottom="@+id/image_info_bg"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="52dp"
android:scaleType="centerCrop" />


<ImageView
android:id="@+id/image_info_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!-- 注意这一行,确保背景图可以包含文本信息 -->
android:layout_alignTop="@+id/title_text"
android:layout_centerHorizontal="true"
android:scaleType="centerCrop" />

那么剩下的两个文本显示就可以直接指定下边距来确定位置了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/version_text"
android:layout_centerHorizontal="true"
<!-- 这里确定了高度 -->
android:layout_marginBottom="17dp"
android:text="@string/app_name"
android:textColor="@color/text_color"
android:textSize="@dimen/text_size_title_bigger"
android:textStyle="bold" />

<TextView
android:id="@+id/version_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
<!-- 这里确定了高度 -->
android:layout_marginBottom="11dp"
android:textColor="@color/secondary_text"
android:textSize="@dimen/text_size_subhead"
android:text="@string/splash_copyright" />

2. 获取组件

在Activity中,先要绑定视图,然后再获取view进行相关的操作(如修改值,绑定事件等)

1
2
3
4
5
6
7
8
9
10
// Activity 的 oncreate方法中,进行初始化
// 绑定视图
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);

// 获取组件
findViewById(R.id.image_info_bg);

// 获取资源,如图片
Drawable drawable = getResources().getDrawable(R.drawable.pic_background_1)

有一个非常有名的工具叫做 butterknife, 可以通过注解的方式来解决 findViewById这种频繁的调用姿势,这个放在后续的进阶版中使用

3. 设置动画

开屏使用了一个图片放大的动画,持续3s,动画播放完毕之后跳转主页;所以这里有个有趣的知识点就是如何使用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
// 解析xml配置为 Animation 对象
Animation animImage = AnimationUtils.loadAnimation(this, R.anim.image_welcome);
// 设置组件的动画属性
mBackgroundImage.startAnimation(animImage);
// 配置监听事件
animImage.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}

// 动画结束后的回调
@Override
public void onAnimationEnd(Animation animation) {
//动画结束时打开首页
startActivity(new Intent(SplashActivity.this, MainActivity.class));
overridePendingTransition(R.anim.activity_slide_in, R.anim.no_anim);
finish();
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});

对应的xml配置如下

image_welcome.xml

1
2
3
4
5
6
7
8
9
10
11
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0"
android:toXScale="1.3"
android:fromYScale="1.0"
android:toYScale="1.3"
android:duration="3000"
android:pivotY="50%"
android:pivotX="50%"
/>
</set>

那么,我们需要实现开头说的,这个图片如果是个广告,点击时展开详情页;右上角显示一个倒计时的小控件,可以怎么处理?(看最后)

4. 页面跳转

从一个Activity跳转到另一个,常见的使用姿势如下

1
startActivity(new Intent(SplashActivity.this, MainActivity.class));

IV. 倒计时改进

如何使用倒计时来替换前面的动画呢?最容易想到的就是用Timer或者ScheduleService来实现一个计时器,当然这是一个后端java的想法,对于Android呢,特意查了一下,发现有个 CountDownTimer 的类,专门干这个的,所以简单的改造一下

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
private void initAdBg() {
mBackgroundImage = findViewById(R.id.image_background);
mBackgroundImage.setImageDrawable(getResources().getDrawable(getBgDrawable()));
mBackgroundImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 点击
Toast.makeText(SplashActivity.this, "点击了", Toast.LENGTH_SHORT).show();
}
});

final TextView countDown = findViewById(R.id.splash_timedown);
CountDownTimer timer = new CountDownTimer(10000, 1000) {
@Override
public void onTick(long l) {
countDown.setText("倒计时:" + (l / 1000) + "s");
}

@Override
public void onFinish() {
//动画结束时打开首页
startActivity(new Intent(SplashActivity.this, MainActivity.class));
overridePendingTransition(R.anim.activity_slide_in, R.anim.no_anim);
finish();
}
};
timer.start();
}

改造后的输出图, 注意右上角的时间,已经下面分割处,不会有前面的空白了

7694230F-D9FE-4DCE-B76B-75E3204D3571.png

V. 其他

额外话

感觉最近不太能专心下来学习一门技术,有点浮躁了,所以决定学习下andorid,锻炼下自己,初步规划,先入门,然后接收一些有趣的第三方框架,最后再试一下kotalin

Android学习第一天,总感觉这将是个漫长的过程,也不晓得最终会完成得怎么样,努力坚持吧

扫描关注,java分享

QrCode