Coder Social home page Coder Social logo

natario1 / zoomlayout Goto Github PK

View Code? Open in Web Editor NEW
1.0K 27.0 146.0 45.39 MB

2D zoom and pan behavior for View hierarchies, images, video streams, and much more, written in Kotlin for Android.

Home Page: https://natario1.github.io/ZoomLayout

License: Apache License 2.0

Java 6.70% Kotlin 93.30%
android android-library zoom-images zooming-panning-moving pinch-to-zoom kotlin kotlin-library surface opengl opengl-es 2d zoom-engine pan touch-events imageview

zoomlayout's Introduction

Build Status Release Issues

Need support, consulting, or have any other business-related question? Feel free to get in touch.

Like the project, make profit from it, or simply want to thank back? Please consider sponsoring!

ZoomLayout

A collection of flexible Android components that support zooming and panning of View hierarchies, images, video streams, and much more - either programmatically or through touch events.

implementation("com.otaliastudios:zoomlayout:1.9.0")
  • ZoomLayout: a container that supports 2D pan and zoom to a View hierarchy, even supporting clicks [docs]
  • ZoomImageView: (yet another) ImageView that supports 2D pan and zoom [docs]
  • ZoomSurfaceView: A SurfaceView that supports 2D pan and zoom with OpenGL rendering [docs]
  • Powerful zoom APIs [docs]
  • Powerful pan APIs [docs]
  • Lightweight, no dependencies
  • Works down to API 16

In fact, ZoomLayout, ZoomImageView and ZoomSurfaceView are just very simple implementations of the internal ZoomEngine [docs]. The zoom engine lets you animate everything through constant updates, as long as you feed it with touch events, with a Matrix-based mechanism that makes it very flexible.

Support

If you like the project, make profit from it, or simply want to thank back, please consider supporting it through the GitHub Sponsors program! You can have your company logo here, get private support hours or simply help me push this forward.

Feel free to contact me for support, consulting or any other business-related question.

Setup

Please read the official website for setup instructions and documentation. You might also be interested in our changelog.

<com.otaliastudios.zoom.ZoomLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical|horizontal"   
    app:transformation="centerInside"                                
    app:transformationGravity="auto"
    app:alignment="center"
    app:overScrollHorizontal="true"
    app:overScrollVertical="true"
    app:overPinchable="true"
    app:horizontalPanEnabled="true"
    app:verticalPanEnabled="true"
    app:zoomEnabled="true"
    app:flingEnabled="true"
    app:scrollEnabled="true"
    app:oneFingerScrollEnabled="true"
    app:twoFingersScrollEnabled="true"
    app:threeFingersScrollEnabled="true"
    app:minZoom="0.7"
    app:minZoomType="zoom"
    app:maxZoom="2.5"
    app:maxZoomType="zoom"
    app:animationDuration="280"
    app:hasClickableChildren="false">

    <!-- Content here. -->

</com.otaliastudios.zoom.ZoomLayout>

zoomlayout's People

Contributors

asclepix avatar bkhall avatar coffeemakr avatar dennisblock avatar dependabot[bot] avatar dmazzoni avatar iamkdblue avatar lrp-sgravel avatar markusressel avatar natario1 avatar nil2l avatar quanlt avatar r4zzz4k avatar rayyantahir avatar sylwester-zielinski avatar yundin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zoomlayout's Issues

How to scroll inside ZoomLayout ?

I am trying to put a ScrollView inside a ZoomLayout, but ScrollView is not working. And that's my question how to Scroll inside ZoomLayout ?

How to sync zoom and pan effect with a view (mini-map) like ticket booking app?

625231ec7035936bca24

Hi, as the title, i want to sync the ZoomLayout with another view (minimap) so that when i zoom or move the layout, the minimap will be sync and move at the same time with the Zoomlayout, it is very helpful to know the position, show where we are now of the whole screen (see the picture). But I don't know where to start with this, it will be very helpful if someone could give me a hint to do this.

Using ViewCompat.postOnAnimation

Instead calling mView.postOnAnimation(this); in ZoomEngine.java, can you change to ViewCompat.postOnAnimation(mView, this);? and change the minimum SDK to 15

