Android Canvas之drawBitmap方法案例详解

前面讲了paint,后面会花几篇主要讲讲canvas,并且由于最近项目比较紧,所以近期的文章都会“短小精悍”;

paint 作为画笔,里面有非常多而强大的设置方法,比如设置颜色过滤器,设置位图渲染、渐变,设置图像的混合模式等等,而canvas呢?里面提供了哪些利器可以为我们所用,一起来看看:

     

   

通过上图我们可以看到,canvas 里的方法基本可以分为这么几类:

  1. save、restore 等与层的保存和回滚相关的方法;
  2. scale、rotate、clipXXX 等对画布进行操作的方法;
  3. drawXXX 等一系列绘画相关的方法;

所以canvas 我们也就可以分上面三块逐个击破,今天咱们主要看 drawXXX里的drawBitmap,看完之后一起做一个漂浮星空的小栗子;

在Canvas 里 drawBitmap 有如下方法可用 :

而咱们也主要讲其中的 drawBitmap(Bitmap,Rect,Rect,Paint);

首先咱们创建一个View,照旧重写里面的 onMeasure、onDraw、onSizeChanged,并且在 onSizeChanged 里拿到view的宽高:

public class DrawBitmapView extends View {
    private Resources mResources;
    private Paint mBitPaint;
    private Bitmap mBitmap;
    private Rect mSrcRect, mDestRect;  

    // view 的宽高
    private int mTotalWidth, mTotalHeight;  

    public DrawBitmapView(Context context) {
        super(context);
        mResources = getResources();
        initBitmap();
        initPaint();
    }  

    private void initPaint() {
        mBitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBitPaint.setFilterBitmap(true);
        mBitPaint.setDither(true);
    }  

    private void initBitmap() {
        mBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.<span style="font-family: Arial, Helvetica, sans-serif;">beautiful_girl</span>))
                .getBitmap();
    }  

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }  

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }  

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTotalWidth = w;
        mTotalHeight = h;
    }
}

上面我们通过

mBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.<span style="font-family: Arial, Helvetica, sans-serif;">beautiful_girl</span>))
                .getBitmap();

拿到了对应的bitmap,这时候我们如果要将它绘制在屏幕上,需要创建两个Rect,其实只要明白了这两个Rect的意义并会灵活运用就可以做出不少效果;

第一个Rect 代表要绘制的bitmap 区域,第二个 Rect 代表的是要将bitmap 绘制在屏幕的什么地方,我们一起来看下:

此时我先定义两个Rect,mSrcRect 取值为整个Bitmap 区域 ,mDestRect 取值为view左上方和bitmap同样大小;

private Rect mSrcRect, mDestRect;
mSrcRect = new Rect(0, 0, mBitWidth, mBitHeight);
mDestRect = new Rect(0, 0, mBitWidth, mBitHeight);

在onDraw 里绘制该位图:

canvas.drawBitmap(mBitmap, mSrcRect, mDestRect, mBitPaint);

此时绘制效果如下,在屏幕的左上方出现了个美女:

画在左上方似乎缺乏美感,我们把美女画在view的中心,没错,我们只需要改变mDestRect:

// 计算左边位置
int left = mHalfWidth - mBitWidth / 2;
// 计算上边位置
int top = mHalfHeight - mBitHeight / 2;
mDestRect = new Rect(left, top, left + mBitWidth, top + mBitHeight);

位置计算的时候,只需要注意在android屏幕坐标系里,左上角的位置是(0,0),往右往下为正,此时效果如下:

既然可以如此轻易的改变绘制的位置,那咱们不断的改变bitmap绘制的位置,模拟一下translate效果;

我们向外提供两个接口:

