Android应用的界面编程

来源:互联网 发布:pg美人网 淘宝 编辑:程序博客网 时间:2024/06/04 17:51

界面编程与视图(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             @Override21             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);    }}

二、Android应用的界面编程(六)ProgressBar及其子类[SeekBar、RatingBar]er

通常用于向用户显示某个耗时操作完成的百分比。Android支持几种风格的进度条,通过style属性可以为ProgressBar指定风格。该属性支持如下几个属性值。# @android:style/Widget.ProgressBar.Horizontal; 水平进度条。# @android:style/Widget.ProgressBar.Inverse; 普通大小的环形进度条。# @android:style/Widget.ProgressBar.Large; 大环形进度条。# @android:style/Widget.ProgressBar.Large.Inverse; 大环形进度条。# @android:style/Widget.ProgressBar.Small; 小环形进度条。# @android:style/Widget.ProgressBar.Small.Inverse; 小环形进度条。

【ProgressBar常用的XML属性和方法】android:max 设置该进度条的最大值android:progress 设置该进度条的已完成进度值android:progressDrawable 设置该进度条的轨道对应的Drawable对象android:indeterminate 该属性设为true,设置进度条不精确显示进度android:indeterminateDrawable 设置绘制不显示进度的进度条的Drawable对象android:indeterminateDuration 设置不精确显示进度的持续时间

getMax():返回这个进度条的范围的上限。getProgress():返回进度。getSecondaryProgress():返回次要进度。incrementProgressBy(int diff):指定增加的进度或减少(+进度增加,-进度减少)。isIndeterminate():指示进度条是否在不确定模式下。setIndeterminate(boolean indeterminate):设置不确定模式下。setVisibility(int v):设置该进度条是否可视。

android:progressDrawable用于指定进度条的轨道的绘制形式,该属性可指定为一个LayerDrawable对象(该对象可通过在XML文件中用<layer-list>元素进行配置)的引用。

范例:进度条各种样式。

复制代码
 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:layout_width="match_parent" 4     android:layout_height="match_parent" 5     android:orientation="vertical" >  7     <LinearLayout 8         android:layout_width="match_parent" 9         android:layout_height="wrap_content"10         android:orientation="horizontal" >12         <!-- 定义一个大环形进度条 -->13         <ProgressBar14             style="@android:style/Widget.ProgressBar.Large"15             android:layout_width="wrap_content"16             android:layout_height="wrap_content" />       18         <!-- 定义一个中等大小的环形进度条 -->19         <ProgressBar20             android:layout_width="wrap_content"21             android:layout_height="wrap_content" />   23         <!-- 定义一个小环形进度条 -->24         <ProgressBar25             style="@android:style/Widget.ProgressBar.Small"26             android:layout_width="wrap_content"27             android:layout_height="wrap_content" />28     </LinearLayout>29 30     <TextView31         android:layout_width="fill_parent"32         android:layout_height="wrap_content"33         android:text="任务完成的进度" />34     35     <!-- 定义一个水平进度条 -->36     <ProgressBar37         android:id="@+id/bar"38         style="@android:style/Widget.ProgressBar.Horizontal"39         android:layout_width="fill_parent"40         android:layout_height="wrap_content"41         android:max="100" />     43     <!-- 定义一个水平进度条,并改变轨道外观 -->44     <ProgressBar45         android:id="@+id/bar2"46         style="@android:style/Widget.ProgressBar.Horizontal"47         android:layout_width="fill_parent"48         android:layout_height="wrap_content"49         android:max="100"50         android:progressDrawable="@drawable/my_bar" />52 </LinearLayout>
复制代码

其中android:progressDrawable="@drawable/my_bar" 的样式如下:

复制代码
<?xml version="1.0" encoding="UTF-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android">    <!-- 定义轨道的背景  (错号小图标)-->    <item android:id="@android:id/background"        android:drawable="@drawable/no" />    <!-- 定义轨道上已完成部分的样式 (对号小图标) -->    <item android:id="@android:id/progress"        android:drawable="@drawable/ok" /></layer-list>
复制代码

 

