2.1.1 视图组件与容器组件
Android应用的绝大部分UI组件都放在android.widget包及其子包、android.view包及其子包中,Android应用的所有UI组件都继承了View类
View类还有一个重要子类:ViewGroup,但ViewGroup通常作为其他组件使用。Android采用了“组合器”设计模式来设计View和ViewGroup:ViewGroup是View子类,因此ViewGroup也可被当成View使用。ViewGroup除了可以包含普通View组件外,还可以再次包含ViewGroup
View类的XML属性
android:alpha
|
|
设置透明度
|
android:background
|
|
|
android:clickable |
|
是否可激发单击事件
|
android:contentDescription
|
|
设置该组件的主要描述信息
|
android:drawingCacheQuality
|
|
所使用的绘制缓存的质量
|
android:fadeScrollbars
|
|
当不使用该组件的滚动条时,组件是否淡出滚动条
|
android:fadingEdge
|
|
设置滚动该组件时边界是否使用淡出效果
|
android:fadingEdgeLength
|
|
|
android:focusable
|
|
|
android:focusableInTouchMode
|
|
|
android:id
|
|
|
android:isScrollContainer
|
|
设置该组件是作为可滚动容器使用
|
android:keepScreenOn
|
|
是否会强制手机屏幕一直打开
|
android:longClickable
|
| 是否可响应长单击事件 |
android:minHeight
|
|
|
android:minWidth
|
|
|
android:nextFocusDown
|
|
设置焦点在该组件上,且按下键时获得焦点的组件ID
|
android:nextFocusLeft
|
|
|
android:nextFocusRight
|
|
|
android:nextFocusUp
|
|
|
android:onClick
|
|
|
android:padding
|
|
在组件四周设置填充区域
|
android:paddingBottom
|
|
|
android:paddingLeft
|
|
|
android:paddingRight
|
|
|
android:paddingTop
|
|
|
android:rotation
|
|
设置该组件旋转角度
|
android:rotationX
|
|
绕X轴旋转角度
|
android:rotationY
|
|
|
android:saveEnabled
|
|
如果设置为false,那么当该组件被冻结时,不会保存它的状态
|
android:scaleX
|
|
设置该组件在水平方向的缩放比
|
android:scaleY
|
|
|
android:scrollX
|
|
初始化后的水平滚动偏移
|
android:scrollY
|
|
|
android:scrollbarAlwaysDrawHorizontalTrack
|
|
是否总是显示水平滚动条的轨道
|
android:scrollbarAlwaysDrawVerticalTrack
|
|
|
android:scrollbarDefaultDelayBeforeFade
|
|
设置滚动条在淡出隐藏之前延迟多少毫秒
|
android:scrollbarFadeDuration
|
|
淡出隐藏过程需要多少秒
|
android:scrollbarSize
|
|
设置滚动条的宽度和水平滚动条的高度
|
android:scrollbarStyle
|
|
设置滚动条的风格和位置:
insideOverlay
insideInset
outsideOverlay
outsideInset
|
android:scrollbarThumbVertical
|
|
设置该组件的垂直滚动条的滑块对应的Drawable对象
|
android:scrollbarTrackHorizontal
|
|
|
android:scrollbarTrackVertical
|
|
|
android:scrollbars
|
|
定义该组件滚动时显示几个滚动条
none
horizontal
vertical
|
android:soundEffectsEnable
|
|
|
android:tag
|
| 字符串tag,findViewWithTag()查找该组件 |
android:transformPivotX
|
|
设置该组件旋转时旋转中心的X坐标
|
android:transformPivotY
|
|
|
android:translationX
|
|
X方向上的位移
|
android:translationY
|
|
|
android:visibility
|
|
是否可见
|
ViewGroup继承了View类,当然也可以当成普通View来使用,但ViewGroup主要还是当成容器类使用。但由于ViewGroup是一个抽象类,实际使用中总是使用ViewGroup的子类来作为容器,例如各种布局管理器
ViewGroup容器控制其子组件的分布依赖于ViewGroup.LayoutParams、ViewGroup.MarginLayoutParams两个内部类。这两个内部类都提供了一些xml属性,ViewGroup容器中的子组件可以指定这些xml属性。
android:layout_height
|
支持的属性值:
fill_parent
match_parent
wrap_content
|
android:layout_width
|
|
为组件指定了高度与宽度,为何还要设置布局高度与布局宽度?
Android组件的大小不仅受它实际的宽度、高度控制,还受它的布局高度与布局宽度控制。
例如,设置一个组件的宽度为30如果将它的布局宽度设为match_parent,那么该组件的宽度将被“拉宽”到占满它所在的父容器;若设为wrap_content,那么该组件的宽度才会是30px。
下表显示了ViewGroup.MarginLayoutParams用于控制子组件周围页边距,其所支持的xml属性有
android:layout_marginBottom
|
|
|
android:layout_marginLeft
|
|
|
android:layout_marginRight
|
|
|
android:layout_marginTop
|
|
|
2.1.2 使用xml布局文件控制UI界面
Android使用xml布局文件来控制视图,这样可以将视图控制逻辑从Java代码中分离出来,从而更好的解耦,体现mvc原则。
当我们在Android应用res/layout目录下定义一个主文件名任意的xml布局文件后(R.java会自动收录该布局资源),Java代码可通过如下方法在Activity中显示该视图:
setContentView(R.layout.<资源文件名>);
当在布局文件中添加多个UI组件时,都可以为该UI组件指定andorid:id属性,该属性的属性值代表该组件的唯一标识。如果希望在Java代码中访问指定UI组件,可通过如下代码来访问:
findViewById(R.id.<android.id属性值>);
一旦在程序中获得指定UI组件之后,接下来就可以代码来控制各UI组件的外观行为了,包括为UI组件绑定事件监听器等
示例代码:
public
class
MainActivity
extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
super.setContentView(layout);
layout.setOrientation(LinearLayout.VERTICAL);
final TextView show = new TextView(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
super.setContentView(layout);
layout.setOrientation(LinearLayout.VERTICAL);
final TextView show = new TextView(this);
Button bn =
new Button(this);
bn.setText(“get time");
bn.setLayoutParams(new
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
layout.addView(show);
layout.addView(bn);
bn.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
show.setText("Hello,Android,"+ new java.util.Date());
}
}
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
layout.addView(show);
layout.addView(bn);
bn.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
show.setText("Hello,Android,"+ new java.util.Date());
}
}
);
}
}
可以看出,通过代码创建UI组件都需要new出一个新的对象,无论创建哪种UI组件,都需要传入一个this参数,这是由于创建UI组件时传入一个Context参数,Context代表访问Android应用环境的全局信息的API。
Activity、Service都继承了Context,都可以直接作为Context使用
2.1.4 使用xml布局文件和Java代码混合控制UI界面
这种情形下,习惯上把变化小、行为固定的组件放在xml布局文件管理中,而那些变化较多,行为控制比较复杂的组件则交给Java
图片查看器示例代码:
public
class
MainActivity
extends ActionBarActivity {
int[]
images
=
new
int[]{
R.drawable.java,
R.drawable.ee,
R.drawable.classic};
int currentImg = 0;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout main = (LinearLayout) findViewById(R.id.root);
final ImageView image = new ImageView(this);
main.addView(image);
image.setImageResource(images[0]);
image.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
image.setImageResource(images[++currentImg % images.length]);
}
});
R.drawable.java,
R.drawable.ee,
R.drawable.classic};
int currentImg = 0;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout main = (LinearLayout) findViewById(R.id.root);
final ImageView image = new ImageView(this);
main.addView(image);
image.setImageResource(images[0]);
image.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
image.setImageResource(images[++currentImg % images.length]);
}
});
}
}
当Android系统提供的UI组件不足以满足项目需要时,开发者可以通过继承View来派生自定义组件。
派生自己的组件时,通常重写的方法如下:
构造器:重写构造器是定制View的最基本方法,当Java代码创建一个View实例,或根据xml布局文件加载并构建界面时讲需要调用该构造器。
onFinishInflate():这是一个回调方法,当应用从xml布局文件加载该组件并利用它来构建界面之后,该方法将被回调
onMeasure(int,int):检测View组件及它所包含的所有子组件的大小
onLayout(boolean,int, int, int, int):当该组件需要分配其子组件的位置、大小时,该方法就会被回调
onSizeChanged(int,int, int, int):当该组件的大小被改变时该方法被回调
onDraw(Canvas):当该组件将要绘制它的内容时回调该方法进行绘制
onKeyDown(int, KeyEvent):当按下某个键时触发该方法
onKeyUp(int, KeyEvent):当松开某个按键时触发该方法
onTrackballEvent(MotionEvent):当发生轨迹球事件时触发该方法
onTouchEvent(MotionEvent):当发生触摸屏事件时触发该方法
onWindowsFocusChanged(boolean):当组件得到、失去焦点时触发
onAttachedToWindow():当把该组件放入某个窗口时触发
onDetachedFromWindow():当把该组件从某个窗口上分离时触发
onWindowsVisibilityChanged(int):当包含该组件的窗口的可见性发生改变时触发
跟随手指滚动的小球实例代码:
file:DrawView.java
public
class
DrawView
extends View {
public float currentX = 360;
public float currentY = 540;
Paint p = new Paint();
public DrawView(Context context)
{
super(context);
}
public DrawView(Context context, AttributeSet set)
{
super(context,set);
}
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
p.setColor(Color.RED);
canvas.drawCircle(currentX, currentY, 15, p);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
currentX =event.getX();
currentY =event.getY();
invalidate();
return true;
}
public float currentX = 360;
public float currentY = 540;
Paint p = new Paint();
public DrawView(Context context)
{
super(context);
}
public DrawView(Context context, AttributeSet set)
{
super(context,set);
}
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
p.setColor(Color.RED);
canvas.drawCircle(currentX, currentY, 15, p);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
currentX =event.getX();
currentY =event.getY();
invalidate();
return true;
}
}
file:main_activity.java
public
class
MainActivity
extends ActionBarActivity {
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout root = (LinearLayout) findViewById(R.id.root);
final DrawView draw = new DrawView(this);
//draw.setMinimumWidth(300);
//draw.setMinimumHeight(500);
root.addView(draw);
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout root = (LinearLayout) findViewById(R.id.root);
final DrawView draw = new DrawView(this);
//draw.setMinimumWidth(300);
//draw.setMinimumHeight(500);
root.addView(draw);
}