public void startTranslate() {
        startTranslate(0, 0, 200, 200, 1000);
    }

    /**
     * 移动位图
     *
     * @param startLeft 起始左边距
     * @param startTop 起始距上边距离
     * @param toLeft 到达左边距
     * @param toTop 到达上边距
     * @param duration 时长
     */
    public void startTranslate(int startLeft, int startTop, int toLeft, int toTop, long duration) {
        mStartLeft = startLeft;
        mStartTop = startTop;

        mToLeft = toLeft;
        mToTop = toTop;

        // 使用ValueAnimator创建一个过程
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new AccelerateInterpolator());
        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                // 不断重新计算上下左右位置
                float fraction = (Float) animator.getAnimatedValue();
                int currentLeft = (int) ((mToLeft - mStartLeft) * fraction + mStartLeft);
                int currentTop = (int) ((mToTop - mStartTop) * fraction + mStartTop);
                if (mDestRect == null) {
                    mDestRect = new Rect(currentLeft, currentTop, currentLeft + mBitWidth,
                            currentTop + mBitHeight);
                }
                mDestRect.left = currentLeft;
                mDestRect.right = currentLeft + mBitWidth;
                mDestRect.top = currentTop;
                mDestRect.bottom = currentTop + mBitHeight;
                // 重绘
                postInvalidate();
            }
        });
        valueAnimator.start();
    }

Activity 里控制view的移动:

final DrawBitmapView drawBitmapView = new DrawBitmapView(this);
        setContentView(drawBitmapView, new LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT));
        drawBitmapView.startTranslate();
        drawBitmapView.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Random random = new Random();
                int startLeft = random.nextInt(200);
                int startTop = random.nextInt(250);
                int toLeft = random.nextInt(550) + 200;
                int toBottom = random.nextInt(1000) + 250;
                drawBitmapView.startTranslate(startLeft, startTop, toLeft, toBottom, 1000);
                return true;
            }
        });

    }

点击之后起始点和到达点随机生成,此时效果如下:

相信到这里大家已经能灵活控制bitmap的位置了,顺势咱们再做个水平缩放为0的小例子:

public void startScale(long duration) {

        // 使用ValueAnimator创建一个过程
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0);
        valueAnimator.setDuration(duration);
        valueAnimator.setInterpolator(new AccelerateInterpolator());
        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                // 不断重新计算上下左右位置
                float fraction = (Float) animator.getAnimatedValue();
                if (mDestRect == null) {
                    mDestRect = new Rect(0, 0, mBitWidth,
                            mBitHeight);
                }
                mDestRect.right = (int) (fraction * mBitWidth);
                // 重绘
                postInvalidate();
            }
        });
        valueAnimator.start();
    }

只需要不断减小mDestRect.right即可,非常简单,看下效果:

      上面两个例子都是通过改变mDestRect ,在哪些时候我们需要动态改变mSrcRect 呢?我前面讲过一个水波纹的例子,那里面就是不断截取水波纹的一部分,进行展示,由于是连续截取,所以视觉感受上是连续波纹效果,有兴趣的同学可以看看参考下; 

    好了本篇就讲这么多,有些同学可能会想,尼玛,这么简单的玩意儿能做毛线牛逼动效啊,其实往往再复杂的动效也就是由一个个小点组成的,而思路和方案的选取就已经决定了能否成功的做出酷炫又如丝般顺滑的效果,好的思路又往往来源于对简单方法的深刻理解

