为 android 上的自定义动态视图实施 magnifier/loupe
Implementing magnifier/loupe for custom dynamic view on android
我正在寻找一种方法来实现 Magnifier/Loupe 用于动态重建 android 上的自定义视图。
我做这个class只是为了回答你的问题。这是放大镜最基本的实现,希望对你有所帮助。祝你好运:
public class ExampleMagnifierView extends View {
Matrix matrix = new Matrix();
Paint shaderPaint = new Paint();
BitmapShader shader = null;
//start the magnifier
boolean zooming;
//capture a new bitmap form a view
boolean isFirstTouch = true;
//magnifier position
static final PointF zoomPos = new PointF(0, 0);
private float magnifierSize = 75;
private Context context = null;
private Bitmap someBitmap = null;
ArrayList<Element> elements = new ArrayList<Element>();
public ExampleMagnifierView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
//Just for the example
someBitmap = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_delete);
//Just for the example
elements = prepareElementsMatrix(5, 6);
}
@Override
protected void onDraw(Canvas canvas) {
drawSomethingToBeMagnifiedNoMatterWhat(canvas);
if (zooming) {
matrix.reset();
matrix.postScale(2f, 2f, zoomPos.x, zoomPos.y);
shaderPaint.getShader().setLocalMatrix(matrix);
canvas.drawCircle(zoomPos.x, zoomPos.y, convertDpToPixel(magnifierSize, this.getContext()), shaderPaint);
}
}
private void drawSomethingToBeMagnifiedNoMatterWhat(Canvas canvas){
for (Element el : elements){
canvas.drawBitmap(someBitmap, el.x , el.y , null);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isFirstTouch) {
//we set the zooming to false because we want a image of the view without magnifier
zooming = false;
shader = null;
shaderPaint = null;
shaderPaint = new Paint();
//get a fresh bitmap from the view
shader = new BitmapShader(getBitmapFromView(this), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
isFirstTouch = false;
}
shaderPaint.setShader(shader);
matrix.reset();
matrix.postTranslate(-zoomPos.x, -zoomPos.y - convertDpToPixel(magnifierSize, context));
shader.setLocalMatrix(matrix);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
zoomPos.x = event.getX();
zoomPos.y = event.getY() - convertDpToPixel(magnifierSize, context);
//this flag starts drawing the magnifier
zooming = true;
invalidate();
isFirstTouch = true;
break;
case MotionEvent.ACTION_MOVE:
zoomPos.x = event.getX();
zoomPos.y = event.getY() - convertDpToPixel(magnifierSize, context);
//this flag starts drawing the magnifier
zooming = true;
invalidate();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isFirstTouch = true;
zooming = false;
invalidate();
break;
}
return true;
}
/**
* This method get the bitmap form a view.
*
* @param view The view who we want as a bitmap
* @return The view's bitmap
*/
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view ( Use RGB_565 for better performance )
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null) {
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
} else {
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
}
// draw the view on the canvas
view.draw(canvas);
//erase the drawable
bgDrawable = null;
//return the bitmap
return returnedBitmap;
}
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @param context Context to get resources and device specific display metrics
* @return A float value to represent px equivalent to dp depending on device density
*/
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return px;
}
private ArrayList<Element> prepareElementsMatrix(int rows, int columns){
ArrayList<Element> elementsMatrix = new ArrayList<Element>();
int offsetX = 0;
int offsetY = 0;
for (int i = 0; i<=columns; i++){
offsetX += someBitmap.getWidth() + 5;
elementsMatrix.add(new Element(offsetX, offsetY));
for (int j = 0; j<=rows; j++){
elementsMatrix.add(new Element(offsetX, offsetY));
offsetY += someBitmap.getHeight() + 5;
}
offsetY = 0;
}
return elementsMatrix;
}
private class Element{
int x;
int y;
public Element(int x, int y){
this.x = x;
this.y = y;
}
}
我自己弄明白了。
所以这是动态变化视图的变体。
1) 首先我们在重写绘制方法时创建具有相同高度和宽度的新位图(整个);
2) 从我们的位图(整个)
创建 Canvas(temporalCanvas)
3) 在 canvas(temporalCanvas)
上绘制我们需要的一切
4) 绘制位图到onDraw中给出的原始canvas(canvas)收入
5) 从 MotionEvent 获取坐标(它应该在 ACTION_DOWN 上设为全局静态)所以这将是无效和绘制视图后的 SAME MotionEvent
6) 围绕所选(MotionEvent.GetX/Y) 位置剪切位图
7) 在原件上绘制修剪后的位图 (canvas) canvas
可能遇到的困难:
-Motion 事件 returns 不同的坐标 X,Y 当它被覆盖的 onTouchEvent 或从 ACTION_DOWN 上发生的静态事件调用时; (只需将 x、y 坐标设为静态)并且不要忘记删除静态触摸事件,以及动作 UP
上的 x、y 坐标
-2应该用canvas或者你可以放大镜放大镜)
我正在寻找一种方法来实现 Magnifier/Loupe 用于动态重建 android 上的自定义视图。
我做这个class只是为了回答你的问题。这是放大镜最基本的实现,希望对你有所帮助。祝你好运:
public class ExampleMagnifierView extends View {
Matrix matrix = new Matrix();
Paint shaderPaint = new Paint();
BitmapShader shader = null;
//start the magnifier
boolean zooming;
//capture a new bitmap form a view
boolean isFirstTouch = true;
//magnifier position
static final PointF zoomPos = new PointF(0, 0);
private float magnifierSize = 75;
private Context context = null;
private Bitmap someBitmap = null;
ArrayList<Element> elements = new ArrayList<Element>();
public ExampleMagnifierView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
//Just for the example
someBitmap = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_delete);
//Just for the example
elements = prepareElementsMatrix(5, 6);
}
@Override
protected void onDraw(Canvas canvas) {
drawSomethingToBeMagnifiedNoMatterWhat(canvas);
if (zooming) {
matrix.reset();
matrix.postScale(2f, 2f, zoomPos.x, zoomPos.y);
shaderPaint.getShader().setLocalMatrix(matrix);
canvas.drawCircle(zoomPos.x, zoomPos.y, convertDpToPixel(magnifierSize, this.getContext()), shaderPaint);
}
}
private void drawSomethingToBeMagnifiedNoMatterWhat(Canvas canvas){
for (Element el : elements){
canvas.drawBitmap(someBitmap, el.x , el.y , null);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isFirstTouch) {
//we set the zooming to false because we want a image of the view without magnifier
zooming = false;
shader = null;
shaderPaint = null;
shaderPaint = new Paint();
//get a fresh bitmap from the view
shader = new BitmapShader(getBitmapFromView(this), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
isFirstTouch = false;
}
shaderPaint.setShader(shader);
matrix.reset();
matrix.postTranslate(-zoomPos.x, -zoomPos.y - convertDpToPixel(magnifierSize, context));
shader.setLocalMatrix(matrix);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
zoomPos.x = event.getX();
zoomPos.y = event.getY() - convertDpToPixel(magnifierSize, context);
//this flag starts drawing the magnifier
zooming = true;
invalidate();
isFirstTouch = true;
break;
case MotionEvent.ACTION_MOVE:
zoomPos.x = event.getX();
zoomPos.y = event.getY() - convertDpToPixel(magnifierSize, context);
//this flag starts drawing the magnifier
zooming = true;
invalidate();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isFirstTouch = true;
zooming = false;
invalidate();
break;
}
return true;
}
/**
* This method get the bitmap form a view.
*
* @param view The view who we want as a bitmap
* @return The view's bitmap
*/
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view ( Use RGB_565 for better performance )
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null) {
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
} else {
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
}
// draw the view on the canvas
view.draw(canvas);
//erase the drawable
bgDrawable = null;
//return the bitmap
return returnedBitmap;
}
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @param context Context to get resources and device specific display metrics
* @return A float value to represent px equivalent to dp depending on device density
*/
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return px;
}
private ArrayList<Element> prepareElementsMatrix(int rows, int columns){
ArrayList<Element> elementsMatrix = new ArrayList<Element>();
int offsetX = 0;
int offsetY = 0;
for (int i = 0; i<=columns; i++){
offsetX += someBitmap.getWidth() + 5;
elementsMatrix.add(new Element(offsetX, offsetY));
for (int j = 0; j<=rows; j++){
elementsMatrix.add(new Element(offsetX, offsetY));
offsetY += someBitmap.getHeight() + 5;
}
offsetY = 0;
}
return elementsMatrix;
}
private class Element{
int x;
int y;
public Element(int x, int y){
this.x = x;
this.y = y;
}
}
我自己弄明白了。 所以这是动态变化视图的变体。
1) 首先我们在重写绘制方法时创建具有相同高度和宽度的新位图(整个);
2) 从我们的位图(整个)
创建 Canvas(temporalCanvas)3) 在 canvas(temporalCanvas)
上绘制我们需要的一切4) 绘制位图到onDraw中给出的原始canvas(canvas)收入
5) 从 MotionEvent 获取坐标(它应该在 ACTION_DOWN 上设为全局静态)所以这将是无效和绘制视图后的 SAME MotionEvent
6) 围绕所选(MotionEvent.GetX/Y) 位置剪切位图
7) 在原件上绘制修剪后的位图 (canvas) canvas
可能遇到的困难: -Motion 事件 returns 不同的坐标 X,Y 当它被覆盖的 onTouchEvent 或从 ACTION_DOWN 上发生的静态事件调用时; (只需将 x、y 坐标设为静态)并且不要忘记删除静态触摸事件,以及动作 UP
上的 x、y 坐标-2应该用canvas或者你可以放大镜放大镜)