match_parent BUG

When I try to set the child view width to match_parent, the view disappears.
I'm trying to add a layout as a child view.
please fix this.

Allow pan while pinching

Current Behaviour

The focus point when pinching is fixed at the center of both touch points when the pinching gesture is started. This means the content can not be panned during the pinch gesture.

Expected Behaviour

The focus point moves with the center of both touch points.
When starting the pinch gesture the center is remembered and when moving both touch points in the same direction and speed (without changing their distance) the content should be panned without any zoom changes.

This allows to zoom more conveniently to a specific position instead of having to zoom to the desired level and adjusting view position afterwards using pan gesture.

Fling detection doesn't work when overscrolled

Current Behaviour

  1. scroll with a single finger to the lower right corner of the view
  2. try to fling up with a slight tendency to the right border causing a slight overscroll on the right edge
  3. release touch
    => the upwards motion stops immediately and an animation is started to return to a non-overscrolled state

Expected Behaviour

A fling gesture is detected regardless of the slight overscroll. The fling is executed and (as is currently the case) also automatically returns to a non-overscrolled state but keeps the initial upwards motion.

Using the ZoomLayout inside a ViewPager

I'm trying to use ZoomLayout as the element of a ViewPager but I'm experiencing a weird issue when swiping to show the next/previous page. It looks like instead of making the new page slide in, it's like if I'm removing an overlay off a page that sits below the current page.

I suppose it's due the layout of the page coming in that is changing dimensions while sliding so that ZoomLayout is adapting the image in a weird way and the final effect is like I'm peeling a layer off a page under the current one. It's nice but it's not what I'm looking for.

Is there any way to temporarily disable this behavior so that it behaves just like an ImageView while sliding in?

Cheers!

How to Pan with overscroll?

I need to center some object that located near Layout corner, I could to it with touch, however, I have to do it programmatically, any Ideas?
P.S. I'm making some kind of floor map, scroll like in AirBnb map
screen shot 2018-08-28 at 5 52 11 pm

Zoom and Pan to coordinates

Hi,

I have a ScrollView as parent, its child is a LinearLayout that contains the ZoomLayout.
The ZoomLayout contains a FrameLayout with an ImageView and another FrameLayout that contains some EditTexts.

I implemented this complex structure to create a PDF compiler. The ImageView will contains the PDF image and, above of it, I have a FrameLayout that has some Edittexts placed with particular coordinates.

I need to "jump" from an EditText to another one (with a Button), applying zoom and pan to the interested EditText.

I tried to implement the method "moveTo" of the class ZoomLayout passing the zoom value, my Edittext coordinates (x and y) and the animated value (boolean).
I haven't the expected result because my layout moves to wrong coordinates.

This is my structure:

...

Please, help me and sorry for my bad english

Unable to interrupt Pan

Steps to produce:

  1. Pan fast
  2. Press view to stop panning

Excepted behaviour:

  • Pan immediately stops, and the view isn't tapped

Current behaviour:

  • Nothing, the pan just continues and doesn't respond to tap

Unregister ZoomLayout's OnGlobalLayoutListener

Environment

Library version: com.otaliastudios:zoomlayout:1.3.0
Android version: Android 9 (API 28), tested on a Google Pixel 2

Issue Description

While testing an application that uses ZoomLayout, a memory leak was reported by LeakCanary. It seems that the leak is caused by the OnGlobalLayoutListener registered in ZoomLayout.addView(), which is never unregistered.

Leak Information

The leak info exported from LeakCanary can be found at square/leakcanary#1126. I had opened that issue because I thought that the leak was caused by the Android SDK and should therefore be added to LeakCanary's exclusion list.

Tests with ZoomLayout

I then re-tested my application with a fork of ZoomLayout in which I modified the OnGlobalLayoutListener to unregister itself the first time it is invoked. No leaks were reported by LeakCanary, and everything in ZoomLayout seemed to be working as expected. Do you think that there could be any negative side effects with that modification?

Is it possible to saperate out multiple view from zoomin

