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

Feature/scrollbars #30

Merged
merged 10 commits into from
Jun 14, 2018
43 changes: 22 additions & 21 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,53 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">

<com.otaliastudios.zoom.ZoomLayout
android:layout_weight="1"
android:id="@+id/zoom_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="horizontal|vertical"
app:hasClickableChildren="true">

<com.otaliastudios.zoom.demo.ColorGridView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content" />

</com.otaliastudios.zoom.ZoomLayout>

<com.otaliastudios.zoom.ZoomImageView
android:layout_weight="1"
android:id="@+id/zoom_image"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="0dp"/>
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="horizontal|vertical"
android:visibility="gone" />

<LinearLayout
android:background="@color/colorAccent"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:orientation="horizontal">

<Button
android:text="View hierarchy"
android:id="@+id/show_zl"
android:background="@null"
android:layout_weight="0.5"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:background="@null"
android:text="View hierarchy" />

<Button
android:text="Image"
android:id="@+id/show_ziv"
android:background="@null"
android:layout_weight="0.5"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:background="@null"
android:text="Image" />

</LinearLayout>

Expand Down
39 changes: 39 additions & 0 deletions library/src/main/java/com/otaliastudios/zoom/ZoomImageView.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.annotation.AttrRes;
Expand Down Expand Up @@ -89,12 +90,50 @@ public boolean onTouchEvent(MotionEvent ev) {
public void onUpdate(ZoomEngine helper, Matrix matrix) {
mMatrix.set(matrix);
setImageMatrix(mMatrix);

if (!awakenScrollBars()) {
invalidate();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for this call? We should not need to invalidate. setImageMatrix will do it.
Same for ZoomLayout.

Copy link
Collaborator Author

@markusressel markusressel Jun 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for awakenScrollBars() states:

When the animation is started, this method returns true, 
and false otherwise. If the animation is started, this method 
calls {@link #invalidate()}; in that case 
the caller should not call {@link invalidate()}.

So I added this condition. I guess if setImageMatrix already does it this check is useless.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think it's better to simply call awakenScrollBars() and ignore the result.
Also, you need to merge the other PR changes to merge this one. Thanks!

}
}

@Override
public void onIdle(ZoomEngine engine) {
}

@Override
protected int computeHorizontalScrollExtent() {
Rect localRect = new Rect();
getLocalVisibleRect(localRect);
return localRect.width();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason why using this rather than getWidth() and getHeight? It should return the same thing almost always. Also in vertical extent & in ZoomLayout callbacks.

If there is a reason, could you cache this rect in a tempRect field? So we don't create a lot of them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I think it should also work with getWidth() and getHeight().
I don't have that much experience with custom views so the "localVisibleRect" method looked like a good fit, but I guess it can be slow.

}

@Override
protected int computeHorizontalScrollOffset() {
return (int) (-1 * mEngine.getPanX() * mEngine.getRealZoom());
}

@Override
protected int computeHorizontalScrollRange() {
return (int) (mDrawableRect.width() * mEngine.getRealZoom());
}

@Override
protected int computeVerticalScrollExtent() {
Rect localRect = new Rect();
getLocalVisibleRect(localRect);
return localRect.height();
}

@Override
protected int computeVerticalScrollOffset() {
return (int) (-1 * mEngine.getPanY() * mEngine.getRealZoom());
}

@Override
protected int computeVerticalScrollRange() {
return (int) (mDrawableRect.height() * mEngine.getRealZoom());
}

//endregion

//region APIs
Expand Down
57 changes: 51 additions & 6 deletions library/src/main/java/com/otaliastudios/zoom/ZoomLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
Expand All @@ -21,13 +22,13 @@
* Uses {@link ZoomEngine} to allow zooming and pan events onto a view hierarchy.
* The hierarchy must be contained in a single view, added to this layout
* (like what you do with a ScrollView).
*
* <p>
* If the hierarchy has clickable children that should react to touch events, you are
* required to call {@link #setHasClickableChildren(boolean)} or use the attribute.
* This is off by default because it is more expensive in terms of performance.
*
* <p>
* Currently padding to this view / margins to the child view are NOT supported.
*
* <p>
* TODO: support padding (from inside ZoomEngine that gets the view)
* TODO: support layout_margin (here)
*/
Expand Down Expand Up @@ -150,23 +151,66 @@ public void onUpdate(ZoomEngine helper, Matrix matrix) {
} else {
invalidate();
}

if (!awakenScrollBars()) {
invalidate();
}
}

@Override
public void onIdle(ZoomEngine engine) {
}

@Override
protected int computeHorizontalScrollExtent() {
Rect localRect = new Rect();
getLocalVisibleRect(localRect);
return localRect.width();
}

@Override
protected int computeHorizontalScrollOffset() {
return (int) (-1 * mEngine.getPanX() * mEngine.getRealZoom());
}

@Override
protected int computeHorizontalScrollRange() {
return (int) (mChildRect.width() * mEngine.getRealZoom());
}

@Override
protected int computeVerticalScrollExtent() {
Rect localRect = new Rect();
getLocalVisibleRect(localRect);
return localRect.height();
}

@Override
protected int computeVerticalScrollOffset() {
return (int) (-1 * mEngine.getPanY() * mEngine.getRealZoom());
}

@Override
protected int computeVerticalScrollRange() {
return (int) (mChildRect.height() * mEngine.getRealZoom());
}

@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean result;

if (!mHasClickableChildren) {
int save = canvas.save();
canvas.setMatrix(mMatrix);
boolean result = super.drawChild(canvas, child, drawingTime);
result = super.drawChild(canvas, child, drawingTime);
canvas.restoreToCount(save);
return result;
} else {
return super.drawChild(canvas, child, drawingTime);
result = super.drawChild(canvas, child, drawingTime);
}

onDrawScrollBars(canvas);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this and use setWillNotDraw(false) in the constructor.


return result;
}

//endregion
Expand Down Expand Up @@ -205,6 +249,7 @@ public void setHasClickableChildren(boolean hasClickableChildren) {

/**
* Gets the backing {@link ZoomEngine} so you can access its APIs.
*
* @return the backing engine
*/
public ZoomEngine getEngine() {
Expand Down