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

效果预览:

这里写图片描述这里写图片描述

正文

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
自定义半圆形进度条,我们可以通过继承ProgressBar类,并重写其中的一些方法来实现。 首先,我们需要创建一个自定义的ProgressBar类,并在构造方法中定义一些必要的属性,如进度条的颜色、进度值等。然后,我们可以通过重写onMeasure方法来测量进度条的大小,保证其为一个半圆形。接着,我们需要重写onDraw方法来绘制进度条的样式。在这个方法中,我们可以利用Canvas和Paint来绘制一个半圆形的背景,并使用同样的方式绘制进度条的进度部分。 在绘制进度条的进度部分时,我们需要根据当前的进度值来确定进度的角度,并使用Path类的arcTo方法来绘制一个与进度值对应的扇形。同时,我们还可以调用Paint的setShader方法来设置进度条的渐变效果,使得进度从一种颜色平滑过渡到另一种颜色。 除了绘制进度条的样式外,我们还可以根据需要为进度条添加一些动画效果。例如,我们可以使用ValueAnimator类来实现进度的平滑过渡,通过不断改变进度值并调用invalidate方法来触发重绘,从而实现进度条的动态效果。 最后,我们还可以根据需要为自定义的半圆形进度条添加一些其他功能,如进度文字显示、进度监听等。这些功能的实现方式与一般的ProgressBar类似,只需在自定义类中添加相应的方法即可。 通过以上的步骤,我们可以实现一个自定义的半圆形进度条,满足我们对进度条样式和功能的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值