This library work like a charm great job.
My problem :
I have multiple view added dynamically on particular x,y co-ordinate.
Few of them are overlapped because of just small difference in there x ,y coordinates.
Wants to zoom in to separate view a little bit.
Any suggestion is appreciated.

Doesn't render when the child is a GridView

    <com.otaliastudios.zoom.ZoomLayout
        android:id="@+id/zoom"
        android:layout_width="320dp"
        android:layout_height="500dp"
        android:scrollbars="vertical|horizontal"
        app:overScrollHorizontal="true"
        app:overScrollVertical="true"
        app:overPinchable="true"
        app:horizontalPanEnabled="true"
        app:verticalPanEnabled="true"
        app:zoomEnabled="true"
        app:minZoom="0.7"
        app:minZoomType="zoom"
        app:maxZoom="3.0"
        app:maxZoomType="zoom"
        app:hasClickableChildren="true">

        <GridView
            android:id="@+id/gridview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none"
            android:numColumns="30"
            android:verticalSpacing="2dp"
            android:horizontalSpacing="2dp"
            android:stretchMode="columnWidth"
            android:gravity="center"
            android:overScrollMode="never"
            android:fadingEdge="none" />

    </com.otaliastudios.zoom.ZoomLayout>

I don't see the gridview when I try this code. Also, when the width and height of the zoomlayout are match_parent, it throws a RuntimeException saying ZoomLayout must be used with fixed dimensions. Any help?

Better pinching - don't change the focus while the gesture is going

Current pinch behavior does not feel super natural, in that it keeps changing the focus point during the gesture (causing a continuous pan, on top of the zoom).

It's OK to zoom towards the gesture focus center, but it should be fixed at the start of the gesture, and respected until the gesture ends.

Set initial zoom, instead of pre-calculating to "fitCenter"

