Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enclosing View is not properly rendered on Android 6 and lower #22

Closed
W3D3 opened this issue Apr 16, 2018 · 2 comments
Closed

Enclosing View is not properly rendered on Android 6 and lower #22

W3D3 opened this issue Apr 16, 2018 · 2 comments

Comments

@W3D3
Copy link

W3D3 commented Apr 16, 2018

I am using a custom View with a Canvas that is made zoomable with help of this library and this works fine on Android 7 and higher.

Here are 2 reference images with the ZoomLayout unzoomed and not panned.

screen shot 2018-04-16 at 19 50 19

The Version running on Android API 27 is behaving as expected and draws the Canvas in the size of the screen. The view is zoomable and the coordinate transformation works so that the clicks on different Hexagons get detected.

screen shot 2018-04-16 at 19 50 27

This is the same View on Android API 23 or lower (shown is API Level 18) where the whole canvas seemed to have moved towards the top. When panning down there is a white part of the ZoomLayout area that should not be there and indicates that the canvas got moved towards the top becomes visible. Clicks on the canvas are also not getting the right x and y values and therefore don't hit any of my defined regions which makes the View useless with zoom.
This does not happen when I just put the View inside a LinearLayout or something similar.

screenshot_1523901541

Here is the XML Code for the view:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    android:id="@+id/gridContainer"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical">


    <Button xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

    <com.otaliastudios.zoom.ZoomLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/zoomContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:hasClickableChildren="false"
        app:maxZoom="3"
        app:maxZoomType="zoom"
        app:minZoom="1"
        app:minZoomType="zoom"
        app:overPinchable="false"
        app:overScrollHorizontal="false"
        app:overScrollVertical="false">

        <!-- Content here. -->

    </com.otaliastudios.zoom.ZoomLayout>

</LinearLayout>

The inner content of my ZoomLayout then gets set programmatically:

...
hexView = new HexView(getApplicationContext());
final ZoomLayout zl = (ZoomLayout) findViewById(R.id.zoomContainer);
hexView.prepare();
zl.addView(hexView);

Where the HexView itself contains this code:

public class HexView extends View {

    Board board;
    List<Hex> hexes;
    List<Region> regionList;
    WindowManager manager;
    int maxX;
    int maxY;
    private final GestureDetector gestureDetector;
    private boolean singleClick;

    ZoomLayout zoomLayout = null;

    Paint strokePaint;
    Paint fillPaint;

    Region clip;

    public Board getBoard() {
        return board;
    }

    public void setBoard(Board board) {
        this.board = board;
    }

    public WindowManager getManager() {
        return manager;
    }

    public void setManager(WindowManager manager) {
        this.manager = manager;
    }

    public HexView(Context context) {
        super(context);


        hexes = new ArrayList<>();
        regionList = new ArrayList<>();

        this.strokePaint = new Paint();
        this.fillPaint = new Paint();

        this.gestureDetector = new GestureDetector(...);
    }

    public ZoomLayout getZoomLayout() {
        return zoomLayout;
    }

    public void setZoomLayout(ZoomLayout zoomLayout) {
        this.zoomLayout = zoomLayout;
    }

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

    public void prepare(){
        hexes.addAll(board.getHexagons());

        Display mdisp = getManager().getDefaultDisplay();
        Point mdispSize = new Point();
        mdisp.getSize(mdispSize);
        maxX = mdispSize.x;
        maxY = mdispSize.y;
        int scale = Math.min(maxX, maxY) / 5;

        for (Hex hex : hexes) {
            hex.calculatePath(new Pair<>(maxX/2, maxY/2), scale);
        }
        //TODO ADJUST MIN/MAX HEIGHT/WIDTH VIA PROPERTIES
        // OR GET IT FROM PARENT?
        setMinimumHeight(maxY);
        setMinimumWidth(maxX);
        //ready to draw
        setWillNotDraw(false);
        invalidate();
    }

    protected void onDraw(Canvas c){
        super.onDraw(c);

        clip = new Region(0, 0, c.getWidth(), c.getHeight());

        //Background white
        this.fillPaint.setStyle(Paint.Style.FILL);
        this.fillPaint.setColor(Color.GRAY);
        c.drawPaint(fillPaint);

        strokePaint.setStrokeWidth(3);
        strokePaint.setPathEffect(null);
        strokePaint.setColor(Color.BLACK);
        strokePaint.setStyle(Paint.Style.STROKE);

        fillPaint.setStyle(Paint.Style.FILL);
        fillPaint.setColor(Color.YELLOW);


        for (Hex hex : hexes) {
            Path path = hex.getPath();

            path.setFillType(Path.FillType.EVEN_ODD);
            fillPaint.setColor(hex.getTerrainColor());
            c.drawPath(path, fillPaint);
            c.drawPath(path, strokePaint);

            Region r = new Region();
            r.setPath(path, clip);
            hex.setRegion(r);
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        // this sets singleClick so we know that when the user wants to really tap something
        gestureDetector.onTouchEvent(event);

        float x = event.getX();
        float y = event.getY();

        if(zoomLayout != null)
        {
            // invert the coordinates so they map back to our regions when using a zoom engine
            x = x * (1/zoomLayout.getEngine().getRealZoom()) - zoomLayout.getEngine().getPanX();
            y = y * (1/ zoomLayout.getEngine().getRealZoom()) - zoomLayout.getEngine().getPanY();
        }

        for (int i = 0; i < hexes.size(); i++) {
            Region r = hexes.get(i).getRegion();
            if (r.contains((int)x,(int)y)) {
                //TODO remove debug data and handle touches properly
                if(singleClick) {
                    System.out.println(hexes.get(i).toString());
                    Toast.makeText(getContext().getApplicationContext(), hexes.get(i).toString(),
                            Toast.LENGTH_SHORT).show();
                }
                singleClick = false;
                break;
            }
        }
        return true;
    }
}

I'd really like to make this available for all Android version.
Help would be greatly appreciated.

@natario1
Copy link
Owner

You don't need to set width and height to the screen dimensions. ZoomLayout will scale it down.

Just use random big values in XML like layout_width=1000dp and layout_height=1000dp. And move the prepare logic after super.onMeasure, using getMeasuredWidth() and getMeasuredHeight() as inputs.

I don't know why you are having this issue, but this might fix.

@natario1
Copy link
Owner

I think this was fixed by #62

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants