Android进阶练习-自定义视图实战之刷新等待进度条

     
    实现一个最简单的自定义视图(不包含处理用户的触摸事件),往往只需要三步

      一、继承自一个View(可以是一个更具体的Android已实现好的View),并增加必须的构造方法(这个根据自定义View怎么使用来判断)

     二、覆写onDraw(Canvas canvas)方法,并且自定义绘制

     三、重绘,分为实时重绘和属性更新重绘


     自定义视图如果是继承自原始View的话, public View(android.content.Context context)这个构造方法是必须的。而
public View(android.content.Context context, android.util.AttributeSet attrs)这个构造方法是可选,但如果你想在xml布局文件中使用自定义视图的话,带属性的构造函数也是必须的,因为Android系统是根据这个构造函数去实例化视图的,这样也可以让我们的视图可视化,配置的属性值也能够根据它来获得

     关于自定义绘制,需要注意的是Android框架已经为我们提供了很多的方法来绘制各种图元,直接使用就行了,要记住的是自定义视图并不会自己主动的去重绘自己,首次显示会绘制一次,往往需要我们去通知它进行重绘,可以在视图上调用invalidate()和postInvalidate()来通知重绘,两者的区别稍后会进行解释

     重绘,有些视图往往需要实时的进行重绘,像一些实时性很强的游戏,但这个一般需要使用到SurfaceView,有兴趣的话可以去学习下,我们今天的例子也需要进行实时重绘,但没有使用到SurfaceView,而是继承于View。有的时候可能并不需要实时进行重绘,像只有在改变了视图的一个属性值的情况下才需要重新绘制,这个时候我们可以在setXX()方法中调用invalidate()方法就行

下面是一个等待进度条的例子
package tu.bingbing.customdialogview.view;

import tu.bingbing.customdialogview.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class CustomDialogView extends View {

        // 加载图片资源id,存入缓存数组
        private final int[] ids = new int[] { R.drawable. loading01,
                    R.drawable. loading02, R.drawable.loading03, R.drawable.loading04 ,
                    R.drawable. loading05, R.drawable.loading06, R.drawable.loading07 ,
                    R.drawable. loading08, R.drawable.loading09, R.drawable.loading10 ,
                    R.drawable. loading11 };

        private Bitmap[] loadingImgs ;

        private Paint loadingImagePaint ;

        private int currentIdsIndex = 0;

        public CustomDialogView(Context context, AttributeSet attrs) {
              super(context, attrs);
             init();
       }

        public CustomDialogView(Context context) {
              super(context);
             init();
       }

        private void init() {
             
              // 实例化画笔
              loadingImagePaint = new Paint();
              // 设置抗锯齿
              loadingImagePaint.setAntiAlias(true);

              // 一次性放进缓存数组中
              loadingImgs = new Bitmap[] {
                           BitmapFactory. decodeResource(getResources(), ids[0]),
                           BitmapFactory. decodeResource(getResources(), ids[1]),
                           BitmapFactory. decodeResource(getResources(), ids[2]),
                           BitmapFactory. decodeResource(getResources(), ids[3]),
                           BitmapFactory. decodeResource(getResources(), ids[4]),
                           BitmapFactory. decodeResource(getResources(), ids[5]),
                           BitmapFactory. decodeResource(getResources(), ids[6]),
                           BitmapFactory. decodeResource(getResources(), ids[7]),
                           BitmapFactory. decodeResource(getResources(), ids[8]),
                           BitmapFactory. decodeResource(getResources(), ids[9]),
                           BitmapFactory. decodeResource(getResources(), ids[10]) };
       }

        @Override
        protected void onDraw(Canvas canvas) {

              // 循环控制每一张图片的绘制顺序,让看起来像是播放动画
              if (currentIdsIndex >= (ids .length - 1)) {
                     currentIdsIndex = 0;
             }

             Bitmap currentLoadingBitmap = loadingImgs[currentIdsIndex ];
              // 绘制图片,显示在屏幕正中
             canvas.drawBitmap(currentLoadingBitmap, (getWidth() - currentLoadingBitmap.getWidth())/2,
                           (getHeight() - currentLoadingBitmap.getHeight())/2, loadingImagePaint );

              currentIdsIndex++;

              super.onDraw(canvas);
       }

}

     在View上getWidth()和getHeight()方法取到的是屏幕的高和宽, BitmapFactory .decodeResource( Resources  res, int id)方法根据资源id得到一张位图用于显示,关于是否应该把所有的图片一次性的加载入内存,这个可以根据需要来定,你可以一次性全部加载,可以得到更流畅的UI,但更耗损内存;你也可以到在要用到的时候再加载,这样可能会有一定的延迟,但可以有效的节省内存;也可以使用软引用来保存图片,这样可以使得在程序内存不足时,图片内存得以回收,两全其美。

在Activity中实时重绘视图
package tu.bingbing.customdialogview;

import tu.bingbing.customdialogview.view.CustomDialogView;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

        private CustomDialogView customDialogView ;
        private RedrawCustomDialogViewThread redrawCdvRunnable ;
       
        @Override
        protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
             
             setContentView(R.layout. activity_main);
             
              customDialogView = (CustomDialogView) findViewById(R.id.view_customdialog );
              redrawCdvRunnable = new RedrawCustomDialogViewThread();
              new Thread(redrawCdvRunnable ).start();
       }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
              // Inflate the menu; this adds items to the action bar if it is present.
             getMenuInflater().inflate(R.menu. main, menu);
              return true ;
       }
       
        final class RedrawCustomDialogViewThread implements Runnable{

              private boolean isRun = true;
             
              @Override
              public void run() {

                     while(isRun ){
                            try {
                                 Thread. sleep(100);
                           } catch (InterruptedException e) {
                                 e.printStackTrace();
                           }
                            // 通知重绘
                            customDialogView.postInvalidate();
                    }
                    
             }

              public boolean isRun() {
                     return isRun ;
             }

              public void setRun(boolean isRun) {
                     this.isRun = isRun;
             }
             
             
       }

        @Override
        protected void onDestroy() {
             
              redrawCdvRunnable.setRun(false );
             
              super.onDestroy();
       }
}

布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    
    <tu.bingbing.customdialogview.view.CustomDialogView 
        android:id="@+id/view_customdialog"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
	    
</RelativeLayout>

     除了使用postInvalidate()方法外,还可以使用invalidate()方法,前者让程序可以在UI主线程外的线程中去通知视图进行重绘,后者必须在UI主线程中进行调用通知,一般可以和Handler一起使用

使用到的图片资源



程序运行效果









  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值