Hi! A helpfull feature would be a method to set the initial scale applied to the image. I saw that after setting the image drawable, the initial zoom is computed to fit the parent`s dimension. However, using the scale type for the initial zoom would provide a better control of the image that is shown.

For instance, in my example I want to show the image "as is", with no automatic zoom.

I surpassed this limitation by adding these lines in the constructor

    // Set the min zoom to 1 to avoid the computed zoom to shrink my image
    getEngine().setMinZoom(1f, ZoomEngine.TYPE_REAL_ZOOM);
    getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if(mOfflineMap != null && mOfflineMap.getMapBitmap() != null) {

                // Compute the min zoom to fit the screen content
                float minZoom = Math.min(
                        (float) getMeasuredWidth() / mOfflineMap.getMapBitmap().getWidth(),
                        (float) getMeasuredHeight() / mOfflineMap.getMapBitmap().getHeight());
                getEngine().setMinZoom(minZoom, ZoomEngine.TYPE_REAL_ZOOM);

                // Compute the actual zoom to the original zoom (no zoom at all)
                getEngine().zoomTo(getEngine().getZoom() / getEngine().getRealZoom(), true);
            }
        }
    });

minSdkVersion 16?

minSdkVersion 16? lol i missed lot off mobile phone and client ... why this?????? i think 14 is ok .. this lib no need minSdkVersion 16...

PanTo position coordinates have to be negative?

First of all, thank you for this amazing library.
Maybe it's just me or I didn't get it, but when I used panTo and passed in the X and Y position of a child it would just scroll to the top left, it turned out that it had to be the negative value of the child, I find this a bit confusing, and it took me a while to figure it out.

Enclosing View is not properly rendered on Android 6 and lower

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.

Scrollbars

Hey, awesome library :)

I want to use this to build a Text Editor and want to add scrollbars for both x and y axis.
Is there some kind of listener/callback API that I missed to intercept changes in the current positioning of the ZoomLayout? If so I would be able to implement scrollbars myself and update them even when "flinging" the position.

It would also be cool to have something like this (scrollbars) built in - although it might be out of scope for this library.

Thx for the great work.

Child view in ZoomLayout is not centered

Hi I'm using the following code but could not get ZoomLayout child view centered:

  <com.otaliastudios.zoom.ZoomLayout
      android:layout_width="match_parent"
      android:layout_height="450dp"
      android:layout_gravity="center"
      android:scrollbars="vertical|horizontal"
      app:horizontalPanEnabled="true"
      app:verticalPanEnabled="true"
      app:zoomEnabled="true"
      app:hasClickableChildren="true">

      <com.xiaopo.flying.sticker.StickerView
          android:id="@+id/sticker_view"
          android:layout_width="253dp"
          android:layout_height="450dp"
          android:layout_gravity="center"
          android:background="#CCC"
          app:showBorder="true"
          app:showIcons="true"
          />

  </com.otaliastudios.zoom.ZoomLayout>

The result:
device-2018-06-28-111900
The grey area view should in center

want to sync a view with ZoomLayout scroll and zoom

Hi,
I have layout to implement similar to ticket booking. It has Gridview and on left side of (outiside of) zoom section I have to show row number of Seats.

But when we pinch or scroll the Seats, the Caption must be scroll and zoom with it to make proper sync. I think this can be achieveable with this library. But I don't understand from where to start. If any one can guide me I will do it myself.

Build fails when float f-suffix is used in xml

The readme gives an example with:

app:minZoom="0.7f"
app:maxZoom="3f"

Which raises the building error:

AGPBI: {"kind":"error","text":"error: \u00270.7f\u0027 is incompatible with attribute myPackage:minZoom (attr) float [weak].","sources":[{"file":"myFile","position":{"startLine":7}}],"original":"","tool":"AAPT"}

It's easily fixed with:

app:minZoom="0.7"
app:maxZoom="3"

Support for padding

It would be cool if ZoomLayout or, better, ZoomEngine, could read padding from the view and support it. Apart from not being simple, I am not even sure what the desired behavior would be.

Should we clip to padding? Assume the padded position to be the rest position? For any scale? How are the semantics of pan affected by this?

Double tap to zoom

It's common to react to double taps to control zoom. This should be a opt-in feature in ZoomEngine, enabled by default in ZoomImageView.

Exception: ZoomLayout must be used with fixed dimensions

I'm using the ZoomLayout in a dynamic layout.
It works very well most of the time. Sometimes on the other hand the app crashes during the measurement with the error:

java.lang.RuntimeException: ZoomLayout must be used with fixed dimensions (e.g. match_parent)

The ZoomLayout has a width and height of match_parent and also a min width and min height of 1dp.
It is inserted in a FrameLayout. How can I prevent this error? It is possible that the Framelayout containing the ZoomLayout has no size yet. Could this be the problem?

Convert code to Kotlin

Hey, I really dig this library and would love to see it come to life in Kotlin.
I know you said you would migrate this library to Kotlin in the long run (#2).

I would like to take the chance and convert the existing code to a version that is usable for both Kotlin and Java.

Redefining SmallerPolicy

I would like to say what I have in mind about this new feature introduced in #71 that looks important to me and get feedback. This might also help in improving documentation.

Transformations

As said elsewhere, transformation is not the best name ever, but that's what we have.
The transformation defines the engine resting position. It is a keyframe that is reached at certain points, like at start up or when certain methods are called (setContentSize or setContainerSize with applyTransformation = true).

This was extremely useful anytime I had to use this library, plus it also defines the difference between zoom and realZoom (other names that I would change today). With transformations like CENTER_CROP or CENTER_INSIDE, we can assume that the content - whatever its real size is - will be fitting one of the container dimensions, and we call that zoom == 1. This is super useful for defining minZoom and maxZoom constraints. (CENTER_CROP and minZoom = 1 make sure that you never show background, for example).

As it is defined now, transformation is a purely zoom thing.

Transformation Gravity

Some transformations / aspect ratios might leave with a situation where, after applying the transformation, part of the content is cropped. In these cases, the engine could align the content to different parts of the container, so the transformation gravity applies. This is a purely pan thing.

Error: this gravity does not apply when the transformation leaves the content smaller than the container. Only the opposite. This feels wrong but also right, in that, the 'smaller policy' is a behavior policy that must apply always, not just at transformation time. This makes me think that this method should not exist at all.

When content is smaller than container

This can happen in various situations:

  • With TRANSFORMATION_NONE and a content that is actually smaller
  • With TRANSFORMATION_CENTER_INSIDE, one of the axes will probably be smaller
  • Unless minZoom is very high, pinching out can always make content smaller than the container

We've been ignoring this case until it was brought up in #71 . In this situation, I see that the engine might actually do two things:

  • Let the content be moved around freely ( = SMALLER_POLICY_NONE)
  • Align the content to some part of the container according to some gravity flag

I can't think of any third option. If you can, please say. But if these are the only two options...

Proposal: Alignment (Gravity)

Remove SmallerPolicies. Create ALIGNMENT_ integer flags as always. Then create alignment XML attribute and setAlignment method.

Possible values should be

  • ALIGNMENT_NONE : corresponds to SMALLER_POLICY_NONE
  • ALIGNMENT_TOP, ALIGNMENT_BOTTOM, ... : aligns to that specific side of the container

Docs should made clear that alignments only apply when content is smaller than the container, because forcing an alignment when content is bigger, makes the hidden content unreachable. This is actually obvious, not a design decision. When content is bigger you must be able to pan around.

About the name

I was also tempted to call this setGravity, I see arguments on both sides. Let me know what you think. For example (good and bad):

  • setGravity makes confusion with setTransformationGravity
  • setGravity is consistent with setTransformationGravity
  • setAlignment being more generic might allow for more behaviors in the future
  • The gravity XML attribute might be already used for some views?
  • setGravity means we're using the Gravity constants.
  • At the same time this is confusing because we will also have GRAVITY_NONE and also we do not support all the gravity fields. A gravity "top|bottom" or "fill_horizontal" is ignored by the engine.
  • With alignment we are free to do more fancy stuff. For example, "none_horizontal|top", "center_horizontal|none_vertical". We could have none as a flag and apply it to single axis.

I do prefer alignment.

About transformationGravity

After this change, docs should say this about transformations:

When a transformation is applied, the content can be smaller or bigger than the container on some axis. When it is smaller, the alignment gravity applies as always. When it is bigger, the alignment gravity applies as well, unless a transformationGravity was defined, in which case it is respected instead.

So we should be inverting the dependency, make transformationGravity default to the alignment and not the opposite. Because transformationGravity is just a pan, one-time translation applied after the transformation and only when content is bigger. The alignment is a key behavior of the engine, always active.

What do you think about this?

@markusressel

Q: Overlay view

Hi @natario1,
I'd like to create a colors grid with your ZoomLayout.
I can easily build the grid using a class that extends GridLayout like in your example class ColorGridView.
But how can i add a view in overlay like in attached screenshot over tapped view in grid?

Thank you!
foto 08-02-18 15 26 04

default zoom coordinate

Hi
I'm using tablview inside of the zoomView . The problem is that by default, zoom view shows middle rows of the table -horizontally and vertically center-. any way to show top of the table by default?

ZoomLayout got stuck and not respond on any touch events.

when ever i am panning and moving layout it got stuck most of the time, even i haven't implemented any click listeners on child views.

Xml Usage

<com.otaliastudios.zoom.ZoomLayout
android:id="@+id/writeViewScroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:overScrollMode="always"
app:hasClickableChildren="false"
app:maxZoom="3"
app:maxZoomType="zoom"
app:minZoom="1"
app:minZoomType="zoom"
app:overPinchable="true"
app:overScrollHorizontal="true"
app:overScrollVertical="true">

        <ImageView
            android:id="@+id/bgCardIv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent"
            android:scaleType="fitXY"
            android:src="@drawable/address" />

        <com.feltapp.writeview.components.WriteViewEdittext
            android:id="@+id/writeCardEt"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/holo_green_light"
            android:enabled="false"
            android:gravity="top|start"
            android:imeOptions="flagNoExtractUi"
            android:inputType="textMultiLine"
            android:padding="36dp" />


        <ImageView
            android:id="@+id/ivGuidlinesPreview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:scaleType="fitXY"
            android:src="@drawable/card"
            android:visibility="gone" />


    </FrameLayout>

</com.otaliastudios.zoom.ZoomLayout>

Scrollbars not rendered when fadeScrollbars="false"

Because of a missing "invalidate()" call (removed in the review of the recently PR) scrollbars are not rendered when the fadeScrollbars attribute is set to false.

This only applies to the ZoomLayout, the ZoomImageView is not affected, apparently because it uses setImageMatrix() which internally calls invalidate() on every draw.

I would just follow the documentation and call invalidate if awakenScrollbars() returns false.

I will create a PR for this issue shortly.

ZoomLayout to Top

Hello,
Firstly, thanks for good library.
With my project requirement, I want to set zoomlayout to Top of screen, but the default config is center. Can you guide me how to set this?
Thanks very much.

Zooming events

Hi @natario1 ,
can you help me how to listen for zooming events of a ZoomLayout?
I'd like to be notified on views zoom level change, to do something when zoom level is over 2x for example.

Thank you!

Default Zoom

Hello, I used your zoomlayout Lib its awesome but I have one doubt, is already there in default zoomin and
zoom out option?. I using minzoom and max zoom its automatically taken min zoom only when open the layout but need default zoom option.

Support for onTouchListener

Hi, i try to add a touchListener to the ZoomImageView

val touchListener = View.OnTouchListener { v, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    val x = event.x.toInt()
                    val y = event.y.toInt()

                    val pixel = maskImage.getPixel(x, y)

                    /*val redValue = Color.red(maskPixel)
                    val greenValue = Color.green(maskPixel)
                    val blueValue = Color.blue(maskPixel)*/

                    if (AssetResource.isNonTouch(pixel)) {
                        Log.i(TAG, "Is non touch")
                    } else {
                        val address = LookupUtilities.pixelToString(pixel)
                        this.currentResource = when(resourceType) {
                            "header" -> headerAsset!!
                            "footer" -> footerAsset!!
                            else -> contentAsset
                        }
                        loadAddress(address)
                    }
                }
            }
zoomImageView.setOnTouchListener(touchListener)

But if i do it like that, it disables all the other listener

RecyclerView inside ZoomLayout

When placing RecyclerView inside ZoomLayout, the whole recyclerView is shown.

@Override
      public void onGlobalLayout() {
               mChildRect.set(0, 0,
                       child.getWidth(),
                       child.getHeight());
               mEngine.setContentSize(mChildRect);
       }
});
super.addView(child, index, params);

Can anything be done to change this behavior? Just to implement a preview view like Google Drive.

Better overscroll / overpinch - replace thresholds with friction

Currently the engine lets you scroll / drag / pinch outside the safe bounds, until a fixed threshold is reached.

This does not feel very natural. The best thing would be to have no threshold, but rather apply a friction to the movement (the more you overdrag, the less movement you cause).

These frictions should be public and controllable.

Need a callback on Zoom event

Hi, you did a really amazing library here. I recently need a callback event for every time its zoom (in or out). What do you think?

Inconsistent layout for different Android device density (or OS version)

I have a image view in child and for 420dpi device it is showing perfect centered vertical in the zoomlayout.

Same code on 560dpi device moves image to top (almost 80dp) behind a view on top of the screen. Image size is 1360 x 910.

Can you give me some hint, i want to fix it myself.

Devices used:

Update
This issue could be because of OS version. Nexus 6P emulator (API 26) has no issue. Nexus 6P emulator (API 23) has the issue.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="10">

    <com.otaliastudios.zoom.ZoomLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="6"
        android:background="@color/colorAccent"
        app:maxZoom="3.0"
        app:minZoom="1.0">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:src="@drawable/img"/>
        </LinearLayout>

    </com.example.syed.draganddrop.engine.ZoomLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="4"
        android:background="@android:color/darker_gray">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textColor="@android:color/white"/>
    </LinearLayout>

</LinearLayout>

Disable Zoom

Is there any way to temporary pause ( disable ) ZoomLayout from zoom and pinch? I want ZoomLayout to stay at paused position until I resume it back ( children should keep listening their listeners)

Thanks for this great component !

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.