From afc230ee5270fb7df00059df68be6aa6556fcee2 Mon Sep 17 00:00:00 2001 From: juhonggang Date: Fri, 7 Sep 2018 20:12:16 +0800 Subject: [PATCH] Add Fresco support --- .../photoview/PhotoViewAttacher.java | 2 +- sample/build.gradle | 2 + sample/src/main/AndroidManifest.xml | 3 + .../sample/FrescoSampleActivity.java | 180 ++++++++++++ .../photoview/sample/LauncherActivity.java | 10 +- .../sample/fresco/DraweeViewAttacher.java | 32 +++ .../sample/fresco/PhotoDraweeView.java | 269 ++++++++++++++++++ .../layout/activity_fresco_simple_sample.xml | 33 +++ 8 files changed, 529 insertions(+), 2 deletions(-) create mode 100755 sample/src/main/java/com/github/chrisbanes/photoview/sample/FrescoSampleActivity.java create mode 100644 sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/DraweeViewAttacher.java create mode 100644 sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/PhotoDraweeView.java create mode 100755 sample/src/main/res/layout/activity_fresco_simple_sample.xml diff --git a/photoview/src/main/java/com/github/chrisbanes/photoview/PhotoViewAttacher.java b/photoview/src/main/java/com/github/chrisbanes/photoview/PhotoViewAttacher.java index 67042c18..d9596dc3 100644 --- a/photoview/src/main/java/com/github/chrisbanes/photoview/PhotoViewAttacher.java +++ b/photoview/src/main/java/com/github/chrisbanes/photoview/PhotoViewAttacher.java @@ -598,7 +598,7 @@ private void checkAndDisplayMatrix() { * @param matrix - Matrix to map Drawable against * @return RectF - Displayed Rectangle */ - private RectF getDisplayRect(Matrix matrix) { + protected RectF getDisplayRect(Matrix matrix) { Drawable d = mImageView.getDrawable(); if (d != null) { mDisplayRect.set(0, 0, d.getIntrinsicWidth(), diff --git a/sample/build.gradle b/sample/build.gradle index 51f3e044..802cbf7c 100755 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -21,4 +21,6 @@ dependencies { implementation "com.android.support:recyclerview-v7:$supportLibVersion" implementation 'com.squareup.picasso:picasso:2.5.2' implementation project(':photoview') + + implementation 'com.facebook.fresco:fresco:1.3.0' } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index bd813a3f..d6e0ac10 100755 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -31,6 +31,9 @@ + + + diff --git a/sample/src/main/java/com/github/chrisbanes/photoview/sample/FrescoSampleActivity.java b/sample/src/main/java/com/github/chrisbanes/photoview/sample/FrescoSampleActivity.java new file mode 100755 index 00000000..9af6d397 --- /dev/null +++ b/sample/src/main/java/com/github/chrisbanes/photoview/sample/FrescoSampleActivity.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * Copyright 2011, 2012 Chris Banes. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ +package com.github.chrisbanes.photoview.sample; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.facebook.drawee.drawable.ScalingUtils; +import com.github.chrisbanes.photoview.OnMatrixChangedListener; +import com.github.chrisbanes.photoview.OnPhotoTapListener; +import com.github.chrisbanes.photoview.OnSingleFlingListener; +import com.github.chrisbanes.photoview.sample.fresco.PhotoDraweeView; + +import java.util.Random; + + +public class FrescoSampleActivity extends AppCompatActivity { + + static final String PHOTO_TAP_TOAST_STRING = "Photo Tap! X: %.2f %% Y:%.2f %% ID: %d"; + static final String SCALE_TOAST_STRING = "Scaled to: %.2ff"; + static final String FLING_LOG_STRING = "Fling velocityX: %.2f, velocityY: %.2f"; + + private PhotoDraweeView mPhotoView; + private TextView mCurrMatrixTv; + + private Toast mCurrentToast; + + private Matrix mCurrentDisplayMatrix = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_fresco_simple_sample); + + Toolbar toolbar = findViewById(R.id.toolbar); + toolbar.setTitle("Simple Sample"); + toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + toolbar.inflateMenu(R.menu.main_menu); + toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_zoom_toggle: + mPhotoView.setZoomable(!mPhotoView.isZoomEnabled()); + item.setTitle(mPhotoView.isZoomEnabled() ? R.string.menu_zoom_disable : R.string.menu_zoom_enable); + return true; + + case R.id.menu_scale_fit_center: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER); + return true; + + case R.id.menu_scale_fit_start: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_START); + return true; + + case R.id.menu_scale_fit_end: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_END); + return true; + + case R.id.menu_scale_fit_xy: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_XY); + return true; + + case R.id.menu_scale_scale_center: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.CENTER); + return true; + + case R.id.menu_scale_scale_center_crop: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP); + return true; + + case R.id.menu_scale_scale_center_inside: + mPhotoView.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.CENTER_INSIDE); + return true; + + case R.id.menu_scale_random_animate: + case R.id.menu_scale_random: + Random r = new Random(); + + float minScale = mPhotoView.getMinimumScale(); + float maxScale = mPhotoView.getMaximumScale(); + float randomScale = minScale + (r.nextFloat() * (maxScale - minScale)); + mPhotoView.setScale(randomScale, item.getItemId() == R.id.menu_scale_random_animate); + + showToast(String.format(SCALE_TOAST_STRING, randomScale)); + + return true; + case R.id.menu_matrix_restore: + if (mCurrentDisplayMatrix == null) + showToast("You need to capture display matrix first"); + else + mPhotoView.setDisplayMatrix(mCurrentDisplayMatrix); + return true; + case R.id.menu_matrix_capture: + mCurrentDisplayMatrix = new Matrix(); + mPhotoView.getDisplayMatrix(mCurrentDisplayMatrix); + return true; + } + return false; + } + }); + mPhotoView = findViewById(R.id.iv_photo); + mCurrMatrixTv = findViewById(R.id.tv_current_matrix); + +// Drawable bitmap = ContextCompat.getDrawable(this, R.drawable.wallpaper); +// mPhotoView.setImageDrawable(bitmap); + mPhotoView.setImageURI(Uri.parse("http://imgsrc.baidu.com/imgad/pic/item/7dd98d1001e93901cf713c2d71ec54e736d196b6.jpg")); + // Lets attach some listeners, not required though! + mPhotoView.setOnMatrixChangeListener(new MatrixChangeListener()); + mPhotoView.setOnPhotoTapListener(new PhotoTapListener()); + mPhotoView.setOnSingleFlingListener(new SingleFlingListener()); + } + + private class PhotoTapListener implements OnPhotoTapListener { + + @Override + public void onPhotoTap(ImageView view, float x, float y) { + float xPercentage = x * 100f; + float yPercentage = y * 100f; + + showToast(String.format(PHOTO_TAP_TOAST_STRING, xPercentage, yPercentage, view == null ? 0 : view.getId())); + } + } + + private void showToast(CharSequence text) { + if (mCurrentToast != null) { + mCurrentToast.cancel(); + } + + mCurrentToast = Toast.makeText(FrescoSampleActivity.this, text, Toast.LENGTH_SHORT); + mCurrentToast.show(); + } + + private class MatrixChangeListener implements OnMatrixChangedListener { + + @Override + public void onMatrixChanged(RectF rect) { + mCurrMatrixTv.setText(rect.toString()); + } + } + + private class SingleFlingListener implements OnSingleFlingListener { + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + Log.d("PhotoView", String.format(FLING_LOG_STRING, velocityX, velocityY)); + return true; + } + } +} diff --git a/sample/src/main/java/com/github/chrisbanes/photoview/sample/LauncherActivity.java b/sample/src/main/java/com/github/chrisbanes/photoview/sample/LauncherActivity.java index 9732861a..5cca8c40 100755 --- a/sample/src/main/java/com/github/chrisbanes/photoview/sample/LauncherActivity.java +++ b/sample/src/main/java/com/github/chrisbanes/photoview/sample/LauncherActivity.java @@ -27,6 +27,8 @@ import android.view.ViewGroup; import android.widget.TextView; +import com.facebook.drawee.backends.pipeline.Fresco; + public class LauncherActivity extends AppCompatActivity { public static final String[] options = { @@ -35,13 +37,17 @@ public class LauncherActivity extends AppCompatActivity { "Rotation Sample", "Picasso Sample", "Activity Transition Sample", - "Immersive Sample" + "Immersive Sample", + "Fresco Sample" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_launcher); + + Fresco.initialize(getApplicationContext()); + Toolbar toolbar = findViewById(R.id.toolbar); toolbar.setTitle(R.string.app_name); RecyclerView recyclerView = findViewById(R.id.list); @@ -78,6 +84,8 @@ public void onClick(View v) { break; case 5: clazz = ImmersiveActivity.class; + case 6: + clazz = FrescoSampleActivity.class; } Context context = holder.itemView.getContext(); diff --git a/sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/DraweeViewAttacher.java b/sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/DraweeViewAttacher.java new file mode 100644 index 00000000..9d36064d --- /dev/null +++ b/sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/DraweeViewAttacher.java @@ -0,0 +1,32 @@ +package com.github.chrisbanes.photoview.sample.fresco; + +import android.graphics.Matrix; +import android.graphics.RectF; + +import com.facebook.drawee.view.GenericDraweeView; +import com.github.chrisbanes.photoview.PhotoViewAttacher; + +/******************************************************************************* + * Description: Extend PhotoViewAttacher to support Fresco. + * + * Author: Freeman + * + * Date: 2018/9/7 + *******************************************************************************/ +public class DraweeViewAttacher extends PhotoViewAttacher { + + private GenericDraweeView imageView; + + public DraweeViewAttacher(GenericDraweeView image) { + super(image); + this.imageView = image; + } + + @Override + protected RectF getDisplayRect(Matrix matrix) { + RectF displayRect = new RectF(); + imageView.getHierarchy().getActualImageBounds(displayRect); + matrix.mapRect(displayRect); + return displayRect; + } +} diff --git a/sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/PhotoDraweeView.java b/sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/PhotoDraweeView.java new file mode 100644 index 00000000..17ab6232 --- /dev/null +++ b/sample/src/main/java/com/github/chrisbanes/photoview/sample/fresco/PhotoDraweeView.java @@ -0,0 +1,269 @@ +package com.github.chrisbanes.photoview.sample.fresco; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.View; +import android.widget.ImageView; + +import com.facebook.drawee.drawable.ScalingUtils; +import com.facebook.drawee.view.SimpleDraweeView; +import com.github.chrisbanes.photoview.OnMatrixChangedListener; +import com.github.chrisbanes.photoview.OnOutsidePhotoTapListener; +import com.github.chrisbanes.photoview.OnPhotoTapListener; +import com.github.chrisbanes.photoview.OnScaleChangedListener; +import com.github.chrisbanes.photoview.OnSingleFlingListener; +import com.github.chrisbanes.photoview.OnViewDragListener; +import com.github.chrisbanes.photoview.OnViewTapListener; +import com.github.chrisbanes.photoview.PhotoViewAttacher; + +/******************************************************************************* + * Description: Create PhotoDraweeView to support Fresco. + * + * Compare to PhotoView, just added onDraw and used PhotoViewAttacher. + * + * Author: Freeman + * + * Date: 2018/9/7 + *******************************************************************************/ +public class PhotoDraweeView extends SimpleDraweeView { + + private PhotoViewAttacher attacher; + private ImageView.ScaleType pendingScaleType; + + public PhotoDraweeView(Context context) { + this(context, null); + } + + public PhotoDraweeView(Context context, AttributeSet attr) { + this(context, attr, 0); + } + + public PhotoDraweeView(Context context, AttributeSet attr, int defStyle) { + super(context, attr, defStyle); + init(); + } + + private void init() { + attacher = new DraweeViewAttacher(this); + getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER); + //We always pose as a Matrix scale type, though we can change to another scale type + //via the attacher + super.setScaleType(ImageView.ScaleType.MATRIX); + //apply the previously applied scale type + if (pendingScaleType != null) { + setScaleType(pendingScaleType); + pendingScaleType = null; + } + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.concat(attacher.getImageMatrix()); + super.onDraw(canvas); + } + + /** + * Get the current {@link PhotoViewAttacher} for this view. Be wary of holding on to references + * to this attacher, as it has a reference to this view, which, if a reference is held in the + * wrong place, can cause memory leaks. + * + * @return the attacher. + */ + public PhotoViewAttacher getAttacher() { + return attacher; + } + + @Override + public ImageView.ScaleType getScaleType() { + return attacher.getScaleType(); + } + + @Override + public Matrix getImageMatrix() { + return attacher.getImageMatrix(); + } + + @Override + public void setOnLongClickListener(View.OnLongClickListener l) { + attacher.setOnLongClickListener(l); + } + + @Override + public void setOnClickListener(View.OnClickListener l) { + attacher.setOnClickListener(l); + } + + @Override + public void setScaleType(ImageView.ScaleType scaleType) { + if (attacher == null) { + pendingScaleType = scaleType; + } else { + attacher.setScaleType(scaleType); + } + } + + @Override + public void setImageDrawable(Drawable drawable) { + super.setImageDrawable(drawable); + // setImageBitmap calls through to this method + if (attacher != null) { + attacher.update(); + } + } + + @Override + public void setImageResource(int resId) { + super.setImageResource(resId); + if (attacher != null) { + attacher.update(); + } + } + + @Override + public void setImageURI(Uri uri) { + super.setImageURI(uri); + if (attacher != null) { + attacher.update(); + } + } + + @Override + protected boolean setFrame(int l, int t, int r, int b) { + boolean changed = super.setFrame(l, t, r, b); + if (changed) { + attacher.update(); + } + return changed; + } + + public void setRotationTo(float rotationDegree) { + attacher.setRotationTo(rotationDegree); + } + + public void setRotationBy(float rotationDegree) { + attacher.setRotationBy(rotationDegree); + } + + @Deprecated + public boolean isZoomEnabled() { + return attacher.isZoomEnabled(); + } + + public boolean isZoomable() { + return attacher.isZoomable(); + } + + public void setZoomable(boolean zoomable) { + attacher.setZoomable(zoomable); + } + + public RectF getDisplayRect() { + return attacher.getDisplayRect(); + } + + public void getDisplayMatrix(Matrix matrix) { + attacher.getDisplayMatrix(matrix); + } + + public boolean setDisplayMatrix(Matrix finalRectangle) { + return attacher.setDisplayMatrix(finalRectangle); + } + + public void getSuppMatrix(Matrix matrix) { + attacher.getSuppMatrix(matrix); + } + + public boolean setSuppMatrix(Matrix matrix) { + return attacher.setDisplayMatrix(matrix); + } + + public float getMinimumScale() { + return attacher.getMinimumScale(); + } + + public float getMediumScale() { + return attacher.getMediumScale(); + } + + public float getMaximumScale() { + return attacher.getMaximumScale(); + } + + public float getScale() { + return attacher.getScale(); + } + + public void setAllowParentInterceptOnEdge(boolean allow) { + attacher.setAllowParentInterceptOnEdge(allow); + } + + public void setMinimumScale(float minimumScale) { + attacher.setMinimumScale(minimumScale); + } + + public void setMediumScale(float mediumScale) { + attacher.setMediumScale(mediumScale); + } + + public void setMaximumScale(float maximumScale) { + attacher.setMaximumScale(maximumScale); + } + + public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) { + attacher.setScaleLevels(minimumScale, mediumScale, maximumScale); + } + + public void setOnMatrixChangeListener(OnMatrixChangedListener listener) { + attacher.setOnMatrixChangeListener(listener); + } + + public void setOnPhotoTapListener(OnPhotoTapListener listener) { + attacher.setOnPhotoTapListener(listener); + } + + public void setOnOutsidePhotoTapListener(OnOutsidePhotoTapListener listener) { + attacher.setOnOutsidePhotoTapListener(listener); + } + + public void setOnViewTapListener(OnViewTapListener listener) { + attacher.setOnViewTapListener(listener); + } + + public void setOnViewDragListener(OnViewDragListener listener) { + attacher.setOnViewDragListener(listener); + } + + public void setScale(float scale) { + attacher.setScale(scale); + } + + public void setScale(float scale, boolean animate) { + attacher.setScale(scale, animate); + } + + public void setScale(float scale, float focalX, float focalY, boolean animate) { + attacher.setScale(scale, focalX, focalY, animate); + } + + public void setZoomTransitionDuration(int milliseconds) { + attacher.setZoomTransitionDuration(milliseconds); + } + + public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener) { + attacher.setOnDoubleTapListener(onDoubleTapListener); + } + + public void setOnScaleChangeListener(OnScaleChangedListener onScaleChangedListener) { + attacher.setOnScaleChangeListener(onScaleChangedListener); + } + + public void setOnSingleFlingListener(OnSingleFlingListener onSingleFlingListener) { + attacher.setOnSingleFlingListener(onSingleFlingListener); + } +} diff --git a/sample/src/main/res/layout/activity_fresco_simple_sample.xml b/sample/src/main/res/layout/activity_fresco_simple_sample.xml new file mode 100755 index 00000000..b6ce8310 --- /dev/null +++ b/sample/src/main/res/layout/activity_fresco_simple_sample.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + \ No newline at end of file