小动画之图片放大镜(ShapeDrawable)

使用 ShapeDrawable 实现小动画之图片🔍

在这里插入图片描述

常用函数

  1. setBounds():用来指定当前ShapeDrawable 在当前控件中的显示位置。
  2. getPaint();
  3. Paint.setShader():Shader 是从S h apeDrawab l e 所在区域的左上角开始绘制的。

代码实现

  1. 自定义 View

    public class MyTelescopeView extends View {
    
        private Bitmap mBitmap;
        private ShapeDrawable mShapeDrawable;
        private  int radius = 320;
        private  int factor = 3;
        private Matrix mMatrix = new Matrix();
        private Bitmap mDecodeResource;
    
        public MyTelescopeView(Context context) {
            super(context);
            init();
        }
    
        public MyTelescopeView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public MyTelescopeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {setLayerType(LAYER_TYPE_SOFTWARE, null);}
    
        /**
         * 通过 activity 向 自定义 View 传递参数;
         * @param radius   监听 SeekBar 的半径
         * @param factor    监听 SeekBar 的放大倍率
         * @param isFlush   是否需要刷新页面?只有 放大倍数发生改变才刷新页面(刷新放大镜),
         */
        public void setParameter(int radius, int factor,boolean isFlush) {
            this.radius = radius;
            this.factor = factor;
            //解决,更新放大倍率、放大镜半径后,镜子位置岔劈的问题;
            if (isFlush)mBitmap = null;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    final int x = (int) event.getX();
                    final int y = (int) event.getY();
    
                    //表示的是绘制 Shader 的起始位置
                    mMatrix.setTranslate(radius - factor * x, radius - factor * y);
                    mShapeDrawable.getPaint().getShader().setLocalMatrix(mMatrix);
    
                    // bounds,圆的外切矩形
                    mShapeDrawable.setBounds(x - radius, y - radius, x + radius, y + radius);
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    mShapeDrawable.setBounds(-10, -10, 0, 0);
                    invalidate();
                    break;
                default:
                    break;
            }
            return true;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (mBitmap == null) {
                mDecodeResource = BitmapFactory.decodeResource(getResources(), R.drawable.advance_woods_path);
                mBitmap = Bitmap.createScaledBitmap(mDecodeResource, getWidth(), getHeight(), false);
    
                BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(mBitmap,
                        mBitmap.getWidth() * factor, mBitmap.getHeight() * factor, true),
                        Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                mShapeDrawable = new ShapeDrawable(new OvalShape());
                mShapeDrawable.getPaint().setShader(shader);
            }
            canvas.drawBitmap(mBitmap, 0, 0, null);
            mShapeDrawable.draw(canvas);
        }
    }
    
  2. MainActivity.java

    public class TelescopeActivity extends AppCompatActivity {
    
        private TextView tv_telescope_factor, tv_telescope_radius;
        private SeekBar sb_telescope_factor, sb_telescope_radius;
        private MyTelescopeView telescope_view;
    
        public int telescope_factor = 3;
        public int telescope_radius = 320;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_telescope);
            initView();
        }
    
        private void initView() {
            ……
            sb_telescope_factor.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    telescope_factor = progress;
                    tv_telescope_factor.setText(String.valueOf(progress));
                    sb_telescope_factor.setProgress(progress);
                    telescope_view.setParameter(telescope_radius, telescope_factor,true);
                }
    
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) { }
    
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {	}
            });
    
            sb_telescope_radius.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    telescope_radius = progress;
                    tv_telescope_radius.setText(String.valueOf(progress));
                    sb_telescope_radius.setProgress(progress);
                    telescope_view.setParameter(telescope_radius, telescope_factor,false);
                }
    
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {	}
    
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) { }
            });
        }
    }
    

注意

  1. 初始化在 onDraw() 方法中;通过 Bitmap.createScaledBitmap 方法根据源图像生成一个指定宽度和高度的 Bitmap;将源图像缩放到当前控件大小。
  2. 上述代码中表示的是绘制 Shader 的起始位置
    mMatrix.setTranslate(radius - factor * x, radius - factor * y);
    mShapeDrawable.getPaint().getShader().setLocalMatrix(mMatrix);
    
  3. 关于项目存在一个 BUG,我调了一天……感兴趣的小伙伴,可以看这里:一个BUG调一天之图片放大镜

Activity 向自定义 View 传递参数

  1. View 中定义 set 方法;
  2. 在 Activity 中实例化 View 调用其 set 方法;

声明:本文整理自《启舰_自定义控件》,如有侵权请联系我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liusaisaiV1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值
>