复制代码
 1 public class ProgressBarTest extends Activity { 2     // 该程序模拟填充长度为100的数组 3     private int[] data = new int[100]; 4     int hasData = 0; 5     // 记录ProgressBar的完成进度 6     int status = 0; 7     ProgressBar bar, bar2; 8     // 创建一个负责更新的进度的Handler 9     Handler mHandler = new Handler() {10         @Override11         public void handleMessage(Message msg) {12             // 表明消息是由该程序发送的13             if (msg.what == 0x111) {14                 bar.setProgress(status);15                 bar2.setProgress(status);16             }17         }18     };19 20     @Override21     public void onCreate(Bundle savedInstanceState) {22         super.onCreate(savedInstanceState);23         setContentView(R.layout.main);24         bar = (ProgressBar) findViewById(R.id.bar);25         bar2 = (ProgressBar) findViewById(R.id.bar2);26 27         // 启动线程来执行任务28         new Thread() {29             public void run() {30                 while (status < 100) {31                     // 获取耗时操作的完成百分比32                     status = doWork();33                     // 发送消息34                     mHandler.sendEmptyMessage(0x111);35                 }36             }37         }.start();38     }39 40     // 模拟一个耗时的操作41     public int doWork() {42         // 为数组元素赋值43         data[hasData++] = (int) (Math.random() * 100);44         try {45             Thread.sleep(100);46         } catch (InterruptedException e) {47             e.printStackTrace();48         }49         return hasData;50     }51 }
复制代码

范例:显示在标题上的进度条
1) 调用Activity的requestWindowFeature(),该方法根据传入的参数可启用特定的窗口特征,例如
传入Window.FEATURE_INDETERMINATE_PROGRESS在窗口标题上显示不带进度的进度条;传入
Window.FEATURE_PROGRESS则显示带进度的进度条。
2) 调用Activity的setProgressBarVisibility(boolean)setProgressBarIndeterminateVisibility(boolean)
即可控制进度条的显示和隐藏。

复制代码
public class TitleProgressBar extends Activity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // //设置窗口特征:启用显示进度的进度条        // requestWindowFeature(Window.FEATURE_PROGRESS); //// 设置窗口特征:启用不显示进度的进度条        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); //        setContentView(R.layout.main);        Button bn1 = (Button) findViewById(R.id.bn1);        Button bn2 = (Button) findViewById(R.id.bn2);        bn1.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View source) {                // 显示不带进度的进度条。                setProgressBarIndeterminateVisibility(true);                // 显示带进度的进度条。                setProgressBarVisibility(true);                // 设置进度条的进度                setProgress(4500);            }        });        bn2.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View source) {                // 隐藏不带进度的进度条。                setProgressBarIndeterminateVisibility(false);                // 隐藏带进度的进度条。                setProgressBarVisibility(false);            }        });    }}
复制代码

 

===== 拖动条(SeekBar)的功能和用法 =====
# 拖动条是通过滑块的位置来标识数值,而且拖动条允许用户拖动滑块来改变值,比如:调节音量等。
# 由于SeekBar继承了ProgressBar,因此ProgressBar所支持的XML属性和方法完全适用于SeekBar。
# android:thumb:指定一个Drawable对象,该对象将作为自定义滑块,改变拖动条的滑块外观。
# 为了让程序能响应拖动条滑块位置的改变,程序可以考虑为它绑定一个OnSeekBarChangeListener监听器。


范例:通过拖动滑块来改变图片的透明度

复制代码
 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:orientation="vertical" 4     android:layout_width="fill_parent" 5     android:layout_height="fill_parent"> 6 <ImageView  7     android:id="@+id/image" 8     android:layout_width="fill_parent"  9     android:layout_height="240px" 10     android:src="@drawable/lijiang" />11 <!-- 定义一个拖动条,并改变它的滑块外观 -->12 <SeekBar 13     android:id="@+id/seekbar"14     android:layout_width="fill_parent" 15     android:layout_height="wrap_content" 16     android:max="255"17     android:progress="255"18     android:thumb="@drawable/ic_launcher" />19 </LinearLayout>
