Android应用的所有UI组件都继承了View类,View组件非常类似于Swing编程中的JPanel,它代表了一个空白的矩形区域,View组件没有任何内容。对于Android应用的其它UI组件来说,它们都继承了View组件,然后在View组件提供的空白区域上绘制外观。
Android采用了”组合器“设计模式来设计View和ViewGroup,ViewGroup作为View的重要子类,通用作为其它组件的容器使用。
当Android系统提供的UI组件不足以满足项目需要时,开发者可以通过继承View来派生自定义组件。在自定义组件时,通常被重写的方法(实际开发中只重写部分)如下:
Android推荐使用XML布局文件来定义用户界面,而不是使用Java代码来开发用户界面。Android中控制组件的方式有如下两种:
上述两种方法控制Android用户界面行为的本质是一样的,通常情况下,控制UI组件的XML属性还有对应的方法。下面就对这两种方法进行简单介绍:
Android推荐使用XML布局文件来控制视图,这样不仅简单、明了,而且可以将应用的视图控制逻辑从Java代码中分离出来,更好地体现了MVC原则。
当应用在res/layout
目录下定义一个主文件名任意的XML布局文件之后,R.java
会自动收录此布局资源。
setContentView(R.layout.<资源文件名字>) //在Activity中显示该视图
findViewById(R.id.) //通过ID获取UI组件,之后就可以通过代码来控制此UI组件的外观行为了(如为UI组件绑定事件监听器等)。
如果希望代码中控制UI界面,我们可以完全抛弃XML布局文件 ,而将所有的UI组件都通过new关键字创建出来,然后以合适的方式”搭建“在一起即可。
public class CodeView extends Activity {
//当第一次创建该Activity时回调该方法
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//创建一个线性布局管理器
LinearLayout layout = new LinearLayout(this);
//设置该Activity显示layout
super.setContentView(layout);
layout.setOrientation(LinearLayout.VERTICAL);
//创建一个TextView
final TextView show = new TextView(this);
//创建一个按钮
Button bn = new Button(this);
bn.setText(R.string.ok);
bn.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
//向Layout容器中添加TextView
layout.addView(show);
//向Layout容器中添加按钮
layout.addView(bn);
//为按钮绑定一个事件监听器
bn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
show.setText("Hello, Android, " + new java.util.Date());
}
});
}
}
完全在代码中控制UI界面不仅不利于高层次的解耦,而且由于通过new关键字来创建UI组件,需要调用方法来设置UI组件的行为,因此代码也显得十分臃肿。相反,如果通过XML文件来控制UI界面,开发者只要在XML布局文件中使用标签即可创建UI组件,而且只要配置简单的属性即可控制UI组件的行为,因此要简单得多。
完全使用代码来控制UI界面不仅烦琐,而且不利于解耦;而完全利用XML布局文件来控制UI界面虽然方便、便捷,但难免有失灵活。
当混合使用XML布局文件和代码来控制UI界面时,习惯上把变化 小、行为比较固定的组件放在XML布局文件中管理,而那些变化较多、行为控制比较复杂的组件则交给Java代码来管理。
我们可以通过先在布局文件中定义一个简单的线性布局容器,然后在程序获取该容器,并往该容器中添加组件。此程序的功能是周期性展示定义在drawable下面的图片,展示中触发切换的操作是点击当前图片。具体代码如下:
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="miss.picturewall.PictureWall">
<LinearLayout
android:id="@+id/root"
android:layout_width="368dp"
android:layout_height="495dp"
android:orientation="vertical"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp">LinearLayout>
android.support.constraint.ConstraintLayout>
public class PictureWall extends AppCompatActivity {
//定义一个访问图片的数组
int[] images = new int[]{
R.drawable.jiajia,
R.drawable.jiajia1,
R.drawable.jiajia2,
R.drawable.jiajia3,
R.drawable.jiajia4,
R.drawable.jiajia5
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.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() {
int currentImg = 0;
@Override
public void onClick(View v) {
currentImg = (currentImg + 1) % images.length;
//改变ImageView里显示的图片
image.setImageResource(images[currentImg]);
}
});
}
}
一个小球跟随手指的程序。主要有以下三个文件
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="miss.fingerball.CustomView">
<LinearLayout
android:id="@+id/root"
android:layout_width="368dp"
android:layout_height="495dp"
android:orientation="vertical"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="8dp">LinearLayout>
android.support.constraint.ConstraintLayout>
public class BallView extends View {
public float currentX = 40;
public float currentY = 50;
public BallView(Context context) {
super(context);
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
//创建画笔
Paint p = new Paint();
//设置画笔颜色
p.setColor(Color.RED);
//绘制一个小球
canvas.drawCircle(currentX, currentY, 15, p);
}
}
public class CustomView extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout root = (LinearLayout)findViewById(R.id.root);
//创建BallView组件
final BallView ball = new BallView(this);
//设置自定义组件的最小宽度、高度
ball.setMinimumWidth(root.getWidth());
ball.setMinimumHeight(root.getHeight());
//为ball组件绑定Touch事件
ball.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//修改ball组件的currentX、currentY两个属性
ball.currentX = event.getX();
ball.currentY = event.getY();
//通知ball组件重绘
ball.invalidate();
return true;
}
});
root.addView(ball);
}
}
摘自《疯狂Android讲义》