自定义扇形进度条、异步加载网络图片、Activity疯狂旋转动画

效果预览:

自定义扇形进度条、异步加载网络图片、Activity疯狂旋转动画_第1张图片自定义扇形进度条、异步加载网络图片、Activity疯狂旋转动画_第2张图片

正文

1、自定义扇形进度条。

思考:
(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;
    }
}

2、扇形进度条的使用与异步任务加载网络图片

思考:
异步任务下载图片
(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);
        }

    }

}

3、通过自定义主题设置Activity进入与退出动画

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

你可能感兴趣的:(动画,android,网络,图片,异步)