您的位置:首页 > 产品设计 > UI/UE

AndroidGUI06:ProgressBar的常用技巧

2011-05-11 22:55 351 查看
ProgressBar
有两种主要的形态:一个是圆形的,一个是长条形的,形如:



圆形的
ProgressBar
,通常用于未确定的何时结束的进度显示,它会一直显示动画。

长条形的
ProgressBar
,通常用于进度明确的进度显示。

1.

在布局文件
(main.xml)
中,增加界面元素声明如下:

<?
xml
version
=
"1.0"

encoding
=
"utf-8"

?>

<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"

android:orientation
=
"vertical"

android:layout_width
=
"fill_parent"

android:layout_height
=
"fill_parent"

>

<
ProgressBar

android:id
=
"@+id/progress_bar1"

style
=
"?android:attr/progressBarStyleSmall"

<!--

小圆
ProgressBar -->

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

/>

<
ProgressBar

android:id
=
"@+id/progress_bar2"

<!--

缺省地,是中圆
ProgressBar -->

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

/>

<
ProgressBar

android:id
=
"@+id/progress_bar3"

style
=
"?android:attr/progressBarStyleLarge"

<!--

大圆
ProgressBar -->

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

/>

<
ProgressBar

android:id
=
"@+id/progress_bar4"

style
=
"?android:attr/progressBarStyleHorizontal"

<!--

长条形
ProgressBar -->

android:layout_width
=
"fill_parent"

android:layout_height
=
"8sp"

<!--

指明高度为
8sp-->

android:max
=
"100"

<!--

最大值为
100 -->

/>

<
TextView

<!--

TextView
做分隔符用
-->

android:layout_width
=
"fill_parent"

android:layout_height
=
"6sp"

/>

<
ProgressBar

android:id
=
"@+id/progress_bar5"

style
=
"?android:attr/progressBarStyleHorizontal"

android:layout_width
=
"fill_parent"

android:layout_height
=
"wrap_content"

android:max
=
"100"

/>

<
Button
<!--

用于触发进度条相关操作
–>

android:id
=
"@+id/button"

android:layout_width
=
"wrap_content"

android:layout_height
=
"wrap_content"

android:text
=
"

进度条测试

"

/>

</
LinearLayout
>

对应的界面结果显示如下:



2.

通过程序的方式,我们还可以把进度条放到应用的标题栏
(Title bar)
中。这个可以用程序来实现:

requestWindowFeature(Window.
FEATURE_INDETERMINATE_PROGRESS

);
//

Titlebar
中,放置圆形进度条

requestWindowFeature(Window.
FEATURE_PROGRESS

);
//


Titlebar
中,放置长条形进度条

setContentView(R.layout.
main

);

setProgressBarIndeterminateVisibility(
true

);
//


Titlebar
中,显示圆形进度条

setProgressBarVisibility(
true

);
//


Titlebar
中,显示长条形进度条

注意:
requestWindowFeature
方法的调用,必须在
setContentView
之前!

3.

Activity
所对应的代码:

public

class
ControlProgressBar
extends
Activity

implements

OnClickListener

{

//
声明
5

ProgressBar
对象

private
ProgressBar
progress_bar1
;

private
ProgressBar
progress_bar2
;

private
ProgressBar
progress_bar3
;

private
ProgressBar
progress_bar4
;

private
ProgressBar
progress_bar5
;

//
声明一个
Button
对象

private
Button
button
;

//
声明一个
Handler
对象

private
Handler
progressHandler
;

@Override

public

void
onCreate(Bundle savedInstanceState)

{

super
.onCreate(savedInstanceState);

requestWindowFeature(Window.
FEATURE_INDETERMINATE_PROGRESS

);

//
在应用的
Title bar
上放置圆形
ProgressBar

requestWindowFeature(Window.
FEATURE_PROGRESS

);

//
在应用的
Title bar
上放置条形
ProgressBar

setContentView(R.layout.
main

);

// requestWindowFeature
方法的调用必须在
setContentView
之前

setProgressBarIndeterminateVisibility(
true
);

//
在应用的
Title bar
上显示圆形
ProgressBar

setProgressBarVisibility(
true
);

//
在应用的
Title bar
上显示条形
ProgressBar

//
获取
ProgressBar
对象

progress_bar1
= (ProgressBar)findViewById(R.id.
progress_bar1

);

progress_bar2
= (ProgressBar)findViewById(R.id.
progress_bar2

);

progress_bar3
= (ProgressBar)findViewById(R.id.
progress_bar3

);

progress_bar4
= (ProgressBar)findViewById(R.id.
progress_bar4

);

progress_bar5
= (ProgressBar)findViewById(R.id.
progress_bar5

);

//
获取
Handler
对象

progressHandler
=
new
Handler()

{

@Override

public

void
handleMessage(Message msg)

//
重写
handleMessage
方法

{

setProgress(msg.
what
* 100);

//
设定
Title bar
上的条形和圆形
ProgressBar
的进度
,
缺省地


//
他们的最大值为
10000
,为此,由于我们准备的
msg.what
的取值

//
范围为
0 ~ 100
,因此,在这里需要乘以
100


//
另外需要注意的是,当
Title bar
上的
ProgressBar
达到最大值

//
后,他们会自行消失

progress_bar4
.setProgress(msg.
what
);

//
根据
msg.what
的取值

设定
progress_bar4
的进度

progress_bar5
.setProgress(msg.
what
);

//
根据
msg.what
的取值

设定
progress_bar5
的进度

progress_bar5
.setSecondaryProgress((
int
)(Math.sqrt
(msg.
what
)) * 10);

//
根据
msg.what
的取值,设定
progress_bar5
的第二个进度

if
(msg.
what
== 100)

//
达到最大值后


progress_bar4
不可见

{

progress_bar4
.setVisibility(ProgressBar.
INVISIBLE

);

}

}

};

//
获取
Button
对象

并为其设置
OnClickListener

button
= (Button)findViewById(R.id.
button

);

button
.setOnClickListener(
this
);

}

public

void
onClick(View v)

{

progress_bar1
.setVisibility(ProgressBar.
VISIBLE

);

// progress_bar1
继续可见

progress_bar2
.setVisibility(ProgressBar.
GONE

);

// progress_bar2
不可见

且离开界面

progress_bar3
.setVisibility(ProgressBar.
INVISIBLE

);

// progress_bar3
不可见

但依然在界面上

ProgressThread pt
=
new
ProgressThread(
progressHandler
);

//
创建线程
pt

pt.start();

//
启动线程
pt

}

}

