Android實現(xiàn)電子書放大鏡效果
前言
最近看電子書發(fā)現(xiàn)了一個挺有意思的效果,類似于一個放大鏡,因此就花了點時間實現(xiàn)了一個放大鏡效果的自定義View,電子書里面的效果,如圖所示:

效果展示
我寫的效果如下:

實現(xiàn)原理

控件的代碼如下,所有的步驟都加入了注釋,可以直接參考注釋
public class MagnifierLayout extends FrameLayout {private Bitmap mBitmap;private Paint mPaintShadow,mPaintBitmap;private long mShowTime = 0;//用于判斷顯示放大鏡的時間private boolean mIsShowMagnifier = false;//是否顯示放大鏡private Path mPath;//用于裁剪畫布的路徑private float mShowMagnifierX = 0;//顯示放大鏡的X坐標(biāo)private float mShowMagnifierY = 0;//顯示放大鏡的Y坐標(biāo)private float mMagnifierRadius = 200;//放大鏡的半徑private float mScaleRate = 3f;//放大比例private Handler mHandler = new Handler();private Runnable mRunnable = new Runnable() {@Overridepublic void run() {mIsShowMagnifier = true;postInvalidate();}};public MagnifierLayout(@NonNull Context context) {this(context,null);}public MagnifierLayout(@NonNull Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public MagnifierLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init(){//繪制放大鏡邊緣投影的畫筆mPaintShadow = new Paint(Paint.ANTI_ALIAS_FLAG);//設(shè)置放大鏡邊緣的投影mPaintShadow.setShadowLayer(20,6,6, Color.BLACK);//繪制Bitmap的畫筆mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG);mPath = new Path();setLayerType(View.LAYER_TYPE_SOFTWARE, null);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:mShowTime = System.currentTimeMillis();mShowMagnifierX = event.getX() + mMagnifierRadius;mShowMagnifierY = event.getY() - mMagnifierRadius;//如果持續(xù)按超過一秒就顯示放大鏡startShowMagnifierDelay();break;case MotionEvent.ACTION_MOVE://觸摸時間大于1秒才顯示if(System.currentTimeMillis() - mShowTime >= 1000){stopShowMagnifier();mIsShowMagnifier = true;mShowMagnifierX = event.getX() + mMagnifierRadius;mShowMagnifierY = event.getY() - mMagnifierRadius;//重繪postInvalidate();}break;case MotionEvent.ACTION_UP:stopShowMagnifier();mIsShowMagnifier = false;postInvalidate();break;}return true;}private void startShowMagnifierDelay() {stopShowMagnifier();mHandler.postDelayed(mRunnable,1000);}private void stopShowMagnifier() {mHandler.removeCallbacks(mRunnable);}@Overrideprotected void dispatchDraw(Canvas canvas) {if(mIsShowMagnifier){//創(chuàng)建整個布局內(nèi)容的BitmapmBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);Canvas mCanvas = new Canvas(mBitmap);//將當(dāng)前布局的內(nèi)容繪制在Bitmap上super.dispatchDraw(mCanvas);//將Bitmap繪制出來(否則頁面是空白,因為上面是用我們自定義的Canvas進(jìn)行繪制的,因此我們還需要用系統(tǒng)的這個進(jìn)行繪制一遍)canvas.drawBitmap(mBitmap,0,0,mPaintBitmap);//繪制出放大鏡邊緣的投影canvas.drawCircle(mShowMagnifierX,mShowMagnifierY,mMagnifierRadius,mPaintShadow);canvas.save();//計算出要裁剪畫布的圓形路徑mPath.reset();mPath.addCircle(mShowMagnifierX,mShowMagnifierY,mMagnifierRadius, Path.Direction.CW);//將圓形路徑的畫布裁剪出來,這樣繪制的Bitmap就是圓形的canvas.clipPath(mPath);//繪制當(dāng)前布局的背景顏色,否則放大鏡顯示的背景會是黑色getBackground().draw(canvas);//根據(jù)縮放的比例計算出裁剪的Bitmap的最小寬高float magnifierWidthAndHeight = mMagnifierRadius * 2 / mScaleRate;//計算出該裁剪的區(qū)域(就是使手指所在的點在要裁剪的Bitmap的中央),并進(jìn)行邊界值處理(開始裁剪的X點不能小于0和大于Bitmap的寬度,并且X點的位置加上要裁剪的寬度不能大于Bitmap的寬度,Y點也是一樣)int cutX = Math.max((int) (mShowMagnifierX - mMagnifierRadius - magnifierWidthAndHeight / 2), 0);int cutY = Math.min(Math.max((int) (mShowMagnifierY + mMagnifierRadius - magnifierWidthAndHeight / 2),0), mBitmap.getHeight());//適配邊界值int cutWidth = magnifierWidthAndHeight + cutX > mBitmap.getWidth() ? mBitmap.getWidth() - cutX : (int)magnifierWidthAndHeight;int cutHeight = magnifierWidthAndHeight + cutY > mBitmap.getHeight() ? mBitmap.getHeight() - cutY : (int)magnifierWidthAndHeight;mBitmap = Bitmap.createBitmap(mBitmap,cutX,cutY,cutWidth,cutHeight);//將裁剪出來的區(qū)域放大mBitmap = Bitmap.createScaledBitmap(mBitmap,(int) (mBitmap.getWidth() * mScaleRate),(int)(mBitmap.getHeight() * mScaleRate),true);//繪制放大后的Bitmap,由于Bitmap的縮放是從左上點開始的因此還要根據(jù)縮放的比例進(jìn)行相應(yīng)的偏移展示canvas.drawBitmap(mBitmap,mShowMagnifierX - mMagnifierRadius ,mShowMagnifierY - mMagnifierRadius,mPaintBitmap);canvas.restore();mBitmap.recycle();mBitmap = null;}else {super.dispatchDraw(canvas);}}}
源碼地址:
https://gitee.com/itfitness/magnifier-layout
到這里就結(jié)束啦。
評論
圖片
表情