到此这篇关于Android Canvas之drawBitmap方法案例详解的文章就介绍到这了,更多相关Android Canvas之drawBitmap方法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android使用Canvas对象实现刮刮乐效果

    在淘宝.京东等电商举办活动的时候,经常可以看到在移动客户端推出的各种刮奖活动,而这种活动也受到了很多人的喜爱.从客户端的体验来说,这种效果应该是通过网页来实现的,那么,我们使用Android的自带控件能不能实现这种刮刮乐的效果呢?当然可以,本篇文章将介绍使用Canvas这个对象,如何实现"刮刮乐"的效果. 先看效果图 下面我们看一下如何使用代码实现 布局文件 <FrameLayout xmlns:android="http://schemas.android.com/a

  • android canvas使用line画半圆

    本文实例为大家分享了android canvas使用line画半圆具体代码,供大家参考,具体内容如下 LineView.java public class LineView extends View { private int progress = 0; private int max = 100; private int roundWidth = 50; public LineView(Context context) { super(context); } public LineView(C

  • Android 使用Canvas在图片上绘制文字的方法

    [Android]Android中 Paint 字体.粗细等属性的一些设置 在Android SDK中使用Typeface类来定义字体,可以通过常用字体类型名称进行设置,如设置默认黑体: Paint mp = new paint(); mp.setTypeface(Typeface.DEFAULT_BOLD) 常用的字体类型名称还有: * Typeface.DEFAULT //常规字体类型 * Typeface.DEFAULT_BOLD //黑体字体类型 * Typeface.MONOSPACE

  • Android编程实现canvas绘制饼状统计图功能示例【自动适应条目数量与大小】

    本文实例讲述了Android编程实现canvas绘制饼状统计图功能.分享给大家供大家参考,具体如下: 本例的目的是实现一个简单的饼状统计图,效果如下:    特点: 1.使用非常方便,可放在xml布局文件中,然后在代码中设置内容,即: PieChartView pieChartView = (PieChartView) findViewById(R.id.pie_chart); PieChartView.PieItemBean[] items = new PieChartView.PieItem

  • Android自定义View中Paint、Rect、Canvas介绍(一)

    自定义View对于新手而言貌似是一个很复杂的东西.格式,各函数的意义.对于大神经常忘记各函数及一些参数的具体写法及意义,刚好在做一个风车效果,把过程及遇到的问题都写下来 1.如何自定义一个View public class LeafView extends View { private String TAG = "--------LeafView"; public LeafView(Context context, AttributeSet attrs) { super(context

  • Android画图之抗锯齿paint和Canvas两种方式实例

    在画图的时候,图片如果旋转或缩放之后,总是会出现那些华丽的锯齿.其实Android自带了解决方式. 方法一:给Paint加上抗锯齿标志.然后将Paint对象作为参数传给canvas的绘制方法. paint.setAntiAlias(true); 方法二:给Canvas加上抗锯齿标志. 有些地方不能用paint的,就直接给canvas加抗锯齿,更方便. 复制代码 代码如下: canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_AL

  • Android中Paint类和Canvas类的方法汇总

    Paint类的常用的方法 1.setColor方法,用于设置画笔的颜色, public void setColor(int color)//参数color为颜色值,也可以使用Color类定义的颜色 Color.BLACK:黑色 Color.BLUE:蓝色 Color.CYAN:青绿色 Color.DKGRAY:灰黑色 Color.YELLOW:黄色 Color.GRAY:灰色 Color.GREEN:绿色 Color.LTGRAY:浅绿色 Color.MAGENTA:红紫色 Color.TRAN

  • Android Canvas之drawBitmap方法案例详解

    前面讲了paint,后面会花几篇主要讲讲canvas,并且由于最近项目比较紧,所以近期的文章都会"短小精悍": paint 作为画笔,里面有非常多而强大的设置方法,比如设置颜色过滤器,设置位图渲染.渐变,设置图像的混合模式等等,而canvas呢?里面提供了哪些利器可以为我们所用,一起来看看:           通过上图我们可以看到,canvas 里的方法基本可以分为这么几类: save.restore 等与层的保存和回滚相关的方法: scale.rotate.clipXXX 等对画布

  • Android ExpandableListView使用方法案例详解

    目录 一.前言 二.实现的功能 三.具体代码 1.主xml代码 2.父布局xml代码 3.子布局xml代码 4.主activity代码 5.adapter代码 一.前言   "好记性不如烂笔头",再次验证了这句话是真的很有道理啊,一个月前看了一下ExpandableListView的使用,今天再看居然忘了这个是干啥的了,今天就详细讲解一下ExpandableListView的使用方法,感觉对于二级条目显示功能都可以实现. 二.实现的功能 1.可实现二级列表条目显示功能,具体包括可自定义

  • Android Canvas和Bitmap结合绘图详解流程

    目录 Rect/RectF Matrix Canvas Bitmap Rect/RectF 存储四个值的矩形类:左侧.顶部.右侧和底部.可用于直接在画布上绘制或仅用于存储要绘制的对象的大小.Rect和RectF类之间的区别在于 RectF 存储浮点值,而Rect类存储整数. private static Bitmap createDrawableBitmap(Drawable drawable) { int width = drawable.getIntrinsicWidth(); int he

  • Android 使用registerReceiver注册BroadcastReceiver案例详解

    android.context.ContextWrapper.registerReceiver public Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter) Register a BroadcastReceiver to be run in the main activity thread. The receiver will be called with any broadcast Intent

  • Android AlertDialog六种创建方式案例详解

    目录 一.setMessage:设置对话框内容为简单文本内容 二.setItem:设置文本框内容为简单列表项 三.setSingleChoiceItems()设置对话框内容为单选列表项 四.setMultiChoiceItems()设置对话框内容为多选项列表 五.setAdapter()设置对话框内容为自定义列表项(这里是一个布局) 六.setView()设置对话框为自定义View 创建AlertDialog的步骤: 创建AlertDialog.Builder对象 调用Builder对象的set

  • Android AlertDialog多种创建方式案例详解

    目录 一.setMessage:设置对话框内容为简单文本内容 二.setItem:设置文本框内容为简单列表项 三.setSingleChoiceItems()设置对话框内容为单选列表项 四.setMultiChoiceItems()设置对话框内容为多选项列表 五.setAdapter()设置对话框内容为自定义列表项(这里是一个布局) 六.setView()设置对话框为自定义View 创建AlertDialog的步骤: 创建AlertDialog.Builder对象 调用Builder对象的set

  • Android Location服务之LocationManager案例详解

    上次介绍了位置服务中的Geocoder,这次就来介绍一下LocationManager.LocationManager系统服务是位置服务的核心组件,它提供了一系列方法来处理与位置相关的问题,包括查询上一个已知位置.注册和注销来自某个LocationProvider的周期性的位置更新.注册和注销接近某个坐标时对一个已定义的Intent的触发等.今天我们就一起探讨一下LocationManager的简单应用. 在进入正题之前,朋友们需要了解与LocationManager相关的两个知识点: prov

  • Android mvvm之LiveData原理案例详解

    1. 生命周期感知 1.1 生命周期感知组件 我们知道,Controller(Activity or Fragment) 都是有生命周期的,但是传统的 Controller 实现方式只负责 Controller 本身的生命周期管理,而与业务层的数据之间并没有实现良好解耦的生命周期事件交换.所以业务层都需要自己主动去感知 Controller 生命周期的变化,并在 Controller 的生存期处理数据的保活,而在消亡时刻解除与 Controller 之间的关系,这种处理方式随着业务规模的扩大往往

  • Android Flutter自适应瀑布流案例详解

    目录 Flutter自适应瀑布流 根据效果图可以分为四步: 1.图片自适应: 2.自适应标签: 3.上拉刷新和下拉加载 4.底部的点赞按钮 Flutter自适应瀑布流 前言:在电商app经常会看到首页商品推荐的瀑布流,或者类似短视频app首页也是瀑布流,这些都是需要自适应的,才能给用户带来好的体验 (具体代码请联系我,当天会回复) 话不多说先上效果图: 根据效果图可以分为四步: 图片自适应 自适应标签 上拉刷新和下拉加载 底部的点赞按钮可以去掉或者自己修改样式,我这里使用的like_button

  • Android registerForActivityResult动态申请权限案例详解

    前言 这几天在做一个小工具app,结果在fragment里面动态申请权限提示原有的申请方法已经弃用,还画了很明显的删除线...这叫一个强迫症的我怎么受得了.赶紧网上找资料也找不出什么结果,看了官方文档才发现了有registerForActivityResult这么一个神奇好用的函数,可以代替我们现有的startActivityForResult和权限申请函数. 那么下面就分两种情况来讲一下如何使用这个函数动态申请权限. 一.申请单个权限 首先,我们需要定义一个launcher: Activity

随机推荐