class
ProgressThread
extends
Thread

{

private
Handler
handler
;

public
ProgressThread(Handler handler)

//
传入一个
Handler
对象

{

this
.
handler
= handler;

}

@Override

public

void
run()

{

int
i = 0;

while
(i <= 100)

{

handler
.sendEmptyMessage(i);

// i
就是
Message

what
的值

handler.sendEmptyMessage

//
会触发
handler

handleMessage
执行

++i;

try

{

sleep
(100);

//
休息
100ms

}

catch

(InterruptedException e)

{

e.printStackTrace();

}

}

}

}

运行结果:

在点击按钮之前:



点击按钮后:



达到最大值后:



4.

关于
Only the
original thread that created a view hierarchy can touch its views
错误


Android
编程中,使用
Thread
更新
ProgressBar
的进度的时候,很多人都碰到过类似的问题。最好的解决办法就是类似
3
中所给出的代码。

5.

在上面的代码中,我们知道,所有的
ProgressBar
对象,都是在
Activity
ControlProgressBar
中创建的,因此,对于这些
ProgressBar
的更新工作,就必须要在
ControlProgressBar
这个
Activity
中完成
(
在这个例子中,是该应用的主线程
)
,而不能在另外一个线程中来完成对那些
ProgressBar
的状态更新。否则,就会出现“
Only the original thread that created a view hierarchy
can touch its views
”这样的错误,从而使整个应用被
Forced
Close


在上面的代码中,在
onClick
方法里面,我们新创建了一个
ProgressThread
的线程,在这个线程中,并没有直接去更新各个
ProgressBar
的状态,只是通过一个循环,不断产生
Message.what
,并通过
sendMessage
方法,向
progressHandler
发送消息,并触发
progressHandler
中的
handleMessage
方法的执行。很显然
progressHandler
是在
Activity
ControlProgressBar
中创建的,它本身也并没有创建新的线程,而在
handleMessage
方法中,我们对各个
ProgressBar
对象的状态,进行了更新。

类似下面的代码,试图在另外一个线程中改变主线程中界面元素的状态,就会出现“
Only the
original thread that created a view hierarchy can touch its views
”这样的错误:

public

class
ControlProgressBar
extends
Activity

implements

OnClickListener

{

//
声明
5

ProgressBar
对象

// … …

//
声明一个
Button
对象

private
Button
button
;

@Override

public

void
onCreate(Bundle savedInstanceState)

{

super
.onCreate(savedInstanceState);

requestWindowFeature(Window.
FEATURE_INDETERMINATE_PROGRESS

);

requestWindowFeature(Window.
FEATURE_PROGRESS

);

setContentView(R.layout.
main

);

setProgressBarIndeterminateVisibility(
true
);

setProgressBarVisibility(
true
);

//
获取
ProgressBar
对象

// … …

//
获取
Button
对象

并为其设置
OnClickListener

button
= (Button)findViewById(R.id.
button

);

button
.setOnClickListener(
this
);

}

public

void
onClick(View v)

{

ProgressThread pt
=
new
ProgressThread(
this
);

//
创建线程
pt

pt.start();

//
启动线程
pt

}

}

class
ProgressThread
extends
Thread

{

private
Context
ctx
;

public
ProgressThread(Context
ctx)

//
传入一个
Context
对象
(
实参将是
ControlProgressBar
)

{

this
.
ctx
= ctx;

}

@Override

public

void
run()

{

int
i = 0;

while
(i <= 100)

{

setProgress(i*
100);

//
在本线程中

更新主线程中界面元素
Title bar
上的
ProgressBar
的状态
,就会出现:

//

Only the original thread that created a view hierarchy can touch its
views
”这样的错误

++i;

try

{

sleep
(100);

//
休息
100ms

}

catch
(InterruptedException e)

{

e.printStackTrace();

}

}

}

}

6.

形如下面的代码,不会报错,但会阻塞
ProgressBar
对象的状态更新,因此也不是好办法。可惜网上很多人似乎在推荐这种方式,实有误人之嫌。

final
Handler handler=
new
Handler();

final
Runnable
runnable
=
new
Runnable()

{

public

void
run()

{

//
更新界面元素

}

};

private
OnClickListener btnLisener =
new
OnClickListener()

{

public

void
onClick(View v)

{

requestData();

}

};

protected

void
requestData()

{

Thread t =
new
Thread()

{

public

void
run()

{

handler.post(runnable);

//
加入到消息队列这样没有启动新的线程

虽然没有报异常

但仍然阻塞
ProgressBar
的进度显示

}

};

t.start();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: