Android学习读书笔记之界面编程
一.界面编程与视图(View)组件
1.视图组件与容器组件
Android应用的绝大部分UI组件都放在android.widget包及其子包,android.view包及其子包中,Android应用的所有UI组件都继承了View类。
所有的组件都提供了两种方式来控制组件的行为。
1> 在XML布局文件中通过XML属性进行控制。
2> 在Java程序代码中通过调用方法进行控制。
ViewGroup容器控制其子组件的分布依赖于ViewGroup.LayoutParams, ViewGroup.MarginLayoutParams两个内部类。这两个内部类都提供了一些XML属性,ViewGroup容器中的子组件可以指定这些XML属性。
ViewGroup.LayoutParams支持的XML属性
支持如下3个属性值:
1> fill_parent: 指定子组件的高度,宽度与父容器组件的高度,宽度相同。
2> match_parent: 该属性值与fill_parent完全相同;
3> wrap_content:指定子组件的大小恰好能包裹它的内容即可。
ViewGroup.MarginLayoutParams用于控制子组件周围的页边距,支持的XML属性如下
2.使用XML布局文件和Java代码混合控制UI界面
当混合使用XML布局文件和代码来控制UI界面时,习惯上把变化小,行为比较固定的组件放在XML布局文件中管理,而那些变化较多,行为控制较为复杂的组件则交给Java代码来管理。
实例1.简单的图片浏览器
step1. 先在布局文件中定义一个简单的线性布局容器,该布局代码如下:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 定义一个线性布局容器-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
</LinearLayout>
step2:在程序中获取该线性布局容器,并往该容器中添加组件:
MainActivity.java
package com.example.simpleadaptertest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
int [] images = new int [] {
R.drawable.fruit,
R.drawable.macao,
R.drawable.mountain,
};
int currentImg = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取LinearLayout布局容器
LinearLayout main = (LinearLayout) findViewById(R.id.root);
//程序创建ImageView组件
final ImageView image = new ImageView(this);
//将ImageView组件添加到LinearLayout布局容器中
main.addView(image);
//初始化时显示第一张图片
image.setImageResource(images[0]);
image.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//改变ImageView里显示的图片
image.setImageResource(images[++currentImg %images.length]);
}
});
}
}
实际效果:
3.开发自定义的View
当Andriod系统提供的UI组件不足以满足项目需求时,开发者可以通过继承View来派生自定义组件。
首先定义一个继承View基类的子类,然后重写View类的一个或多个方法。通常可以被用户重写的方法如下:
实例2.跟随手指的小球
当需要开发自定义View时,开发者可以根据需要重写父类的部分方法。
DrawView.java
package com.example.customview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class DrawView extends View {
private final static String TAG = "DrawView";
public float currentX = 40;
public float currentY = 50;
//定义并创建画笔
Paint p = new Paint();
public DrawView(Context context){
super(context);
}
public DrawView(Context context, AttributeSet set){
super(context, set);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
p.setColor(Color.GREEN);
//绘制一个小圆
canvas.drawCircle(currentX, currentY, 35, p);
}
//为该组件的触碰事件重写事件处理方法
//这里会调用两次按下和弹起
@Override
public boolean onTouchEvent(MotionEvent event) {
currentX = event.getX();
currentY = event.getY();
Log.d(TAG, "event:"+event.getActionMasked());
if(event.getActionMasked() == event.ACTION_DOWN){
}else if(event.getActionMasked() == event.ACTION_UP){
}
Log.d(TAG, "onTouchEvent: x:"+currentX);
Log.d(TAG, "onTouchEvent: y:"+currentY);
//通知当前组件重绘自己
invalidate();
//返回true表明该处理方法已经处理该事件
return true;
}
}
接下来可以通过Java代码把该组件添加到指定容器中,这样就可以看到该组件的运行效果。
CustomViewActivity.java
package com.example.customview;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;
public class CustomViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout root = (LinearLayout)findViewById(R.id.root);
//创建DrawView组件
final DrawView draw = new DrawView(this);
//设置自定义组件的最小宽度和高度
draw.setMinimumWidth(800);
draw.setMinimumHeight(1000);
root.addView(draw);
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CustomViewActivity">
</LinearLayout>
实际效果:
三.布局管理器
1.线性布局 LinearLayout
2.表格布局 TableLayout
3.帧布局 FrameLayout
实现:霓虹灯效果
使用上面的FrameLayout布局管理器,只是程序启动了一个线程来控制周期性改变这6个TextView的背景色。
MainActivity.java
package com.example.framelayouttest;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
import org.w3c.dom.Text;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private int currentColor = 0;
//定义一个颜色数组
final int [] colors = new int []{
R.color.color1,
R.color.color2,
R.color.color3,
R.color.color4,
R.color.color5,
R.color.color6,
};
final int [] names = new int [] {
R.id.view01,
R.id.view02,
R.id.view03,
R.id.view04,
R.id.view05,
R.id.view06
};
TextView [] views = new TextView[names.length];
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
//表明消息来自本程序所发送的
if(msg.what == 0x123){
for(int i = 0; i < names.length; i++){
views[i].setBackgroundResource(colors[(i+currentColor) % names.length]);
}
currentColor++;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceSrate) {
super.onCreate(savedInstanceSrate);
setContentView(R.layout.activity_main);
for(int i = 0; i < names.length; i++){
views[i] = (TextView)findViewById(names[i]);
}
//定义一个线程周期性地改变currentColor变量值
new Timer().schedule(new TimerTask() {
@Override
public void run() {
//发送一条空消息通知系统改变6个TextView组件的背景色
handler.sendEmptyMessage(0x123);
/*
for(int i = 0; i<names.length; i++){
views[i].setBackgroundResource(colors[(i+currentColor) % names.length]);
}
currentColor++;
*/
}
},0,2000);
}
}
实际效果:
4.相对布局 RelativeLayout
5.网格布局 GridLayout
6.绝对布局 AbsoluteLayout
Android中一般支持如下常用的距离单位:
四.TextView及其子类
五.ImageView及其子类
六.AdapterView及其子类
七.ProgressBar及其子类
八.ViewAnimator及其子类
九.对话框