diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index cc72de3..e0d5b93 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,45 +5,34 @@ - + - - - - - 1.8 - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b737894..82d0710 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 - buildToolsVersion '27.0.2' + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { applicationId "ch.ielse.demo.p02" - minSdkVersion 14 - targetSdkVersion 27 + minSdkVersion 15 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -19,8 +19,8 @@ android { } dependencies { - implementation 'com.android.support:appcompat-v7:27.0.2' - implementation 'com.android.support:recyclerview-v7:27.0.2' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support:recyclerview-v7:28.0.0' implementation 'com.github.bumptech.glide:glide:4.6.1' annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1' diff --git a/app/src/main/java/ch/ielse/demo/p02/CustomLoadingUIProvider2.java b/app/src/main/java/ch/ielse/demo/p02/CustomLoadingUIProvider2.java new file mode 100644 index 0000000..7951b3f --- /dev/null +++ b/app/src/main/java/ch/ielse/demo/p02/CustomLoadingUIProvider2.java @@ -0,0 +1,47 @@ +package ch.ielse.demo.p02; + +import android.content.Context; +import android.os.Handler; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.github.ielse.imagewatcher.ImageWatcher; + + +public class CustomLoadingUIProvider2 implements ImageWatcher.LoadingUIProvider { + private final FrameLayout.LayoutParams lpCenterInParent = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + private final Handler mHandler = new Handler(); + + private Runnable runDelayDisplay; + + @Override + public View initialView(Context context) { + ImageView load = new ImageView(context); + lpCenterInParent.gravity = Gravity.CENTER; + load.setLayoutParams(lpCenterInParent); + load.setImageResource(R.mipmap.loading); + return load; + } + + @Override + public void start(final View loadView) { + if (runDelayDisplay != null) mHandler.removeCallbacks(runDelayDisplay); + runDelayDisplay = new Runnable() { + @Override + public void run() { + loadView.setVisibility(View.VISIBLE); + } + }; + mHandler.postDelayed(runDelayDisplay, 500); + } + + @Override + public void stop(View loadView) { + if (runDelayDisplay != null) mHandler.removeCallbacks(runDelayDisplay); + runDelayDisplay = null; + loadView.setVisibility(View.GONE); + } +} diff --git a/app/src/main/java/ch/ielse/demo/p02/DecorationLayout.java b/app/src/main/java/ch/ielse/demo/p02/DecorationLayout.java new file mode 100644 index 0000000..abc2346 --- /dev/null +++ b/app/src/main/java/ch/ielse/demo/p02/DecorationLayout.java @@ -0,0 +1,93 @@ +package ch.ielse.demo.p02; + +import android.content.Context; +import android.net.Uri; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.github.ielse.imagewatcher.ImageWatcher; +import com.github.ielse.imagewatcher.ImageWatcherHelper; + +public class DecorationLayout extends FrameLayout implements ViewPager.OnPageChangeListener, View.OnClickListener { + + private ImageWatcherHelper mHolder; + private TextView vDisplayOrigin; + private View vDownload; + private int currentPosition; + private int mPagerPositionOffsetPixels; + + public DecorationLayout(Context context) { + super(context); + final FrameLayout vContainer = (FrameLayout) LayoutInflater.from(context).inflate(R.layout.layout_watcher_decoration, this); + vDisplayOrigin = vContainer.findViewById(R.id.vDisplayOrigin); + vDisplayOrigin.setOnClickListener(this); + vDownload = vContainer.findViewById(R.id.vDownload); + vDownload.setOnClickListener(this); + + } + + public void attachImageWatcher(ImageWatcherHelper iwHelper) { + mHolder = iwHelper; + } + + + @Override + public void onClick(View v) { + if (mPagerPositionOffsetPixels != 0) return; + + if (v.getId() == R.id.vDownload) { + final int clickPosition = currentPosition; + Toast.makeText(v.getContext().getApplicationContext(), "download [" + clickPosition + "] ", Toast.LENGTH_SHORT).show(); + } else if (v.getId() == R.id.vDisplayOrigin) { + final int clickPosition = currentPosition; + Toast.makeText(v.getContext().getApplicationContext(), "display origin [" + clickPosition + "]", Toast.LENGTH_SHORT).show(); + Uri newUri = Uri.parse("https://pub-static.haozhaopian.net/static/web/site/features/cn/crop/images/crop_20a7dc7fbd29d679b456fa0f77bd9525d.jpg"); + notifyAdapterItemChanged(clickPosition, newUri); + + } + } + + @Override + public void onPageScrolled(int i, float v, int i1) { + mPagerPositionOffsetPixels = i1; + notifyAlphaChanged(v); + // setAlpha(1 - v); + } + + @Override + public void onPageSelected(int i) { + currentPosition = i; + } + + @Override + public void onPageScrollStateChanged(int i) { + + } + + private void notifyAdapterItemChanged(int position, Uri newUri) { + if (mHolder != null) { + final ImageWatcher iw = mHolder.getImageWatcher(); + if (iw != null) { + iw.notifyItemChanged(position, newUri); + } + } + } + + private void notifyAlphaChanged(float p) { + if (0 < p && p <= 0.2f) { + float r = (0.2f - p) * 5; + setAlpha(r); + } else if (0.8f <= p && p < 1) { + float r = (p - 0.8f) * 5; + setAlpha(r); + } else if (p == 0) { + setAlpha(1f); + } else { + setAlpha(0f); + } + } +} diff --git a/app/src/main/java/ch/ielse/demo/p02/MainActivity.java b/app/src/main/java/ch/ielse/demo/p02/MainActivity.java index b05e59b..987ef67 100644 --- a/app/src/main/java/ch/ielse/demo/p02/MainActivity.java +++ b/app/src/main/java/ch/ielse/demo/p02/MainActivity.java @@ -64,7 +64,7 @@ public void onClick(View v) { // 长按图片的回调,你可以显示一个框继续提供一些复制,发送等功能 vImageWatcher.setOnPictureLongPressListener(this); vImageWatcher.setLoader(new GlideSimpleLoader()); - vImageWatcher.setOnStateChangedListener(new ImageWatcher.OnStateChangedListener() { + vImageWatcher.addOnStateChangedListener(new ImageWatcher.OnStateChangedListener() { @Override public void onStateChangeUpdate(ImageWatcher imageWatcher, ImageView clicked, int position, Uri uri, float animatedValue, int actionTag) { Log.e("IW", "onStateChangeUpdate [" + position + "][" + uri + "][" + animatedValue + "][" + actionTag + "]"); diff --git a/app/src/main/java/ch/ielse/demo/p02/MainActivity2.java b/app/src/main/java/ch/ielse/demo/p02/MainActivity2.java index e08c5c9..0017284 100644 --- a/app/src/main/java/ch/ielse/demo/p02/MainActivity2.java +++ b/app/src/main/java/ch/ielse/demo/p02/MainActivity2.java @@ -26,6 +26,8 @@ public class MainActivity2 extends Activity implements MessagePicturesLayout.Cal private RecyclerView vRecycler; private MessageAdapter adapter; + private DecorationLayout layDecoration; + @Override protected void onCreate(Bundle savedInstanceState) { boolean isTranslucentStatus = false; @@ -40,6 +42,7 @@ protected void onCreate(Bundle savedInstanceState) { } super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); + layDecoration = new DecorationLayout(this); vRecycler = (RecyclerView) findViewById(R.id.v_recycler); vRecycler.setLayoutManager(new LinearLayoutManager(this)); @@ -74,7 +77,12 @@ public void onStateChanged(ImageWatcher imageWatcher, int position, Uri uri, int } } }) - .setLoadingUIProvider(new CustomLoadingUIProvider()); // 自定义LoadingUI + .setOtherView(layDecoration) + .addOnPageChangeListener(layDecoration) + .setLoadingUIProvider(new CustomLoadingUIProvider2()); // 自定义LoadingUI + + + layDecoration.attachImageWatcher(iwHelper); Utils.fitsSystemWindows(isTranslucentStatus, findViewById(R.id.v_fit)); diff --git a/app/src/main/java/ch/ielse/demo/p02/MainActivity4.java b/app/src/main/java/ch/ielse/demo/p02/MainActivity4.java index 0efdc99..a45df49 100644 --- a/app/src/main/java/ch/ielse/demo/p02/MainActivity4.java +++ b/app/src/main/java/ch/ielse/demo/p02/MainActivity4.java @@ -66,7 +66,8 @@ public void onClick(View v) { iwHelper = ImageWatcherHelper.with(this, new GlideSimpleLoader()) // 一般来讲, ImageWatcher 需要占据全屏的位置 - .setIndexProvider(new CustomDotIndexProvider()); // 自定义index + .setIndexProvider(new CustomDotIndexProvider()) // 自定义index + .setLoadingUIProvider(new CustomLoadingUIProvider()); // 骰子loading } diff --git a/app/src/main/res/drawable/b_white_ffffff_stroke_round_3_shape.xml b/app/src/main/res/drawable/b_white_ffffff_stroke_round_3_shape.xml new file mode 100644 index 0000000..3b6a250 --- /dev/null +++ b/app/src/main/res/drawable/b_white_ffffff_stroke_round_3_shape.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/app/src/main/res/layout/layout_watcher_decoration.xml b/app/src/main/res/layout/layout_watcher_decoration.xml new file mode 100644 index 0000000..33a56f5 --- /dev/null +++ b/app/src/main/res/layout/layout_watcher_decoration.xml @@ -0,0 +1,32 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxhdpi/download.png b/app/src/main/res/mipmap-xxhdpi/download.png new file mode 100755 index 0000000..a1c8a89 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/download.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/loading.png b/app/src/main/res/mipmap-xxhdpi/loading.png new file mode 100644 index 0000000..74a47f3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/loading.png differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 922a100..9602a69 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ ImageWatcher + diff --git a/build.gradle b/build.gradle index 4c2a261..a687f8c 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { maven { url 'https://maven.google.com' } } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8098292..4a105d6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/imagewatcher/build.gradle b/imagewatcher/build.gradle index 2218847..b2664e4 100644 --- a/imagewatcher/build.gradle +++ b/imagewatcher/build.gradle @@ -4,15 +4,14 @@ apply plugin: 'com.jfrog.bintray' android { - compileSdkVersion 27 - buildToolsVersion "27.0.2" + compileSdkVersion 28 resourcePrefix "imagewatcher__" defaultConfig { - minSdkVersion 14 - targetSdkVersion 27 - versionCode 7 - versionName "1.1.4" + minSdkVersion 15 + targetSdkVersion 28 + versionCode 8 + versionName "1.1.5" } buildTypes { @@ -24,5 +23,5 @@ android { } dependencies { - implementation 'com.android.support:appcompat-v7:27.0.2' + implementation 'com.android.support:appcompat-v7:28.0.0' } \ No newline at end of file diff --git a/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcher.java b/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcher.java index d4b5734..c3ce6da 100644 --- a/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcher.java +++ b/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcher.java @@ -9,7 +9,6 @@ import android.content.Context; import android.graphics.Color; import android.graphics.drawable.Animatable; -import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; @@ -34,11 +33,13 @@ import android.widget.TextView; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.List; public class ImageWatcher extends FrameLayout implements GestureDetector.OnGestureListener, ViewPager.OnPageChangeListener { private static final int SINGLE_TAP_UP_CONFIRMED = 1; private static final int DATA_INITIAL = 2; + public static final int STATE_ENTER_DISPLAYING = 3; public static final int STATE_EXIT_HIDING = 4; private final Handler mHandler; @@ -90,10 +91,11 @@ public class ImageWatcher extends FrameLayout implements GestureDetector.OnGestu private int currentPosition; private int mPagerPositionOffsetPixels; // viewpager当前在屏幕上偏移量 private Loader loader; // 图片加载者 - private OnStateChangedListener stateChangedListener; + private final List onStateChangedListeners = new ArrayList<>(); private IndexProvider indexProvider; // 索引ui接口 private View idxView; // 索引ui private LoadingUIProvider loadingUIProvider; // 加载ui + private final List onPageChangeListeners = new ArrayList<>(); private boolean detachAffirmative; // dismiss detach parent 退出查看大图模式后,立即释放内存 private boolean detachedParent; @@ -110,7 +112,6 @@ public ImageWatcher(Context context, AttributeSet attrs) { addView(vPager = new ViewPager(context)); vPager.addOnPageChangeListener(this); setVisibility(View.INVISIBLE); - setIndexProvider(new DefaultIndexProvider()); setLoadingUIProvider(new DefaultLoadingUIProvider()); } @@ -136,14 +137,22 @@ public void setLoadingUIProvider(LoadingUIProvider lp) { loadingUIProvider = lp; } - public void setOnStateChangedListener(OnStateChangedListener changedListener) { - stateChangedListener = changedListener; + public void addOnStateChangedListener(OnStateChangedListener listener) { + if (!onStateChangedListeners.contains(listener)) { + onStateChangedListeners.add(listener); + } } public void setOnPictureLongPressListener(OnPictureLongPressListener listener) { pictureLongPressListener = listener; } + public void addOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + if (!onPageChangeListeners.contains(listener)) { + onPageChangeListeners.add(listener); + } + } + public interface Loader { void load(Context context, Uri uri, LoadCallback lc); } @@ -201,6 +210,7 @@ public interface LoadingUIProvider { public class DefaultLoadingUIProvider implements LoadingUIProvider { final LayoutParams lpCenterInParent = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + private Runnable runDelayDisplay; @Override public View initialView(Context context) { @@ -211,15 +221,30 @@ public View initialView(Context context) { } @Override - public void start(View loadView) { - loadView.setVisibility(View.VISIBLE); - ((ProgressView) loadView).start(); + public void start(final View loadView) { + if (runDelayDisplay != null) mHandler.removeCallbacks(runDelayDisplay); + runDelayDisplay = new Runnable() { + @Override + public void run() { + loadView.setVisibility(View.VISIBLE); + if (!((ProgressView) loadView).isRunning()) { + ((ProgressView) loadView).start(); + } + } + }; + mHandler.postDelayed(runDelayDisplay, 500); } @Override public void stop(View loadView) { - ((ProgressView) loadView).stop(); + if (runDelayDisplay != null) mHandler.removeCallbacks(runDelayDisplay); + runDelayDisplay = null; + + if (((ProgressView) loadView).isRunning()) { + ((ProgressView) loadView).stop(); + } loadView.setVisibility(View.GONE); + } } @@ -256,7 +281,7 @@ public void show(List urlList, int initPos) { * @param imageGroupList 被点击的ImageView的所在列表,加载图片时会提前展示列表中已经下载完成的thumb图片 * @param urlList 被加载的图片url列表,数量必须大于等于 imageGroupList.size。 且顺序应当和imageGroupList保持一致 */ - public void show(ImageView i, SparseArray imageGroupList, final List urlList) { + public boolean show(ImageView i, SparseArray imageGroupList, final List urlList) { if (i == null || imageGroupList == null || urlList == null) { throw new NullPointerException("i[" + i + "] imageGroupList[" + imageGroupList + "] urlList[" + urlList + "]"); } @@ -270,7 +295,10 @@ public void show(ImageView i, SparseArray imageGroupList, final List< if (initPosition < 0) { throw new IllegalArgumentException("param ImageView i must be a member of the List imageGroupList!"); } + + if (i.getDrawable() == null) return false; showInternal(i, imageGroupList, urlList); + return true; } private void showInternal(ImageView i, SparseArray imageGroupList, final List urlList) { @@ -278,8 +306,6 @@ private void showInternal(ImageView i, SparseArray imageGroupList, fi throw new NullPointerException("please invoke `setLoader` first [loader == null]"); } - if (i != null && i.getDrawable() == null) return; - if (!isInitLayout) { initI = i; initImageGroupList = imageGroupList; @@ -307,7 +333,22 @@ public int getCurrentPosition() { } public Uri getDisplayingUri() { - return mUrlList != null ? mUrlList.get(getCurrentPosition()) : null; + return getUri(getCurrentPosition()); + } + + public Uri getUri(int position) { + if (mUrlList == null || mUrlList.size() <= position || position < 0) { + return null; + } + return mUrlList.get(position); + } + + public void notifyItemChanged(int position, Uri newUri) { + if (mUrlList == null || mUrlList.size() <= position || position < 0) { + return; + } + mUrlList.set(position, newUri); + adapter.notifyItemChanged(position); } @Override @@ -839,6 +880,12 @@ private void handleExitTouchResult() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { mPagerPositionOffsetPixels = positionOffsetPixels; + + if (!onPageChangeListeners.isEmpty()) { + for (ViewPager.OnPageChangeListener onPageChangeListener : onPageChangeListeners) { + onPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } } /** @@ -860,11 +907,22 @@ public void onPageSelected(int position) { if (ViewState.read(mNext, ViewState.STATE_DEFAULT) != null) { ViewState.restoreByAnim(mNext, ViewState.STATE_DEFAULT).create().start(); } + + if (!onPageChangeListeners.isEmpty()) { + for (ViewPager.OnPageChangeListener onPageChangeListener : onPageChangeListeners) { + onPageChangeListener.onPageSelected(position); + } + } } @Override public void onPageScrollStateChanged(int state) { + if (!onPageChangeListeners.isEmpty()) { + for (ViewPager.OnPageChangeListener onPageChangeListener : onPageChangeListeners) { + onPageChangeListener.onPageScrollStateChanged(state); + } + } } class ImagePagerAdapter extends PagerAdapter { @@ -917,6 +975,74 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return view == object; } + void notifyItemChanged(final int position) { + final ImageView imageView = mImageSparseArray.get(position); + if (imageView != null) { + loader.load(imageView.getContext(), mUrlList.get(position), new LoadCallback() { + @Override + public void onResourceReady(Drawable resource) { + final int sourceDefaultWidth, sourceDefaultHeight, sourceDefaultTranslateX, sourceDefaultTranslateY; + int resourceImageWidth = resource.getIntrinsicWidth(); + int resourceImageHeight = resource.getIntrinsicHeight(); + if (resourceImageWidth * 1f / resourceImageHeight > mWidth * 1f / mHeight) { + sourceDefaultWidth = mWidth; + sourceDefaultHeight = (int) (sourceDefaultWidth * 1f / resourceImageWidth * resourceImageHeight); + sourceDefaultTranslateX = 0; + sourceDefaultTranslateY = (mHeight - sourceDefaultHeight) / 2; + imageView.setTag(R.id.image_orientation, "horizontal"); + } else { + sourceDefaultWidth = mWidth; + sourceDefaultHeight = (int) (sourceDefaultWidth * 1f / resourceImageWidth * resourceImageHeight); + sourceDefaultTranslateX = 0; + sourceDefaultTranslateY = 0; + imageView.setTag(R.id.image_orientation, "vertical"); + } + imageView.setImageDrawable(resource); + notifyItemChangedState(position, false, false); + + ViewState vsDefault = ViewState.write(imageView, ViewState.STATE_DEFAULT).width(sourceDefaultWidth).height(sourceDefaultHeight) + .translationX(sourceDefaultTranslateX).translationY(sourceDefaultTranslateY); + + ViewState.restore(imageView, vsDefault.mTag); + imageView.setAlpha(1f); + imageView.animate().alpha(1).start(); + + imageView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + } + + @Override + public void onViewDetachedFromWindow(View v) { + Drawable displayingDrawable = imageView.getDrawable(); + if (displayingDrawable instanceof Animatable) { + ((Animatable) displayingDrawable).stop(); + } + } + }); + + Drawable displayingDrawable = imageView.getDrawable(); + if (displayingDrawable instanceof Animatable) { + if (!((Animatable) displayingDrawable).isRunning()) { + ((Animatable) displayingDrawable).start(); + } + } + } + + @Override + public void onLoadStarted(Drawable placeholder) { + notifyItemChangedState(position, true, false); + } + + @Override + public void onLoadFailed(Drawable errorDrawable) { + notifyItemChangedState(position, false, imageView.getDrawable() == null); + } + }); + } + + } + /** * 更新ViewPager中每项的当前状态,比如是否加载,比如是否加载失败 * @@ -1229,8 +1355,10 @@ public void onAnimationUpdate(ValueAnimator animation) { float p = (float) animation.getAnimatedValue(); setBackgroundColor(mColorEvaluator.evaluate(p, mCurrentBackgroundColor, colorResult)); - if (stateChangedListener != null) { - stateChangedListener.onStateChangeUpdate(ImageWatcher.this, iSource, getCurrentPosition(), getDisplayingUri(), p, tag); + if (!onStateChangedListeners.isEmpty()) { + for (OnStateChangedListener stateChangedListener : onStateChangedListeners) { + stateChangedListener.onStateChangeUpdate(ImageWatcher.this, iSource, getCurrentPosition(), getDisplayingUri(), p, tag); + } } } }); @@ -1238,18 +1366,22 @@ public void onAnimationUpdate(ValueAnimator animation) { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); - if (stateChangedListener != null) { + if (!onStateChangedListeners.isEmpty()) { if (tag == STATE_ENTER_DISPLAYING) { - stateChangedListener.onStateChanged(ImageWatcher.this, getCurrentPosition(), getDisplayingUri(), tag); + for (OnStateChangedListener stateChangedListener : onStateChangedListeners) { + stateChangedListener.onStateChanged(ImageWatcher.this, getCurrentPosition(), getDisplayingUri(), tag); + } } } } @Override public void onAnimationEnd(Animator animation) { - if (stateChangedListener != null) { + if (!onStateChangedListeners.isEmpty()) { if (tag == STATE_EXIT_HIDING) { - stateChangedListener.onStateChanged(ImageWatcher.this, getCurrentPosition(), getDisplayingUri(), tag); + for (OnStateChangedListener stateChangedListener : onStateChangedListeners) { + stateChangedListener.onStateChanged(ImageWatcher.this, getCurrentPosition(), getDisplayingUri(), tag); + } } } diff --git a/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcherHelper.java b/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcherHelper.java index fc083e9..e7e1549 100644 --- a/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcherHelper.java +++ b/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ImageWatcherHelper.java @@ -2,15 +2,19 @@ import android.app.Activity; import android.net.Uri; +import android.support.v4.view.ViewPager; +import android.util.Log; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; +import java.util.ArrayList; import java.util.List; public class ImageWatcherHelper { + private static final int VIEW_DECORATION_ID = R.id.view_decoration; private static final int VIEW_IMAGE_WATCHER_ID = R.id.view_image_watcher; private final Activity holder; private final ViewGroup activityDecorView; @@ -21,7 +25,10 @@ public class ImageWatcherHelper { private ImageWatcher.OnPictureLongPressListener listener; private ImageWatcher.IndexProvider indexProvider; private ImageWatcher.LoadingUIProvider loadingUIProvider; - private ImageWatcher.OnStateChangedListener onStateChangedListener; + private final List onPageChangeListeners = new ArrayList<>(); + private final List onStateChangedListeners = new ArrayList<>(); + private View otherView; + private ImageWatcherHelper(Activity activity) { holder = activity; @@ -51,6 +58,19 @@ public ImageWatcherHelper setOnPictureLongPressListener(ImageWatcher.OnPictureLo return this; } + + public ImageWatcherHelper addOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + if (!onPageChangeListeners.contains(listener)) { + onPageChangeListeners.add(listener); + } + return this; + } + + public ImageWatcherHelper setOtherView(View other) { + otherView = other; + return this; + } + public ImageWatcherHelper setIndexProvider(ImageWatcher.IndexProvider ip) { indexProvider = ip; return this; @@ -62,18 +82,24 @@ public ImageWatcherHelper setLoadingUIProvider(ImageWatcher.LoadingUIProvider lp } public ImageWatcherHelper setOnStateChangedListener(ImageWatcher.OnStateChangedListener listener) { - onStateChangedListener = listener; + if (!onStateChangedListeners.contains(listener)) { + onStateChangedListeners.add(listener); + } return this; } public void show(ImageView i, SparseArray imageGroupList, List urlList) { init(); - mImageWatcher.show(i, imageGroupList, urlList); + final boolean displaySuccess = mImageWatcher.show(i, imageGroupList, urlList); + if (displaySuccess) { + appendOtherView(); + } } public void show(List urlList, int initPos) { init(); mImageWatcher.show(urlList, initPos); + appendOtherView(); } private void init() { @@ -86,29 +112,72 @@ private void init() { if (listener != null) mImageWatcher.setOnPictureLongPressListener(listener); if (indexProvider != null) mImageWatcher.setIndexProvider(indexProvider); if (loadingUIProvider != null) mImageWatcher.setLoadingUIProvider(loadingUIProvider); - if (onStateChangedListener != null) - mImageWatcher.setOnStateChangedListener(onStateChangedListener); + if (!onStateChangedListeners.isEmpty()) { + for (ImageWatcher.OnStateChangedListener onStateChangedListener : onStateChangedListeners) { + mImageWatcher.addOnStateChangedListener(onStateChangedListener); + } + } + if (!onPageChangeListeners.isEmpty()) { + for (ViewPager.OnPageChangeListener onPageChangeListener : onPageChangeListeners) { + mImageWatcher.addOnPageChangeListener(onPageChangeListener); + } + } + - removeExistingOverlayInView(activityDecorView); // 理论上是无意义的操作。在ImageWatcher 'dismiss' 时会移除自身。但检查一下不错 + removeExistingOverlayInView(activityDecorView, mImageWatcher.getId()); // 理论上是无意义的操作。在ImageWatcher 'dismiss' 时会移除自身。但检查一下不错 activityDecorView.addView(mImageWatcher); + + } + + public ImageWatcher getImageWatcher() { + if (mImageWatcher == null) { + Log.i("ImageWatcherHelper", "please invoke 'show' first"); + } + return mImageWatcher; } public boolean handleBackPressed() { return mImageWatcher != null && mImageWatcher.handleBackPressed(); } - private void removeExistingOverlayInView(ViewGroup parent) { + private void removeExistingOverlayInView(ViewGroup parent, int viewId) { for (int i = 0; i < parent.getChildCount(); i++) { View child = parent.getChildAt(i); - if (child.getId() == VIEW_IMAGE_WATCHER_ID) { + if (child.getId() == viewId) { parent.removeView(child); } + if (child instanceof ViewGroup) { - removeExistingOverlayInView((ViewGroup) child); + removeExistingOverlayInView((ViewGroup) child, viewId); } } } + private void appendOtherView() { + if (otherView != null) { + if (otherView.getId() == View.NO_ID) otherView.setId(VIEW_DECORATION_ID); + removeExistingOverlayInView(activityDecorView, otherView.getId()); + activityDecorView.addView(otherView); + mImageWatcher.addOnStateChangedListener(new ImageWatcher.OnStateChangedListener() { + @Override + public void onStateChangeUpdate(ImageWatcher imageWatcher, ImageView clicked, int position, Uri uri, float animatedValue, int actionTag) { + } + + @Override + public void onStateChanged(ImageWatcher imageWatcher, int position, Uri uri, int actionTag) { + if (actionTag == ImageWatcher.STATE_EXIT_HIDING) { + if (otherView != null) { + if (otherView.getParent() != null) { + ((ViewGroup) otherView.getParent()).removeView(otherView); + } + } + } + } + }); + } + } + + public interface Provider { ImageWatcherHelper iwHelper(); } diff --git a/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ProgressView.java b/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ProgressView.java index 80fc13c..6b1ecf6 100644 --- a/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ProgressView.java +++ b/imagewatcher/src/main/java/com/github/ielse/imagewatcher/ProgressView.java @@ -60,6 +60,10 @@ public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long } + public boolean isRunning() { + return mDrawable.isRunning(); + } + public void start() { mDrawable.start(); } diff --git a/imagewatcher/src/main/res/values/ids.xml b/imagewatcher/src/main/res/values/ids.xml index d18bc82..4008cdc 100644 --- a/imagewatcher/src/main/res/values/ids.xml +++ b/imagewatcher/src/main/res/values/ids.xml @@ -9,4 +9,5 @@ + \ No newline at end of file