常规 & 高级 UI 编程 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的第3天
单听理论会很陌生,以下建议自己边学边上手,以便巩固加深印象。并且本节课很多源码不用每行逐步了解,了解思路与线路足矣,有一定能力再去专研。
这节课我将学习到单个UI组件基础以及多个UI组件排版、从静态页面绘制到动态页面的设计、从系统组件应用到自定义组件等多个维度。分为以下几个部分:
UI组件:学习Android UI组件相关知识
布局:学习如何将多个UI组件排版成想要的界面
渲染:学习Android UI渲染流程及原理
交互:学习Android常规的交互知识及原理
动画:学习Android动画相关知识
自定义View:学习如何自定义View
UI组件
什么是Android UI
- UI:User Interface
- Android系统是图形用户界面操作系统
- UI界面由多个不同功能的UI组件构成
- Android SDK提供了大量的UI组件
UI组件
常规UI组件大多由Android Framework中的android.widget这个package提供
常规View的属性和方法
UI组件间关系
布局
LinearLayout
线性布局,可用android:orientation定义纵向还是横向线性分布
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top" />
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="right" />
</LinearLayout>
RelativeLayout
相对容器
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:paddingLeft="16dp" android:paddingRight="16dp" >
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/dates"
android:layout_width="0dp" android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/times" />
<Spinner
android:id="@id/times"
android:layout_width="96dp" android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_alignParentRight="true" />
<Button
android:layout_width="96dp" android:layout_height="wrap_content"
android:layout_below="@id/times"
android:layout_alignParentRight="true" />
</RelativeLayout>
FrameLayout
层级布局
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<TextView
android:layout_width="300dp"
android:layout_height="300dp"
android:gravity="center"
android:background="@android:color/holo_blue_bright"
android:text="我是第一层"/>
<TextView
android:layout_width="150dp"
android:layout_height="140dp"
android:gravity="center"
android:background="@android:color/holo_green_light"
android:text="我是第二层"/>
</FrameLayout>
ConstraintLayout
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_beauty"
android:layout_width="100dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="@drawable/beauty"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_girl"
android:layout_width="100dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="@drawable/girl"
app:layout_constraintBottom_toBottomOf="@+id/iv_beauty"
app:layout_constraintLeft_toRightOf="@+id/iv_beauty"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
渲染
布局加载
在Activity中设置布局文件
setContentView究竟做了什么?通过源码分析可知,setContentView最终创建了DecorView,并由LayoutInflater来加载了XML文件
布局解析
布局加载后调用了LayoutInflater相关方法,那LayoutInflater究竟做了什么?通过源码分析可知,LayoutInflater解析了XML文件,并根据XML文件生成了View实例,并将View实例添加了到了其ViewGroup中
布局渲染
页面绘制流程
UI渲染流程
渲染流程
交互
button例子
本人习惯用:
private TextView result;
private Button disable;
private Button enable;
private Button test;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_button_enable);
enable = findViewById(R.id.btn_enable);
disable = findViewById(R.id.btn_disable);
test = findViewById(R.id.btn_test);
result = findViewById(R.id.result);
enable.setOnClickListener(this);
disable.setOnClickListener(this);
test.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_enable:
test.setEnabled(true);
break;
case R.id.btn_disable:
test.setEnabled(false);
break;
case R.id.btn_test:
result.setText("点击了按钮");
break;
}
}
}
这样监听繁多时便不会显得很乱很冗杂
常用交互事件监听器
触摸事件
当用户触摸屏幕时,系统将建立一系列的MotionEvent对象,MotionEvent包含关于发生触摸的位置和时间等细节信息,MotionEvent对象被传递到相应的捕获函数中,例如onTouchEvent()。
捕获触摸事件
- Activity和View都有onTouchEvent(),用于处理触摸事件。
- 当用户触摸屏幕时,会回调触摸视图上的onTouchEvent()。 对于最终被识别为手势的每个轻触事件序列,onTouchEvent() 都会多次被触发。
事件处理流程
交互总结
动画
帧动画
补间动画
差值器示例: