diff --git a/BigImageViewer/src/main/java/com/github/piasy/biv/view/BigImageView.java b/BigImageViewer/src/main/java/com/github/piasy/biv/view/BigImageView.java index cd3cba4..6abd2de 100644 --- a/BigImageViewer/src/main/java/com/github/piasy/biv/view/BigImageView.java +++ b/BigImageViewer/src/main/java/com/github/piasy/biv/view/BigImageView.java @@ -98,7 +98,10 @@ public class BigImageView extends FrameLayout implements ImageLoader.Callback { private View mProgressIndicatorView; private ImageView mFailureImageView; + private boolean mDelayMainImage = false; + private ImageSaveCallback mImageSaveCallback; + private ImageShownCallback mImageShownCallback; private ImageLoader.Callback mUserCallback; private File mCurrentImageFile; private Uri mUri; @@ -286,6 +289,10 @@ public void setImageSaveCallback(ImageSaveCallback imageSaveCallback) { mImageSaveCallback = imageSaveCallback; } + public void setImageShownCallback(ImageShownCallback imageCycleCallback) { + mImageShownCallback = imageCycleCallback; + } + public void setProgressIndicator(ProgressIndicator progressIndicator) { mProgressIndicator = progressIndicator; } @@ -342,17 +349,34 @@ public void showImage(Uri uri) { } public void showImage(final Uri thumbnail, final Uri uri) { + showImage(thumbnail, uri, false); + } + + public void showImage(final Uri thumbnail, final Uri uri, final boolean delayMainImage) { mThumbnail = thumbnail; mUri = uri; clearThumbnailAndProgressIndicator(); - mImageLoader.loadImage(hashCode(), uri, mInternalCallback); + + mDelayMainImage = delayMainImage; + if (mDelayMainImage) { + BigImageViewer.prefetch(uri); + mImageLoader.loadImage(hashCode(), thumbnail, mInternalCallback); + } else { + mImageLoader.loadImage(hashCode(), uri, mInternalCallback); + } if (mFailureImageView != null) { mFailureImageView.setVisibility(GONE); } } + public void loadMainImageNow() { + + mDelayMainImage = false; + mImageLoader.loadImage(hashCode(), mUri, mInternalCallback); + } + public void cancel() { mImageLoader.cancel(hashCode()); } @@ -362,9 +386,9 @@ public SubsamplingScaleImageView getSSIV() { } @Override - public void onCacheHit(final int imageType, File image) { + public void onCacheHit(final int imageType, final File image) { mCurrentImageFile = image; - doShowImage(imageType, image); + doShowImage(imageType, image, mDelayMainImage); if (mUserCallback != null) { mUserCallback.onCacheHit(imageType, image); @@ -375,7 +399,7 @@ public void onCacheHit(final int imageType, File image) { public void onCacheMiss(final int imageType, final File image) { mCurrentImageFile = image; mTempImages.add(image); - doShowImage(imageType, image); + doShowImage(imageType, image, mDelayMainImage); if (mUserCallback != null) { mUserCallback.onCacheMiss(imageType, image); @@ -502,32 +526,63 @@ public void onAnimationRepeat(Animation animation) { } @UiThread - private void doShowImage(final int imageType, final File image) { - if (mMainView != null) { - removeView(mMainView); - } + private void doShowImage(final int imageType, final File image, final boolean useThumbnailView) { - mMainView = mViewFactory.createMainView(getContext(), imageType, image, mInitScaleType); - if (mMainView == null) { - onFail(new RuntimeException("Image type not supported: " - + ImageInfoExtractor.typeName(imageType))); - return; - } + if (useThumbnailView) { + + if(mThumbnailView != null) { + removeView(mThumbnailView); + } - addView(mMainView, ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - mMainView.setOnClickListener(mOnClickListener); - mMainView.setOnLongClickListener(mOnLongClickListener); + mThumbnailView = mViewFactory.createThumbnailView(getContext(), Uri.fromFile(image), mThumbnailScaleType); + if (mThumbnailView != null) { + + addView(mThumbnailView, ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mThumbnailView.setOnClickListener(mOnClickListener); + mThumbnailView.setOnLongClickListener(mOnLongClickListener); + + ((ImageView) mThumbnailView).setAdjustViewBounds(true); + ((ImageView) mThumbnailView).setScaleType(ImageView.ScaleType.FIT_START); + ((ImageView) mThumbnailView).setImageURI(Uri.fromFile(image)); + + if (mImageShownCallback != null) { + mImageShownCallback.onThumbnailShown(); + } + } + + } else { + + if (mMainView != null) { + removeView(mMainView); + } + + mMainView = mViewFactory.createMainView(getContext(), imageType, image, mInitScaleType); + if (mMainView == null) { + onFail(new RuntimeException("Image type not supported: " + + ImageInfoExtractor.typeName(imageType))); + return; + } - if (mMainView instanceof SubsamplingScaleImageView) { - mSSIV = (SubsamplingScaleImageView) mMainView; + addView(mMainView, ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mMainView.setOnClickListener(mOnClickListener); + mMainView.setOnLongClickListener(mOnLongClickListener); - mSSIV.setMinimumTileDpi(160); + if (mMainView instanceof SubsamplingScaleImageView) { + mSSIV = (SubsamplingScaleImageView) mMainView; - setOptimizeDisplay(mOptimizeDisplay); - setInitScaleType(mInitScaleType); + mSSIV.setMinimumTileDpi(160); - mSSIV.setImage(ImageSource.uri(Uri.fromFile(image))); + setOptimizeDisplay(mOptimizeDisplay); + setInitScaleType(mInitScaleType); + + mSSIV.setImage(ImageSource.uri(Uri.fromFile(image))); + + if (mImageShownCallback != null) { + mImageShownCallback.onMainImageShown(); + } + } } if (mFailureImageView != null) { diff --git a/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageShownCallback.java b/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageShownCallback.java new file mode 100644 index 0000000..54714de --- /dev/null +++ b/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageShownCallback.java @@ -0,0 +1,10 @@ +package com.github.piasy.biv.view; + +import androidx.annotation.UiThread; + +@UiThread +public interface ImageShownCallback { + + void onThumbnailShown(); + void onMainImageShown(); +} diff --git a/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageViewFactory.java b/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageViewFactory.java index 2f6d187..20803c8 100644 --- a/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageViewFactory.java +++ b/BigImageViewer/src/main/java/com/github/piasy/biv/view/ImageViewFactory.java @@ -60,6 +60,6 @@ protected View createAnimatedImageView(Context context, int imageType, File imag } public View createThumbnailView(Context context, Uri thumbnail, ImageView.ScaleType scaleType) { - return null; + return new ImageView(context); } } diff --git a/app/build.gradle b/app/build.gradle index 4600af6..5f02a2d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,7 @@ apply plugin: 'com.android.application' apply plugin: 'com.github.ben-manes.versions' +apply plugin: 'kotlin-android' android { compileSdkVersion rootProject.ext.androidCompileSdkVersion @@ -72,8 +73,9 @@ android { } dependencies { + implementation "androidx.core:core-ktx:1.1.0" implementation "androidx.appcompat:appcompat:1.1.0" - implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.recyclerview:recyclerview:1.1.0-beta05" implementation "com.google.android.material:material:$materialVersion" implementation('com.tbruyelle.rxpermissions2:rxpermissions:0.9.5') { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 44603d1..cc812da 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,8 +23,7 @@ ~ SOFTWARE. --> + package="com.github.piasy.biv.example"> @@ -52,6 +51,8 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/github/piasy/biv/example/FirstAnimActivity.kt b/app/src/main/java/com/github/piasy/biv/example/FirstAnimActivity.kt new file mode 100644 index 0000000..fd68665 --- /dev/null +++ b/app/src/main/java/com/github/piasy/biv/example/FirstAnimActivity.kt @@ -0,0 +1,31 @@ +package com.github.piasy.biv.example + +import android.os.Bundle +import android.widget.ImageView +import androidx.appcompat.app.AppCompatActivity +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy + +class FirstAnimActivity : AppCompatActivity() { + + companion object { + private const val THUMB_URL = "https://preview.redd.it/nahhvcadsbo21.jpg?width=216&crop=smart&auto=webp&s=c560e5774d7f43e178c1f0faad09315cdb86c203" + private const val SOURCE_URL = "https://i.redd.it/nahhvcadsbo21.jpg" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_anim_first) + + val thumb = findViewById(R.id.thumbView) + thumb.setOnClickListener { + + SecondAnimActivity.start(this, thumb, THUMB_URL, SOURCE_URL) + } + + val glide = Glide.with(this) + glide.asBitmap() + .load(THUMB_URL) + .into(thumb) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/piasy/biv/example/LongImageActivity.java b/app/src/main/java/com/github/piasy/biv/example/LongImageActivity.java index 0c7591e..3e48693 100644 --- a/app/src/main/java/com/github/piasy/biv/example/LongImageActivity.java +++ b/app/src/main/java/com/github/piasy/biv/example/LongImageActivity.java @@ -25,14 +25,16 @@ package com.github.piasy.biv.example; import android.Manifest; -import android.app.Dialog; import android.net.Uri; import android.os.Bundle; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import com.github.piasy.biv.BigImageViewer; @@ -55,7 +57,7 @@ public class LongImageActivity extends AppCompatActivity { private Disposable mPermissionRequest; private Disposable mQrCodeDecode; - private Dialog dialog; + private AlertDialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { @@ -73,36 +75,13 @@ public void onClick(View v) { } }); - dialog = new Dialog(this); - dialog.setTitle(R.string.long_click_actions); - dialog.setContentView(R.layout.dialog_long_image); - - final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); - lp.copyFrom(dialog.getWindow().getAttributes()); - lp.width = WindowManager.LayoutParams.MATCH_PARENT; - dialog.getWindow().setAttributes(lp); - - final TextView textScan = dialog.findViewById(R.id.action_scan_qr); - final TextView textSave = dialog.findViewById(R.id.action_save_image); - - textScan.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - decodeQrCode(); - } - }); - - textSave.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - saveImage(); - } - }); - mBigImageView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { + + dialog = showDialog(); dialog.show(); + return true; } }); @@ -141,10 +120,6 @@ protected void onDestroy() { disposePermissionRequest(); disposeQrCodeDecode(); - if (dialog.isShowing()) { - dialog.dismiss(); - } - BigImageViewer.imageLoader().cancelAll(); } @@ -195,6 +170,33 @@ public void accept(Throwable throwable) throws Exception { }); } + private AlertDialog showDialog() { + + final ViewGroup container = findViewById(R.id.container); + final AlertDialog.Builder builder = new AlertDialog.Builder(LongImageActivity.this); + final View rootView = LayoutInflater.from(LongImageActivity.this).inflate(R.layout.dialog_long_image, container, false); + builder.setView(rootView); + + final TextView textScan = rootView.findViewById(R.id.action_scan_qr); + final TextView textSave = rootView.findViewById(R.id.action_save_image); + + textScan.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + decodeQrCode(); + } + }); + + textSave.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + saveImage(); + } + }); + + return builder.create(); + } + private void disposePermissionRequest() { if (mPermissionRequest != null) { mPermissionRequest.dispose(); diff --git a/app/src/main/java/com/github/piasy/biv/example/MainActivity.java b/app/src/main/java/com/github/piasy/biv/example/MainActivity.java index 5c4a3ef..47b959f 100644 --- a/app/src/main/java/com/github/piasy/biv/example/MainActivity.java +++ b/app/src/main/java/com/github/piasy/biv/example/MainActivity.java @@ -84,5 +84,11 @@ public void onClick(View v) { startActivity(new Intent(MainActivity.this, ImageTypesActivity.class)); } }); + findViewById(R.id.mSharedTransition).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(MainActivity.this, FirstAnimActivity.class)); + } + }); } } diff --git a/app/src/main/java/com/github/piasy/biv/example/SecondAnimActivity.kt b/app/src/main/java/com/github/piasy/biv/example/SecondAnimActivity.kt new file mode 100644 index 0000000..6ea8bde --- /dev/null +++ b/app/src/main/java/com/github/piasy/biv/example/SecondAnimActivity.kt @@ -0,0 +1,101 @@ +package com.github.piasy.biv.example + +import android.app.Activity +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.transition.Transition +import android.util.Log +import android.view.MenuItem +import android.widget.ImageView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityOptionsCompat +import androidx.core.net.toUri +import com.github.piasy.biv.BigImageViewer +import com.github.piasy.biv.loader.glide.GlideImageLoader +import com.github.piasy.biv.view.BigImageView +import com.github.piasy.biv.view.ImageShownCallback + +class SecondAnimActivity : AppCompatActivity() { + + companion object { + + private const val THUMB_PARAM = "intent_param_thumbnail" + private const val SOURCE_PARAM = "intent_param_source" + + fun start(activity: Activity, imageView: ImageView, thumbUrl: String, sourceUrl: String) { + + val intent = Intent(activity, SecondAnimActivity::class.java) + intent.putExtra(THUMB_PARAM, thumbUrl) + intent.putExtra(SOURCE_PARAM, sourceUrl) + + val transitionName = activity.resources.getString(R.string.transition_name) + val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, imageView, transitionName) + val bundle = options.toBundle() + + if (Build.VERSION.SDK_INT >= 16) { + activity.startActivity(intent, bundle) + } else { + Log.i("SecondAnimActivity", "Animation not available for this SDK Versions.") + } + } + } + + private val thumbUrl by lazy { intent.getStringExtra(THUMB_PARAM)!! } + private val sourceUrl by lazy { intent.getStringExtra(SOURCE_PARAM)!! } + + private val biv by lazy { findViewById(R.id.sourceView) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) + + setContentView(R.layout.activity_anim_second) + + if (Build.VERSION.SDK_INT >= 21) { + window.sharedElementEnterTransition.addListener(object : Transition.TransitionListener { + + override fun onTransitionStart(transition: Transition?) {} + override fun onTransitionCancel(transition: Transition?) {} + override fun onTransitionPause(transition: Transition?) {} + override fun onTransitionResume(transition: Transition?) {} + + override fun onTransitionEnd(transition: Transition?) { + + biv.loadMainImageNow() + } + }) + } + + biv.setImageShownCallback(object : ImageShownCallback { + + override fun onThumbnailShown() { + showToast("onThumbnailShown triggered!") + } + + override fun onMainImageShown() { + showToast("onMainImageShown triggered!") + } + }) + + biv.showImage(thumbUrl.toUri(), sourceUrl.toUri(), true) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + + when(item.itemId) { + android.R.id.home -> { + supportFinishAfterTransition() + return true + } + } + + return super.onOptionsItemSelected(item) + } + + private fun showToast(text: String) { + Toast.makeText(this, text, Toast.LENGTH_SHORT).show() + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_anim_first.xml b/app/src/main/res/layout/activity_anim_first.xml new file mode 100644 index 0000000..c99d5a8 --- /dev/null +++ b/app/src/main/res/layout/activity_anim_first.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_anim_second.xml b/app/src/main/res/layout/activity_anim_second.xml new file mode 100644 index 0000000..38e56ca --- /dev/null +++ b/app/src/main/res/layout/activity_anim_second.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml index 456665d..b375f9a 100644 --- a/app/src/main/res/layout/activity_big_image.xml +++ b/app/src/main/res/layout/activity_big_image.xml @@ -1,24 +1,25 @@ + + - + app:optimizeDisplay="true" + app:failureImage="@drawable/ic_cloud_off_white" + app:failureImageInitScaleType="center" + />