效果预览:
正文
思考:
(1)如何绘制扇形。
(2)重写onDraw(Canvas canvas) 或 draw(Canvas canvas)。
(3)是否保留背景设置。
(4)什么时候以及如何更新进度。
(5)自定义进度、绘画起点度、扇形颜色(背景)等属性。
(6)进度文字的显示。
(7)扫描、旋转、阴影等效果的实现。
……
思路:
(1)扇形绘制方法:
canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
(2)不保留背景设置,则重写draw(Canvas canvas),并去掉超类方法。
(3)同上。
(4)当新的进度不等于旧的进度,并且新的扇形弧度与旧的扇形弧度的距离>1时(绝对值,考虑人为打断更新进度导致新的进度小于旧的进度的情况。如完成后,设进度为0),调用更新方法。当进度不断更新时,即产生动画。
(5)命名空间、attrs文件
(6)文字绘制在中央、内部,或随进度的移动而移动。
(7)增加一些绚丽效果。
……
代码实现:
首先在 AndroidManifest.xml 添加访问网络的权限:
<uses-permission android:name="android.permission.INTERNET"/>
然后自定义定义属性,attrs代码:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="lu">
<attr name="progress" format="float"/>
<attr name="shapeColor" format="color"/>
<attr name="startPosition" format="float"/>
</declare-styleable>
</resources>
view的java代码:
package com.example.sectorprogressdemo.view;
import com.example.sectorprogressdemo.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/** * @author Yue * 扇形进度进度条。 * <p>说明: * <p>可以设置扇形颜色,背景,起始位置(度数)。 * <p>定义了扇形颜色,起始位置(度数),进度等属性。 * */
public class SectorProgressView extends View{
private Paint paint;
/**进度*/
private float progress;
private RectF rectf;
/**绘制度数*/
private float sweepangle;
// private String namespace = "http://www.hao123.com";
/**画笔颜色*/
private int shapeColor;
private float startPosition;
public SectorProgressView(Context context) {
this(context,null);//调用更多参数的构造方法
}
public SectorProgressView(Context context, AttributeSet attrs) {
this(context,attrs,0);//调用更多参数的构造方法
}
public SectorProgressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private final void init(Context context, AttributeSet attrs, int defStyle){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lu,defStyle, 0);
progress = a.getFloat(R.styleable.lu_progress, 0f);//获取自定义属性的进度值
//progress = attrs.getAttributeFloatValue(namespace , "hao",0);
shapeColor = a.getColor(R.styleable.lu_shapeColor, Color.BLUE);//获取自定义属性的画笔颜色
startPosition = a.getFloat(R.styleable.lu_startPosition, 0);//获取绘制的起始位置
a.recycle();
sweepangle = progress*360;
rectf = new RectF();
paint = new Paint();
paint.setAntiAlias(true);//抗锯齿
paint.setColor(shapeColor);
}
@Override
protected void onDraw(Canvas canvas) {
// rectf = new RectF(0, 0, getWidth(), getHeight());
if (rectf.isEmpty()) {
rectf.set(0, 0, getWidth(), getHeight());
}
sweepangle = progress*360;
canvas.drawArc(rectf, -180+startPosition, sweepangle, true, paint);//奇葩的,为0时是从右下角顺时针绘制,因此减去180度
}
/** * 设置进度。符合条件则更新进度条 * @param progress */
public void setProgerss(float progress){
float newSweepangle = progress*360;
float sub = Math.abs(newSweepangle - sweepangle);
if (progress != this.progress && sub>1) {
invalidate();
}
this.progress = progress;
}
/** * @return 当前进度 */
public double getProgress(){
return progress;
}
/** * @return 扇形弧度 */
public float getSweepangle() {
return sweepangle;
}
/** * @return 起始位置(度数) */
public float getStartPosition() {
return startPosition;
}
/** * 设置起始位置(度数) * @param startPosition */
public void setStartPosition(float startPosition) {
this.startPosition = startPosition;
}
}
思考:
异步任务下载图片
(1)使用数组准备一组网络图片链接。
(2)设置按钮监听,点击按钮时检测当前是否下载完成,完成则可以再次下载,否则无反应。使用变量控制,当异步任务开启与结束时分别标记。
(3)异步任务进行中使用get请求的方式获取网络图片的输入流以及图片大小等相关信息。使用while循环,将输入流读取到byte数组中,再将该数组写入byte数组输出流,并计算进度,发送进度信息。
(4)根据进度更新扇形进度条。
扇形进度条的使用与xml布局代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:yue="http://schemas.android.com/apk/res/com.example.sectorprogressdemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.sectorprogressdemo.MainActivity" >
<com.example.sectorprogressdemo.view.SectorProgressView
android:id="@+id/spv_test_MainActivity"
android:layout_width="200dp"
android:layout_height="200dp"
yue:shapeColor="#556699"
yue:progress = "0.3"
yue:startPosition="60"
android:layout_centerInParent="true"
/>
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:text="开始测试" />
</RelativeLayout>
其中,
xmlns:yue="http://schemas.android.com/apk/res/com.example.sectorprogressdemo"
为xml的命名空间(相当于一个标志信息,标出xml的归属)。此处必须以http://开头,apk/res/表示应用资源文件,com.example.sectorprogressdemo 是R.java的包名。
由于自定义了属性,并在java代码中通过R.styleable.xxx的形式进行了引用,因此此处的包名应当一致而不能随意更改。
如更改,则应使用其他的方式获取属性值。
java代码:
package com.example.sectorprogressdemo;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Random;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import com.example.sectorprogressdemo.view.SectorProgressView;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
private View contentView;
private SectorProgressView spv_test;
private Button btn_start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView(){
contentView = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
spv_test = (SectorProgressView) contentView.findViewById(R.id.spv_test_MainActivity);
btn_start = (Button) contentView.findViewById(R.id.btn_start);
setContentView(contentView);
btn_start.setOnClickListener(this);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
overActivity();
}
return true;
}
private void overActivity() {
Animation animation = AnimationUtils.loadAnimation(this, R.anim.activity_out);
contentView.startAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
finish();
}
});
}
private final static int LOAD_ON = 1;
private final static int LOAD_OVER = 0;
private int LOAD_FLAG = LOAD_OVER;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
doLoadImage();
break;
}
}
/** * 网络图片链接数组 */
private final static String[] imageUrl= {
"http://www.9610.com/song/baiyuchan/baiyuchan.jpg",
"http://www.9610.com/dangdai/usa/zhangchonghe0.jpg",
"http://www.9610.com/yangwz/14.jpg",
"http://www.9610.com/zhmf/guiqulaici.jpg",
"http://www.9610.com/dqc/dqch1.jpg",
"http://www.9610.com/huaisu/zixutie/5.jpg"
};
/** * 下载网络图片 */
private void doLoadImage() {
if (LOAD_FLAG == LOAD_ON) {
return;
}
contentView.setBackgroundColor(0);
LoadImageTrask loadImageTrask = new LoadImageTrask();
loadImageTrask.execute(imageUrl);
}
/** * 异步任务类 */
private class LoadImageTrask extends AsyncTask<String, Float, Bitmap>{
private int imageRandom;
@Override
protected void onPreExecute() {
// 准备
LOAD_FLAG = LOAD_ON;
Random random = new Random();
imageRandom = random.nextInt(imageUrl.length);
}
@Override
protected Bitmap doInBackground(String... imageUrl) {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(imageUrl[imageRandom]);
HttpResponse httpResponse = null;
HttpEntity httpEntity = null;
long fileSize = 0;
Bitmap bitmap = null;
try {
httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {//请求获取链接状态.获取状态码
httpEntity = httpResponse.getEntity();
fileSize = httpEntity.getContentLength();
InputStream in = httpEntity.getContent();
byte[] b = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) fileSize);
int len = 0;
int downloadSize = 0;
Log.d("测试", downloadSize+" "+fileSize);
float[] progress = new float[1];
while ((len = in.read(b)) != -1) {
downloadSize = downloadSize + len;
progress[0] = downloadSize/(float)fileSize;
bos.write(b, 0, len);
publishProgress(progress[0]);
Log.d("测试", downloadSize+" "+fileSize);
}
byte[] data = bos.toByteArray();
bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
}
}
catch (Exception e) {
}
return bitmap;
}
@Override
protected void onProgressUpdate(Float... values) {
// 进度更新
spv_test.setProgerss(values[0]);
}
@Override
protected void onPostExecute(Bitmap result) {
LOAD_FLAG = LOAD_OVER;
BitmapDrawable bitmapDrawable = new BitmapDrawable(null, result);
Drawable background = bitmapDrawable;
contentView.setBackgroundDrawable(background);
spv_test.setProgerss(0);
}
}
}
Activity疯狂旋转进入动画
activity_in.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<rotate android:fromDegrees="0" android:interpolator="@android:anim/overshoot_interpolator" android:toDegrees="3600" android:duration="2500" />
<scale android:fromXScale="0.3" android:fromYScale="0.3" android:toXScale="1" android:toYScale="0.5" android:pivotX="50%" android:pivotY="50%" android:duration="2500" />
</set>
Activity疯狂旋转退出动画
activity_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<rotate android:fromDegrees="0" android:interpolator="@android:anim/overshoot_interpolator" android:toDegrees="3600" android:duration="2500" />
<scale android:fromXScale="1" android:fromYScale="1" android:toXScale="0.3" android:toYScale="0.3" android:pivotX="50%" android:pivotY="50%" android:duration="2500" />
</set>
新建主题文件,设置Activity主题
themes.xml:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme_Yue">
<item name="android:windowAnimationStyle">@style/ActivityAnimation_Yue</item>
<item name="android:windowNoTitle">true</item>
</style>
<!-- activity动画 -->
<style name="ActivityAnimation_Yue" parent="@android:style/Animation.Activity">
<item name="android:activityOpenEnterAnimation">@anim/activity_in</item>
<item name="android:activityOpenExitAnimation">@anim/activity_out</item>
<item name="android:activityCloseEnterAnimation">@anim/activity_in</item>
<item name="android:activityCloseExitAnimation">@anim/activity_out</item>
<item name="android:taskOpenEnterAnimation">@anim/activity_in</item>
<item name="android:taskOpenExitAnimation">@anim/activity_out</item>
<item name="android:taskCloseEnterAnimation">@anim/activity_in</item>
<item name="android:taskCloseExitAnimation">@anim/activity_out</item>
<item name="android:taskToFrontEnterAnimation">@anim/activity_in</item>
<item name="android:taskToFrontExitAnimation">@anim/activity_out</item>
<item name="android:taskToBackEnterAnimation">@anim/activity_in</item>
<item name="android:taskToBackExitAnimation">@anim/activity_out</item>
<item name="android:wallpaperOpenEnterAnimation">@anim/activity_in</item>
<item name="android:wallpaperOpenExitAnimation">@anim/activity_out</item>
<item name="android:wallpaperCloseEnterAnimation">@anim/activity_in</item>
<item name="android:wallpaperCloseExitAnimation">@anim/activity_out</item>
<item name="android:wallpaperIntraOpenEnterAnimation">@anim/activity_in</item>
<item name="android:wallpaperIntraOpenExitAnimation">@anim/activity_out</item>
<item name="android:wallpaperIntraCloseEnterAnimation">@anim/activity_in</item>
<item name="android:wallpaperIntraCloseExitAnimation">@anim/activity_out</item>
</style>
</resources>
说明:
通过设置主题,改变Activity的动画样式,定义titleBar等。
以上Activity的动画不需要全部更改,其中包括进入退出,壁纸,Fragment等动画效果。
其中第一个样式即主题,名为Theme_Yue,在清单文件中@引用:
……
<style name="Theme_Yue">
<item name="android:windowAnimationStyle">@style/ActivityAnimation_Yue</item>
<item name="android:windowNoTitle">true</item>
</style>
……
name=”android:windowAnimationStyle” 表示安卓系统的动画样式,值为引用themes.xml中定义的第二个样式。
true表示没有TitleBar。
第二个stytle样式继承自android:style/Animation.Activity,即Activity的动画效果,修改它定义的值即可改变系统默认的动画效果。
最后,
Activity在清单文件 AndroidManifest.xml 中使用主题:
<activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/Theme_Yue">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
另,由于改变的动画效果很多,如果报错,需要删除不支持的动画更改。
源码链接:http://download.csdn.net/detail/mingyueyixi/9495276