复制代码
复制代码
 1 public class SeekBarTest extends Activity { 2     ImageView image; 3  4     @Override 5     public void onCreate(Bundle savedInstanceState) { 6         super.onCreate(savedInstanceState); 7         setContentView(R.layout.main); 8         image = (ImageView) findViewById(R.id.image); 9         SeekBar seekBar = (SeekBar) findViewById(R.id.seekbar);10 11         seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {12             // 当拖动条的滑块位置发生改变时触发该方法13             @Override14             public void onProgressChanged(SeekBar arg0, int progress,15                     boolean fromUser) {16                 // 动态改变图片的透明度17                 image.setAlpha(progress);18             }20             @Override21             public void onStartTrackingTouch(SeekBar bar) {22             }24             @Override25             public void onStopTrackingTouch(SeekBar bar) {26             }27         });28     }29 }
复制代码

===== 星级评分条(RatingBar)的功能和用法 =====

# RatingBar与SeekBar最大区别在于:RatingBar通过星星来表示进度。

【RatingBar支持的常见XML属性】
android:rating 设置该星级评分条默认的星级
android:numStars 设置该星级评分条总共有多少个星级
android:stepSize 设置每次最少需要改变多少个星级
android:isIndicator 设置该星级评分条是否允许用户改变(true为不允许修改)

为了让程序能相应星级评分的改变,程序可以考虑为它绑定一个OnRatingBarChangeListener监听器。

范例:通过星级改变图片的透明度

复制代码
 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:orientation="vertical" 4     android:layout_width="fill_parent" 5     android:layout_height="fill_parent"> 6 <ImageView  7     android:id="@+id/image" 8     android:layout_width="fill_parent"  9     android:layout_height="240px" 10     android:src="@drawable/lijiang" />11 <!-- 定义一个星级评分条 -->    12 <RatingBar 13     android:id="@+id/rating"14     android:layout_width="wrap_content" 15     android:layout_height="wrap_content" 16     android:numStars="5"17     android:max="255"18     android:progress="255"19     android:stepSize="0.5" />20 </LinearLayout>
复制代码
复制代码
 1 public class RatingBarTest extends Activity { 2     ImageView image; 3  4     @Override 5     public void onCreate(Bundle savedInstanceState) { 6         super.onCreate(savedInstanceState); 7         setContentView(R.layout.main); 8         image = (ImageView) findViewById(R.id.image); 9         RatingBar ratingBar = (RatingBar) findViewById(R.id.rating);10 11         ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {12             // 当拖动条的滑块位置发生改变时触发该方法13             @Override14             public void onRatingChanged(RatingBar arg0, float rating,15                     boolean fromUser) {16                 // 动态改变图片的透明度,其中255是星级评分条的最大值17                 // 5个星星就代表最大值25518                 image.setAlpha((int) (rating * 255 / 5));19             }20         });21     }22 }
复制代码

由于上面定义RatingBar时指定了android:stepSize="0.5",因此该星级评分条中星级的最小变化为0.5,也就是

最少要变化半个星级。

【改变样式】其中XML属性 style="@style/roomRatingBar"的样式如下:

复制代码
styles.xml<?xml version="1.0" encoding="utf-8"?><resources>    <style name="roomRatingBar" parent="@android:style/Widget.RatingBar">       <item name="android:progressDrawable">@drawable/room_rating_bar</item>       <item name="android:minHeight">16dip</item>       <item name="android:maxHeight">16dip</item>    </style></resources>
复制代码

上面的意思是继承@android:style/Widget.RatingBar,重写android:progressDrawable属性,换成我们自定义@drawable/room_rating_bar文件。

控制该组件的最大和最小高度。好我们继续去找这自定义文件@drawable/room_rating_bar。

room_rating_bar.xml

复制代码
<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android">    <item android:id="@+android:id/background"    android:drawable="@drawable/room_unselect" />     <item android:id="@+android:id/secondaryProgress"    android:drawable="@drawable/room_unselect" />     <item android:id="@+android:id/progress"    android:drawable="@drawable/room_select" /> </layer-list>
复制代码

0 0
原创粉丝点击