Реализация лупа / лупа для настраиваемого динамического просмотра на Android

Я ищу способ реализовать Magnifier/Loupe для пользовательского просмотра на Android, который динамически перестраивается.

2 ответа

Решение

Я понял это сам. Так что вот вариант для динамического изменения вида.

1) Сначала мы создаем новое растровое изображение (целое) с такими же высотой и шириной в методе Overriden on Draw;

2) создать Canvas(temporalCanvas) из нашего растрового изображения (целое)

3) нарисуйте все, что нам нужно, на холсте (temporalCanvas)

4) вывести растровое изображение на оригинальный холст (canvas), который указан в доходе onDraw

5) взять координаты из MotionEvent (он должен быть сделан глобальным статическим на ACTION_DOWN), так что это будет ЖЕ MotionEvent после аннулирования и просмотра рисунка

6) Вырезать растровое изображение вокруг выбранной позиции (MotionEvent.GetX/Y)

7) Нарисуйте обрезанный растровый рисунок на оригинальном холсте

Возможные трудности: -Motion событие возвращает разные координаты X,Y, когда оно вызывается либо из переопределенного onTouchEvent, либо из статического события, которое было сделано в ACTION_DOWN; (просто сделайте координаты x,y статическими) и не забудьте удалить статическое событие касания, а координаты x,y при действии UP

-2 холст надо использовать или можно увеличить лупу)

Я сделал этот класс только для того, чтобы ответить на ваш вопрос. Это самая базовая реализация лупы, надеюсь, это поможет. Удачи:

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;
    }

}
Другие вопросы по тегам