二、Android应用的界面编程(一)界面编程与视图(View)组件

Android应用的绝大部分UI组件都放在android.widget包及其子包、android.view包及其子包中,
Android应用的所有UI组件都继承了View类。它代表一个空白的矩形区域。
View类还有一个重要的子类:ViewGroup,但ViewGroup通常作为其他组件的容器使用。
Android的所有UI都是建立在View、ViewGroup基础之上的,因此ViewGroup也可以被当成View使用。
ViewGroup里除了可以包含普通View组件之外,还可以再次包含ViewGroup组件。

Android定义用户界面
1)在XML布局文件中通过XML属性进行控制。
2)在Java程序代码中通过调用方法进行控制。

 

 

Drawable是Android提供的一个抽象类,它代表了“可以被绘制出来的某种东西”,
Drawable包括了大量子类,比如:
BitmapDrawable代表位图Drawable;
ColorDrawable代表颜色Drawable;
ShapeDrawable代表几何形状Drawable;
各种Drawable可以用于定制UI组件的背景等外观。

ViewGroup继承了View类,也可以当成普通View来使用。但ViewGroup主要还是当成容器类使用。但由ViewGroup
是一个抽象类,因此实际使用中通常总是使用ViewGroup的子类来作为容器,例如各种布局管理器。
ViewGroup容器控制其子组件的分布依赖于ViewGroup.LayoutParams、ViewGroup.MarginLayoutParams两个内部类。
这两个内部类中都提供了一些XML属性,ViewGroup容器中的子组件可以指定这些XML属性。

ViewGroup.LayoutParams所支持的两个XML属性。
android:layout_width 指定该子组件的布局高度。
android:layout_height 指定该子组件的布局宽度。
属性值:
fill_parent:指定子组件的高度、宽度与父容器组件的高度、宽度相同(实际上还要减去填充的空白距离)。
match_parent:与fill_parent相同,从Android2.2开始推荐使用这个属性来代替fill_parent。
wrap_content:指定子组件的大小恰好能包裹它的内容即可。

【ViewGroup.MarginLayoutParams支持的属性】
android:layout_marginBottom 指定该子组件下边的页边距。
android:layout_marginLeft 指定该子组件左边的页边距。
android:layout_marginRight 指定该子组件右边的页边距。
android:layout_marginTop 指定该子组件上边的页边距。
相关方法:setMargins(int,int,int,int)


实例:在代码中控制UI界面

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("单击我");
        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 OnClickListener() {
            @Override
            public void onClick(View v) {
                show.setText("Hello , Android , " + new java.util.Date());
            }
        });
    }
}

从上面的代码看出,该程序中所用到的UI组件都是通过new关键字创建出来的。然后程序使用LinearLayout容器来“盛装”这些UI组件,这样就组成了图形用户界面。

从上面的程序代码中可以看出,无论创建哪种UI组件,都需要传入一个this参数,这是由于创建UI组件时传入一个
Context代表访问Android应用环境的全局信息的API。让UI组件持有一个Context参数,可让这些UI组件通过该Context
参数来获取Android应用环境的全局信息。
Context本身是一个抽象类,Android应用的Activity、Service都继承了Context,因此Activity、Service都可以直
接作为Context使用。


实例:使用XML布局文件和Java代码混合控制UI界面(简单图片浏览器)。
<?xml version="1.0" encoding="utf-8"?>
<!-- 定义一个线性布局容器 -->

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
</LinearLayout>
 1 public class MixView extends Activity {
 2     // 定义一个访问图片的数组
 3     int[] images = new int[] { R.drawable.java, R.drawable.ee,
 4             R.drawable.classic, R.drawable.ajax, R.drawable.xml, };
 5     int currentImg = 0;
 6 
 7     @Override
 8     public void onCreate(Bundle savedInstanceState) {
 9         super.onCreate(savedInstanceState);
10         setContentView(R.layout.main);
11         // 获取LinearLayout布局容器
12         LinearLayout main = (LinearLayout) findViewById(R.id.root);
13         // 程序创建ImageView组件
14         final ImageView image = new ImageView(this);
15         // 将ImageView组件添加到LinearLayout布局容器中
16         main.addView(image);
17         // 初始化时显示第一张图片
18         image.setImageResource(images[0]);
19         image.setOnClickListener(new OnClickListener() {
20             @Override
21             public void onClick(View v) {
22                 // 改变ImageView里显示的图片
23                 image.setImageResource(images[++currentImg % images.length]);
24             }
25         });
26     }
27 }

 

【开发自定义View】
首先定义一个继承View基类的子类,然后重写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):当发生触摸屏幕事件时触发该方法。

# onWindowFocusChanged(boolean):当该组件得到、失去焦点时触发该方法。

# onAttachedToWindow():当把该组件放入某个窗口时触发该方法。

# onDetachedFromWindow():当把该组件从某个窗口上分离时触发该方法。

# onWindowVisibilltyChanged(int):当包含该组件的窗口的可见性发生改变时触发该方法。

当需要开发自定义View时,开发者并不需要重写上面列出的所有方法,而是可以根据业务需要重写上面的部分方法,
例如下面的示例程序就只重写onDraw(Canvas)方法。

实例:跟随手指的小球(可任意拖动)
这个UI组件将会在指定位置绘制一个小球,这个位置可以动态改变。当用户通过手指在屏幕上拖动时,程序监听
到这个手势动作,并把手指动作的位置传入自定义UI组件,并通知该组件绘制即可。

public class DrawView extends View {
    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
    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、currentY两个属性
        currentX = event.getX();
        currentY = event.getY();
        // 通知当前组件重绘自己
        invalidate();
        // 返回true表明该处理方法已经处理该事件
        return true;
    }
}

上面的DrawView组件继承了View基类,并重写了onDraw方法---该方法负责在该组件的指定位置绘制一个小球,除此

之外,该组件还重写了onTouchEvent(MotionEvent),该方法用于处理该组件的触碰事件,当用户手指触碰该组件时
将会激发该方法。当手指在触摸屏上移动时,将会不断地触发触摸屏事件,事件监听器中负责触发事件的坐标将被
传入DrawView组件,并通过该组件重绘---这样就可保证DrawView上小球跟随手指移动而移动。

接下来可以通过Java代码把该组件添加到指定的容器中,这样就可以看到该组件的运行结果了。

public class CustomView extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // 获取布局文件中的LinearLayout容器
        LinearLayout root = (LinearLayout) findViewById(R.id.root);
        // 创建DrawView组件
        final DrawView draw = new DrawView(this);
        // 设置自定义组件的最大宽度、高度
        draw.setMinimumWidth(300);
        draw.setMinimumHeight(500);
        root.addView(draw);
    }
}

 

posted on 2015-06-24 13:32  大米稀饭  阅读(566)  评论(0编辑  收藏  举报