Commit cce84b56 by fengquan

feat: 咨询师图片/视频预览

parent cea87958
......@@ -23,6 +23,8 @@ import com.ydl.ydlcommon.utils.AppProgressUtils;
import com.ydl.ydlcommon.utils.Utils;
import com.yidianling.common.tools.LogUtil;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.consultant.preview.TestImageLoader;
import com.yidianling.consultant.preview.ZoomMediaLoader;
import com.yidianling.course.lifeCallback.CoursePlayLifecycle;
......@@ -48,7 +50,7 @@ public class ComponentTestApp extends BaseApp {
com.ydl.ydlcommon.utils.LogUtil.debug = BuildConfig.DEBUG;
webviewSetPath(this);
ZoomMediaLoader.getInstance().init(new TestImageLoader());
if (!BuildConfig.DEBUG && Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {//release包去除,debug包不去除,用于检测是否还有反射api的方法
//去掉在Android P上的提醒弹窗 Detected problems with API
......
......@@ -70,6 +70,7 @@ dependencies {
kapt 'com.alibaba:arouter-compiler:1.2.2'
implementation rootProject.ext.dependencies["BaseRecyclerViewAdapterHelper"]
api rootProject.ext.dependencies["ydl-user-router"]
implementation "com.ydl:jjdxm-ijkplayer:0.0.33"
if (rootProject.ext.dev_mode){
//开发时使用
implementation modularPublication('com.ydl:m-user-api')
......
......@@ -18,6 +18,13 @@
android:name=".ConsultAssistantCenterActivity"
android:screenOrientation="portrait"
android:theme="@style/consultant_Transparent"/>
<activity android:name=".preview.GridPreviewActivity"
android:screenOrientation="portrait"
android:theme="@style/consultant_Transparent"/>
<activity android:name=".preview.GPreviewActivity"
android:screenOrientation="portrait"
android:theme="@style/consultant_Transparent"/>
</application>
</manifest>
\ No newline at end of file
package com.yidianling.consultant.preview;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import com.dou361.ijkplayer.widget.IjkVideoView;
import com.yidianling.consultant.R;
/**
* @author rainb
* Deprecated: 图片预览单个图片的fragment
*/
public class BasePhotoFragment extends Fragment {
/**
* 预览图片 类型
*/
private static final String KEY_TRANS_PHOTO = "is_trans_photo";
private static final String KEY_SING_FILING = "isSingleFling";
private static final String KEY_PATH = "key_item";
private static final String KEY_DRAG = "isDrag";
private static final String KEY_SEN = "sensitivity";
private IThumbViewInfo beanViewInfo;
private boolean isTransPhoto = false;
protected SmoothImageView imageView;
protected View rootView;
protected View loading;
protected MySimpleTarget mySimpleTarget;
protected View btnVideo;
private LinearLayout btnLL;
private RelativeLayout videoContainer;
private IjkVideoView videoView;
// public static VideoClickListener listener;
public static BasePhotoFragment getInstance(Class<? extends BasePhotoFragment> fragmentClass,
IThumbViewInfo item,
boolean currentIndex,
boolean isSingleFling,
boolean isDrag,
float sensitivity) {
BasePhotoFragment fragment;
try {
fragment = fragmentClass.newInstance();
} catch (Exception e) {
fragment = new BasePhotoFragment();
}
Bundle bundle = new Bundle();
bundle.putParcelable(BasePhotoFragment.KEY_PATH, item);
bundle.putBoolean(BasePhotoFragment.KEY_TRANS_PHOTO, currentIndex);
bundle.putBoolean(BasePhotoFragment.KEY_SING_FILING, isSingleFling);
bundle.putBoolean(BasePhotoFragment.KEY_DRAG, isDrag);
bundle.putFloat(BasePhotoFragment.KEY_SEN, sensitivity);
fragment.setArguments(bundle);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_image_photo_layout, container, false);
}
@CallSuper
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(view);
initData();
}
@CallSuper
@Override
public void onStop() {
ZoomMediaLoader.getInstance().getLoader().onStop(this);
super.onStop();
}
@CallSuper
@Override
public void onDestroyView() {
super.onDestroyView();
release();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
}
@Override
public void onDestroy() {
super.onDestroy();
ZoomMediaLoader.getInstance().getLoader().clearMemory(getActivity());
if (getActivity() != null && getActivity().isFinishing()) {
// listener = null;
}
}
public void release() {
isTransPhoto = false;
}
/**
* 初始化控件
*/
private void initView(View view) {
loading = view.findViewById(R.id.loading);
imageView = view.findViewById(R.id.photoView);
btnVideo = view.findViewById(R.id.btnVideo);
rootView = view.findViewById(R.id.rootView);
rootView.setDrawingCacheEnabled(false);
imageView.setDrawingCacheEnabled(false);
btnLL = view.findViewById(R.id.btnLL);
imageView.setBtnLL(btnLL);
videoContainer = view.findViewById(R.id.videoContainer);
videoView = view.findViewById(R.id.videoView);
// btnVideo.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// String video = beanViewInfo.getVideoUrl();
// if (video != null && !video.isEmpty()) {
// if (listener != null) {
// listener.onPlayerVideo(video);
// } else {
// GPVideoPlayerActivity.startActivity(getContext(), video);
// }
// }
//
// }
// });
mySimpleTarget = new MySimpleTarget() {
@Override
public void onResourceReady() {
loading.setVisibility(View.GONE);
String video = beanViewInfo.getVideoUrl();
if (video != null && !video.isEmpty()) {
btnVideo.setVisibility(View.VISIBLE);
ViewCompat.animate(btnVideo).alpha(1).setDuration(1000).start();
} else {
btnVideo.setVisibility(View.GONE);
}
}
@Override
public void onLoadFailed(Drawable errorDrawable) {
loading.setVisibility(View.GONE);
btnVideo.setVisibility(View.GONE);
if (errorDrawable != null) {
imageView.setImageDrawable(errorDrawable);
}
}
};
}
/**
* 初始化数据
*/
private void initData() {
Bundle bundle = getArguments();
boolean isSingleFling = true;
// 非动画进入的Fragment,默认背景为黑色
if (bundle != null) {
isSingleFling = bundle.getBoolean(KEY_SING_FILING);
//地址
beanViewInfo = bundle.getParcelable(KEY_PATH);
//位置
assert beanViewInfo != null;
//imageView.setDrag(bundle.getBoolean(KEY_DRAG), bundle.getFloat(KEY_SEN));
imageView.setThumbRect(beanViewInfo.getBounds());
rootView.setTag(beanViewInfo.getUrl());
//是否展示动画
isTransPhoto = bundle.getBoolean(KEY_TRANS_PHOTO, false);
if (!TextUtils.isEmpty(beanViewInfo.getUrl())){
if (beanViewInfo.getUrl().toLowerCase().contains(".gif")) {
imageView.setVisibility(View.VISIBLE);
videoContainer.setVisibility(View.GONE);
imageView.setZoomable(false);
//加载图
ZoomMediaLoader.getInstance().getLoader().displayGifImage(this, beanViewInfo.getUrl(), imageView, mySimpleTarget);
} else {
//加载图
ZoomMediaLoader.getInstance().getLoader().displayImage(this, beanViewInfo.getUrl(), imageView, mySimpleTarget);
}
}else {
videoContainer.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
// IjkVideoView videoView = new IjkVideoView(getContext());
// videoContainer.addView(videoView);
String videoUlr = beanViewInfo.getVideoUrl();
if (!TextUtils.isEmpty(videoUlr)) {
videoView.setVideoURI(Uri.parse(videoUlr));
videoView.start();
}
}
}
if (!isTransPhoto) {
rootView.setBackgroundColor(Color.BLACK);
} else {
imageView.setMinimumScale(0.7f);
}
if (isSingleFling) {
imageView.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() {
@Override
public void onViewTap(View view, float x, float y) {
}
});
imageView.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() {
@Override
public void onViewTap(View view, float x, float y) {
if (imageView.checkMinScale()) {
((GPreviewActivity) getActivity()).transformOut();
}
}
});
} else {
imageView.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
@Override
public void onPhotoTap(View view, float x, float y) {
if (imageView.checkMinScale()) {
((GPreviewActivity) getActivity()).transformOut();
}
}
@Override
public void onOutsidePhotoTap() {
}
});
}
imageView.setAlphaChangeListener(new SmoothImageView.OnAlphaChangeListener() {
@Override
public void onAlphaChange(int alpha) {
if (alpha == 255) {
String video = beanViewInfo.getVideoUrl();
if (video != null && !video.isEmpty()) {
btnVideo.setVisibility(View.VISIBLE);
} else {
btnVideo.setVisibility(View.GONE);
}
} else {
btnVideo.setVisibility(View.GONE);
}
rootView.setBackgroundColor(getColorWithAlpha(alpha / 255f, Color.BLACK));
}
});
imageView.setTransformOutListener(new SmoothImageView.OnTransformOutListener() {
@Override
public void onTransformOut() {
((GPreviewActivity) getActivity()).transformOut();
}
});
}
public static int getColorWithAlpha(float alpha, int baseColor) {
int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24;
int rgb = 0x00ffffff & baseColor;
return a + rgb;
}
public void transformIn() {
assert imageView != null;
imageView.transformIn(new SmoothImageView.onTransformListener() {
@Override
public void onTransformCompleted(SmoothImageView.Status status) {
rootView.setBackgroundColor(Color.BLACK);
}
});
}
public void transformOut(SmoothImageView.onTransformListener listener) {
assert imageView != null;
imageView.transformOut(listener);
}
public void changeBg(int color) {
ViewCompat.animate(btnVideo).alpha(0).setDuration(SmoothImageView.getDuration()).start();
rootView.setBackgroundColor(color);
}
public IThumbViewInfo getBeanViewInfo() {
return beanViewInfo;
}
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.view.MotionEvent;
import android.view.View;
/**
* @author rainb
*/
public class Compat {
private static final int SIXTY_FPS_INTERVAL = 1000 / 60;
public static void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
postOnAnimationJellyBean(view, runnable);
} else {
view.postDelayed(runnable, SIXTY_FPS_INTERVAL);
}
}
@TargetApi(16)
private static void postOnAnimationJellyBean(View view, Runnable runnable) {
view.postOnAnimation(runnable);
}
public static int getPointerIndex(int action) {
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
return getPointerIndexHoneyComb(action);
else
return getPointerIndexEclair(action);
}
@SuppressWarnings("deprecation")
@TargetApi(VERSION_CODES.ECLAIR)
private static int getPointerIndexEclair(int action) {
return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
}
@TargetApi(VERSION_CODES.HONEYCOMB)
private static int getPointerIndexHoneyComb(int action) {
return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
/**
* @author rainb
*/
public class CupcakeGestureDetector implements GestureDetector {
protected OnGestureListener mListener;
private static final String LOG_TAG = "CupcakeGestureDetector";
float mLastTouchX;
float mLastTouchY;
final float mTouchSlop;
final float mMinimumVelocity;
@Override
public void setOnGestureListener(OnGestureListener listener) {
this.mListener = listener;
}
public CupcakeGestureDetector(Context context) {
final ViewConfiguration configuration = ViewConfiguration
.get(context);
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mTouchSlop = configuration.getScaledTouchSlop();
}
private VelocityTracker mVelocityTracker;
private boolean mIsDragging;
float getActiveX(MotionEvent ev) {
return ev.getX();
}
float getActiveY(MotionEvent ev) {
return ev.getY();
}
@Override
public boolean isScaling() {
return false;
}
@Override
public boolean isDragging() {
return mIsDragging;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mVelocityTracker = VelocityTracker.obtain();
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
} else {
Log.i(LOG_TAG, "Velocity tracker is null");
}
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
mIsDragging = false;
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);
final float dx = x - mLastTouchX, dy = y - mLastTouchY;
if (!mIsDragging) {
// Use Pythagoras to see if drag length is larger than
// touch slop
mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
}
if (mIsDragging) {
mListener.onDrag(dx, dy);
mLastTouchX = x;
mLastTouchY = y;
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
}
break;
}
case MotionEvent.ACTION_CANCEL: {
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
case MotionEvent.ACTION_UP: {
if (mIsDragging) {
if (null != mVelocityTracker) {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
// Compute velocity within the last 1000ms
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000);
final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
.getYVelocity();
// If the velocity is greater than minVelocity, call
// listener
if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
mListener.onFling(mLastTouchX, mLastTouchY, -vX,
-vY);
}
}
}
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
}
return true;
}
}
package com.yidianling.consultant.preview;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
* @author rainb
*/
public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener {
private PhotoViewAttacher photoViewAttacher;
/**
* Default constructor
*
* @param photoViewAttacher PhotoViewAttacher to bind to
*/
public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) {
setPhotoViewAttacher(photoViewAttacher);
}
/**
* Allows to change PhotoViewAttacher within range of single instance
*
* @param newPhotoViewAttacher PhotoViewAttacher to bind to
*/
public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) {
this.photoViewAttacher = newPhotoViewAttacher;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (this.photoViewAttacher == null) {
return false;
}
ImageView imageView = photoViewAttacher.getImageView();
if (null != photoViewAttacher.getOnPhotoTapListener()) {
final RectF displayRect = photoViewAttacher.getDisplayRect();
if (null != displayRect) {
final float x = e.getX(), y = e.getY();
// Check to see if the user tapped on the photo
if (displayRect.contains(x, y)) {
float xResult = (x - displayRect.left)
/ displayRect.width();
float yResult = (y - displayRect.top)
/ displayRect.height();
photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult);
return true;
} else {
photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap();
}
}
}
if (null != photoViewAttacher.getOnViewTapListener()) {
photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY());
}
return false;
}
@Override
public boolean onDoubleTap(MotionEvent ev) {
if (photoViewAttacher == null) {
return false;
}
try {
float scale = photoViewAttacher.getScale();
float x = ev.getX();
float y = ev.getY();
if (scale < photoViewAttacher.getMediumScale()) {
photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true);
} else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) {
photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true);
} else {
photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true);
}
} catch (ArrayIndexOutOfBoundsException e) {
// Can sometimes happen when getX() and getY() is called
}
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Wait for the confirmed onDoubleTap() instead
return false;
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.MotionEvent;
/**
* @author rainb
*/
@TargetApi(5)
public class EclairGestureDetector extends CupcakeGestureDetector {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private int mActivePointerIndex = 0;
public EclairGestureDetector(Context context) {
super(context);
}
@Override
float getActiveX(MotionEvent ev) {
try {
return ev.getX(mActivePointerIndex);
} catch (Exception e) {
return ev.getX();
}
}
@Override
float getActiveY(MotionEvent ev) {
try {
return ev.getY(mActivePointerIndex);
} catch (Exception e) {
return ev.getY();
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
// Ignore deprecation, ACTION_POINTER_ID_MASK and
// ACTION_POINTER_ID_SHIFT has same value and are deprecated
// You can have either deprecation or lint target api warning
final int pointerIndex = Compat.getPointerIndex(ev.getAction());
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
}
break;
}
mActivePointerIndex = ev
.findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId
: 0);
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException e) {
// Fix for support lib bug, happening when onDestroy is
return true;
}
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
/**
* @author rainb
*/
@TargetApi(8)
public class FroyoGestureDetector extends EclairGestureDetector {
protected final ScaleGestureDetector mDetector;
public FroyoGestureDetector(Context context) {
super(context);
ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) {
return false;
}
mListener.onScale(scaleFactor,
detector.getFocusX(), detector.getFocusY());
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// NO-OP
}
};
mDetector = new ScaleGestureDetector(context, mScaleListener);
}
@Override
public boolean isScaling() {
return mDetector.isInProgress();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
mDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
} catch (IllegalArgumentException e) {
// Fix for support lib bug, happening when onDestroy is
return true;
}
}
}
package com.yidianling.consultant.preview;
import android.graphics.Color;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import com.yidianling.consultant.R;
import java.util.ArrayList;
import java.util.List;
/**
* @author rainb
*/
public class GPreviewActivity extends AppCompatActivity {
protected boolean isTransformOut = false;
/*** 图片的地址***/
private List<IThumbViewInfo> imgUrls;
/*** 当前图片的位置 ***/
protected int currentIndex;
/***指示器类型枚举***/
private GPreviewBuilder.IndicatorType type;
/***默认显示***/
private boolean isShow = true;
/*** 展示图片的viewPager ***/
private PhotoViewPager viewPager;
/*** 图片的展示的Fragment***/
private List<BasePhotoFragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
setContentView(R.layout.consultant_image_preview_photo);
initView();
}
private void initView() {
viewPager = findViewById(R.id.viewPager);
//viewPager的适配器
PhotoPagerAdapter adapter = new PhotoPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(currentIndex);
// viewPager.setOffscreenPageLimit(3);
viewPager.setOffscreenPageLimit(0);
}
private void initData() {
imgUrls = getIntent().getParcelableArrayListExtra("imagePaths");
currentIndex = getIntent().getIntExtra("position", -1);
type = (GPreviewBuilder.IndicatorType) getIntent().getSerializableExtra("type");
isShow = getIntent().getBooleanExtra("isShow", true);
boolean isFullscreen = getIntent().getBooleanExtra("isFullscreen", false);
boolean isScale = getIntent().getBooleanExtra("isScale", false);
SmoothImageView.setFullscreen(isFullscreen);
SmoothImageView.setIsScale(isScale);
if (isFullscreen) {
setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
}
initFragment(imgUrls, currentIndex, BasePhotoFragment.class);
}
private void initFragment(List<IThumbViewInfo> imgUrls, int currentIndex, Class<BasePhotoFragment> className) {
if (imgUrls != null) {
int size = imgUrls.size();
for (int i = 0; i < size; i++) {
fragments.add(BasePhotoFragment.
getInstance(className, imgUrls.get(i),
currentIndex == i,
getIntent().getBooleanExtra("isSingleFling", false),
getIntent().getBooleanExtra("isDrag", false),
getIntent().getFloatExtra("sensitivity", 0.5f))
);
}
} else {
finish();
}
}
@Override
protected void onDestroy() {
ZoomMediaLoader.getInstance().getLoader().clearMemory(this);
if (viewPager != null) {
viewPager.setAdapter(null);
viewPager.clearOnPageChangeListeners();
viewPager.removeAllViews();
viewPager = null;
}
if (fragments != null) {
fragments.clear();
fragments = null;
}
if (imgUrls != null) {
imgUrls.clear();
imgUrls = null;
}
super.onDestroy();
}
/***
* 得到PhotoViewPager
* @return PhotoViewPager
* **/
public PhotoViewPager getViewPager() {
return viewPager;
}
public void transformOut() {
if (isTransformOut) {
return;
}
getViewPager().setEnabled(false);
isTransformOut = true;
int currentItem = viewPager.getCurrentItem();
if (currentItem < imgUrls.size()) {
BasePhotoFragment fragment = fragments.get(currentItem);
fragment.changeBg(Color.TRANSPARENT);
fragment.transformOut(new SmoothImageView.onTransformListener() {
@Override
public void onTransformCompleted(SmoothImageView.Status status) {
getViewPager().setEnabled(true);
exit();
}
});
} else {
exit();
}
}
/**
* 关闭页面
*/
private void exit() {
finish();
overridePendingTransition(0, 0);
}
@Override
public void onBackPressed() {
isTransformOut = false;
transformOut();
}
@Override
public void finish() {
// BasePhotoFragment.listener=null;
super.finish();
}
/**
* pager的适配器
*/
private class PhotoPagerAdapter extends FragmentStatePagerAdapter {
PhotoPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments == null ? 0 : fragments.size();
}
}
}
package com.yidianling.consultant.preview;
import android.app.Activity;
import android.content.Intent;
import android.os.Parcelable;
import androidx.fragment.app.Fragment;
import java.util.ArrayList;
import java.util.List;
/**
* @author rainb
*/
public class GPreviewBuilder {
private Activity mContext;
private Intent intent;
private Class className;
private GPreviewBuilder(Activity activity) {
mContext = activity;
intent = new Intent();
}
public static GPreviewBuilder form(Activity activity) {
return new GPreviewBuilder(activity);
}
public static GPreviewBuilder from(Fragment fragment) {
return new GPreviewBuilder(fragment.getActivity());
}
/***
* 设置数据源
* @param imgUrls 数据
*@param <T> 你的实体类类型
* @return GPreviewBuilder
* **/
public <T extends IThumbViewInfo> GPreviewBuilder setData(List<T> imgUrls) {
intent.putParcelableArrayListExtra("imagePaths", new ArrayList<Parcelable>(imgUrls));
return this;
}
/***
* 设置默认索引
* @param currentIndex 数据
* @return GPreviewBuilder
* **/
public GPreviewBuilder setCurrentIndex(int currentIndex) {
intent.putExtra("position", currentIndex);
return this;
}
/***
* 设置指示器类型
* @param indicatorType 枚举
* @return GPreviewBuilder
* **/
public GPreviewBuilder setType(IndicatorType indicatorType) {
intent.putExtra("type", indicatorType);
return this;
}
public void start() {
if (className == null) {
intent.setClass(mContext, GPreviewActivity.class);
} else {
intent.setClass(mContext, className);
}
mContext.startActivity(intent);
mContext.overridePendingTransition(0, 0);
intent = null;
mContext = null;
}
public GPreviewBuilder setFullscreen(boolean isFullscreen) {
intent.putExtra("isFullscreen", isFullscreen);
return this;
}
/***
* 指示器类型
* ***/
public enum IndicatorType {
Dot, Number
}
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.view.MotionEvent;
/**
* @author rainb
*/
public interface GestureDetector {
boolean onTouchEvent(MotionEvent ev);
boolean isScaling();
boolean isDragging();
void setOnGestureListener(OnGestureListener listener);
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
import android.widget.OverScroller;
/**
* @author rainb
*/
@TargetApi(9)
public class GingerScroller extends ScrollerProxy {
protected final OverScroller mScroller;
public GingerScroller(Context context) {
mScroller = new OverScroller(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
@Override
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
int overX, int overY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY);
}
@Override
public void forceFinished(boolean finished) {
mScroller.forceFinished(finished);
}
@Override
public boolean isFinished() {
return mScroller.isFinished();
}
@Override
public int getCurrX() {
return mScroller.getCurrX();
}
@Override
public int getCurrY() {
return mScroller.getCurrY();
}
}
\ No newline at end of file
package com.yidianling.consultant.preview;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import com.blankj.utilcode.util.ScreenUtils;
import com.bumptech.glide.Glide;
import com.ydl.ydlcommon.base.BaseActivity;
import com.ydl.ydlcommon.bean.StatusBarOptions;
import com.yidianling.consultant.R;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* @author fq
*/
public class GridPreviewActivity extends BaseActivity {
private ArrayList<UserViewInfo> mThumbViewInfoList = new ArrayList<>();
MyListAdapter adapter;
private GridView gridView;
@NotNull
@Override
public StatusBarOptions getStatusViewOptions() {
return new StatusBarOptions(true, true);
}
/**
* 查找信息
* 从第一个完整可见item逆序遍历,如果初始位置为0,则不执行方法内循环
*/
private void computeBoundsBackward(int firstCompletelyVisiblePos) {
for (int i = firstCompletelyVisiblePos; i < mThumbViewInfoList.size(); i++) {
View itemView = gridView.getChildAt(i - firstCompletelyVisiblePos);
Rect bounds = new Rect();
bounds.left = ScreenUtils.getScreenWidth() / 2;
bounds.top = ScreenUtils.getScreenHeight() / 2;
bounds.right = ScreenUtils.getScreenWidth() / 2;
bounds.bottom = ScreenUtils.getScreenHeight() / 2;
// if (itemView != null) {
// ImageView thumbView = (ImageView) itemView.findViewById(R.id.iv);
// thumbView.getGlobalVisibleRect(bounds);
// }
mThumbViewInfoList.get(i).setBounds(bounds);
}
}
@Override
protected int layoutResId() {
return R.layout.consultant_picture_preview;
}
@Override
protected void initDataAndEvent() {
gridView = findViewById(R.id.grid_view);
List<String> urls = ImageUrlConfig.getUrls();
for (int i = 0; i < urls.size(); i++) {
mThumbViewInfoList.add(new UserViewInfo(urls.get(i)));
}
mThumbViewInfoList.add(4, new UserViewInfo("https://pic.ydlcdn.com/Qkkb6HmQiM.mp4", null));
adapter = new MyListAdapter();
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
computeBoundsBackward(gridView.getFirstVisiblePosition());
GPreviewBuilder.form(GridPreviewActivity.this)
.setData(mThumbViewInfoList)
.setCurrentIndex(position)
.setFullscreen(true)
.setType(GPreviewBuilder.IndicatorType.Dot)
.start();
}
});
}
private class MyListAdapter extends BaseAdapter {
@Override
public int getCount() {
return mThumbViewInfoList.size();
}
@Override
public Object getItem(int position) {
return mThumbViewInfoList.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = getLayoutInflater().inflate(R.layout.consultant_item_image, null);
ImageView iv = (ImageView) view.findViewById(R.id.iv);
Glide.with(GridPreviewActivity.this)
.load(mThumbViewInfoList.get(position).getUrl())
.into(iv);
iv.setTag(R.id.iv, mThumbViewInfoList.get(position));
return view;
}
}
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.View;
import android.widget.ImageView;
/**
* @author rainb
*/
public interface IPhotoView {
float DEFAULT_MAX_SCALE = 3.0f;
float DEFAULT_MID_SCALE = 1.75f;
float DEFAULT_MIN_SCALE = 1.0f;
int DEFAULT_ZOOM_DURATION = 200;
/**
* Returns true if the PhotoView is set to allow zooming of Photos.
*
* @return true if the PhotoView allows zooming.
*/
boolean canZoom();
/**
* Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to
* this View and includes all scaling and translations.
*
* @return - RectF of Displayed Drawable
*/
RectF getDisplayRect();
/**
* Sets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
* relative to this View and includes all scaling and translations.
*
* @param finalMatrix target matrix to set PhotoView to
* @return - true if rectangle was applied successfully
*/
boolean setDisplayMatrix(Matrix finalMatrix);
/**
* Copies the Display Matrix of the currently displayed Drawable. The Rectangle is considered
* relative to this View and includes all scaling and translations.
*
* @param matrix target matrix to copy to
*/
void getDisplayMatrix(Matrix matrix);
/**
* @return The current minimum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMinimumScale();
/**
* @return The current medium scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMediumScale();
/**
* @return The current maximum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMaximumScale();
/**
* Returns the current scale value
*
* @return float - current scale value
*/
float getScale();
/**
* Return the current scale type in use by the ImageView.
*
* @return current ImageView.ScaleType
*/
ImageView.ScaleType getScaleType();
/**
* Whether to allow the ImageView's parent to intercept the touch event when the photo is scroll
* to it's horizontal edge.
*
* @param allow whether to allow intercepting by parent element or not
*/
void setAllowParentInterceptOnEdge(boolean allow);
/**
* Sets the minimum scale level. What this value represents depends on the current {@link
* ImageView.ScaleType}.
*
* @param minimumScale minimum allowed scale
*/
void setMinimumScale(float minimumScale);
/**
* Sets the medium scale level. What this value represents depends on the current {@link ImageView.ScaleType}.
*
* @param mediumScale medium scale preset
*/
void setMediumScale(float mediumScale);
/**
* Sets the maximum scale level. What this value represents depends on the current {@link
* ImageView.ScaleType}.
*
* @param maximumScale maximum allowed scale preset
*/
void setMaximumScale(float maximumScale);
/**
* Allows to set all three scale levels at once, so you don't run into problem with setting
* medium/minimum scale before the maximum one
*
* @param minimumScale minimum allowed scale
* @param mediumScale medium allowed scale
* @param maximumScale maximum allowed scale preset
*/
void setScaleLevels(float minimumScale, float mediumScale, float maximumScale);
/**
* Register a callback to be invoked when the Photo displayed by this view is long-pressed.
*
* @param listener - Listener to be registered.
*/
void setOnLongClickListener(View.OnLongClickListener listener);
/**
* Register a callback to be invoked when the Matrix has changed for this View. An example would
* be the user panning or scaling the Photo.
*
* @param listener - Listener to be registered.
*/
void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener);
/**
* Register a callback to be invoked when the Photo displayed by this View is tapped with a
* single tap.
*
* @param listener - Listener to be registered.
*/
void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener);
/**
* Register a callback to be invoked when the View is tapped with a single tap.
*
* @param listener - Listener to be registered.
*/
void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener);
/**
* Enables rotation via PhotoView internal functions.
*
* @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
*/
void setRotationTo(float rotationDegree);
/**
* Enables rotation via PhotoView internal functions.
*
* @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
*/
void setRotationBy(float rotationDegree);
/**
* Changes the current scale to the specified value.
*
* @param scale - Value to scale to
*/
void setScale(float scale);
/**
* Changes the current scale to the specified value.
*
* @param scale - Value to scale to
* @param animate - Whether to animate the scale
*/
void setScale(float scale, boolean animate);
/**
* Changes the current scale to the specified value, around the given focal point.
*
* @param scale - Value to scale to
* @param focalX - X Focus Point
* @param focalY - Y Focus Point
* @param animate - Whether to animate the scale
*/
void setScale(float scale, float focalX, float focalY, boolean animate);
/**
* Controls how the image should be resized or moved to match the size of the ImageView. Any
* scaling or panning will happen within the confines of this {@link
* ImageView.ScaleType}.
*
* @param scaleType - The desired scaling mode.
*/
void setScaleType(ImageView.ScaleType scaleType);
/**
* Allows you to enable/disable the zoom functionality on the ImageView. When disable the
* ImageView reverts to using the FIT_CENTER matrix.
*
* @param zoomable - Whether the zoom functionality is enabled.
*/
void setZoomable(boolean zoomable);
/**
* Extracts currently visible area to Bitmap object, if there is no image loaded yet or the
* ImageView is already destroyed, returns {@code null}
*
* @return currently visible area as bitmap or null
*/
Bitmap getVisibleRectangleBitmap();
/**
* Allows to change zoom transition speed, default value is 200 (PhotoViewAttacher.DEFAULT_ZOOM_DURATION).
* Will default to 200 if provided negative value
*
* @param milliseconds duration of zoom interpolation
*/
void setZoomTransitionDuration(int milliseconds);
/**
* Will return instance of IPhotoView (eg. PhotoViewAttacher), can be used to provide better
* integration
*
* @return IPhotoView implementation instance if available, null if not
*/
IPhotoView getIPhotoViewImplementation();
/**
* Sets custom double tap listener, to intercept default given functions. To reset behavior to
* default, you can just pass in "null" or public field of PhotoViewAttacher.defaultOnDoubleTapListener
*
* @param newOnDoubleTapListener custom OnDoubleTapListener to be set on ImageView
*/
void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener);
/**
* Will report back about scale changes
*
* @param onScaleChangeListener OnScaleChangeListener instance
*/
void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener);
/**
* Will report back about fling(single touch)
*
* @param onSingleFlingListener OnSingleFlingListener instance
*/
void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener);
}
package com.yidianling.consultant.preview;
import android.graphics.Rect;
import android.os.Parcelable;
/**
* Deprecated: 图片预览接口
*
* @author rainb
*/
public interface IThumbViewInfo extends Parcelable {
/****
* 图片地址
* @return String
* ****/
String getUrl();
/**
* 记录坐标
*
* @return Rect
***/
Rect getBounds();
/**
* 获取视频链接
***/
String getVideoUrl();
}
package com.yidianling.consultant.preview;
import android.content.Context;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
/**
* Deprecated: 加载器接口
*
* @author rainb
*/
public interface IZoomMediaLoader {
/***
* @param context 容器
* @param path 图片你的路径
* @param simpleTarget 图片加载状态回调
* ***/
void displayImage(@NonNull Fragment context, @NonNull String path, ImageView imageView, @NonNull MySimpleTarget simpleTarget);
/***
* 加载gif 图
* @param context 容器
* @param path 图片你的路径
* @param simpleTarget 图片加载状态回调
* ***/
void displayGifImage(@NonNull Fragment context, @NonNull String path, ImageView imageView, @NonNull MySimpleTarget simpleTarget);
/**
* 停止
*
* @param context 容器
**/
void onStop(@NonNull Fragment context);
/**
* 停止
*
* @param c 容器
**/
void clearMemory(@NonNull Context c);
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.annotation.TargetApi;
import android.content.Context;
/**
* @author rainb
*/
@TargetApi(14)
public class IcsScroller extends GingerScroller {
public IcsScroller(Context context) {
super(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
}
package com.yidianling.consultant.preview;
import java.util.ArrayList;
import java.util.List;
/**
* ImageUrlConfig
*
* @author rainb
*/
public final class ImageUrlConfig {
private static List<String> sUrls = new ArrayList<>();
private static List<UserViewInfo> videos = new ArrayList<>();
public static List<UserViewInfo> getVideos() {
videos.clear();
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
"http://pic.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
"http://pic.vjshi.com/2017-05-25/b146e104069c2bd0590bb919269193c4/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://ac-QYgvX1CC.clouddn.com/36f0523ee1888a57.jpg"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-05-07/d0bbfc4ac4dd173cc93873ed4eb0be53.mp4",
"http://pic.vjshi.com/2017-05-07/d0bbfc4ac4dd173cc93873ed4eb0be53/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-07-18/80d08ce1a84adfbaed5c7067b73d19ed.mp4",
"http://pic.vjshi.com/2017-07-18/80d08ce1a84adfbaed5c7067b73d19ed/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://img0.imgtn.bdimg.com/it/u=556618733,1205300389&fm=21&gp=0.jpg"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
"http://pic.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://img0.imgtn.bdimg.com/it/u=556618733,1205300389&fm=21&gp=0.jpg"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2018-06-07/cf673556cce54ab9cf4633fd7d9d0d46.mp4",
"http://pic.vjshi.com/2018-06-06/caa296729c8e6e41e6aff2aadf4feff3/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://img44.photophoto.cn/20170730/0018090594006661_s.jpg"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a.mp4",
"http://pic.vjshi.com/2017-09-13/f55a900d89679ac1c9837d5b5aaf632a/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://ac-QYgvX1CC.clouddn.com/36f0523ee1888a57.jpg"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2018-01-27/5169bb7bdd7386ce7bd4ce1739229424.mp4",
"http://pic.vjshi.com/2018-01-27/5169bb7bdd7386ce7bd4ce1739229424/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://photocdn.sohu.com/20160307/mp62252655_1457334772519_2.png"));
videos.add(new UserViewInfo("http://lmp4.vjshi.com/2017-09-27/9a6e69f7c257ff7b7832e8bac6fddf82.mp4",
"http://pic.vjshi.com/2017-09-27/9a6e69f7c257ff7b7832e8bac6fddf82/online/puzzle.jpg?x-oss-process=style/resize_w_285_crop_h_428"));
videos.add(new UserViewInfo("http://photocdn.sohu.com/20160307/mp62252655_1457334772519_2.png"));
return videos;
}
public static List<String> getUrls() {
sUrls.clear();
sUrls.add("https://hellorfimg.zcool.cn/preview260/129132983.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1156349101.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1156349101.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/298757792.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/587590211.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/407797777.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/675219493.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1045107625.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/551576716.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1016991457.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/377604361.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/533952916.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234602281.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234602281.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2235502018.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/137983838.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234677521.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/321745829.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2236891951.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/102396898.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/793540144.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/619468106.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/220323652.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/428018086.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234609274.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/401555077.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1034426839.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234619039.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/298605944.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/393511423.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/253828555.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/400379983.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2237655331.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/606048908.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/181387775.jpg");
sUrls.add("https://hellorfimg.zcool.cn/provider_image/preview260/2234602281.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/326490512.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/521163331.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/1499307269.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/459494017.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/102396898.jpg");
sUrls.add("https://hellorfimg.zcool.cn/preview260/606363722.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085581124963_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085226124343_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085226124343_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085200668628_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085246003750_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085012707934_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0005018303330857_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085231427344_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085236829578_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085729490157_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170727/0847085751995287_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085729043617_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170729/0847085786392651_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085761440022_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170727/0847085275244570_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085858434984_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085781987193_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085707961800_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085229451104_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170720/0847085716198074_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170720/0847085769259426_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085717385169_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085757949071_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085789079771_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170722/0847085229451104_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170721/0847085757949071_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170728/0847085265005650_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170730/0008118269110532_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170731/0008118203762697_s.jpg");
sUrls.add("http://img44.photophoto.cn/20170727/0008118269666722_s.jpg");
return sUrls;
}
public static List<UserViewInfo> getGifUrls() {
List<UserViewInfo> userViewInfos = new ArrayList<>();
userViewInfos.add(new UserViewInfo("https://hellorfimg.zcool.cn/preview260/658596682.jpg"));
userViewInfos.add(new UserViewInfo("https://hellorfimg.zcool.cn/preview260/123343987.jpg"));
userViewInfos.add(new UserViewInfo("https://hellorfimg.zcool.cn/preview260/658275328.jpg"));
userViewInfos.add(new UserViewInfo("http://img.soogif.com/SH0FB6FnTNgoCsVtxcAMtSNfV7XxXmo8.gif"));
userViewInfos.add(new UserViewInfo("http://img.soogif.com/SH0FB6FnTNgoCsVtxcAMtSNfV7XxXmo8.gif"));
userViewInfos.add(new UserViewInfo("http://img.soogif.com/KkB9WARG3PFrz9EEX4DJdiy6Vyg95fGl.gif"));
return userViewInfos;
}
}
package com.yidianling.consultant.preview;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
/**
* Deprecated: 图片加载回调状态接口
*
* @author rainb
*/
public interface MySimpleTarget {
/**
* Callback when an image has been successfully loaded.
* <p>
* <strong>Note:</strong> You must not recycle the bitmap.
*/
void onResourceReady();
/**
* Callback indicating the image could not be successfully loaded.
*
* @param errorRes 内容
*/
void onLoadFailed(@Nullable Drawable errorRes);
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
/**
* @author rainb
*/
public interface OnGestureListener {
void onDrag(float dx, float dy);
void onFling(float startX, float startY, float velocityX,
float velocityY);
void onScale(float scaleFactor, float focusX, float focusY);
}
\ No newline at end of file
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.content.Context;
import android.graphics.Bitmap;
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;
public class PhotoView extends androidx.appcompat.widget.AppCompatImageView implements IPhotoView {
private PhotoViewAttacher mAttacher;
private ScaleType mPendingScaleType;
public PhotoView(Context context) {
this(context, null);
}
public PhotoView(Context context, AttributeSet attr) {
this(context, attr, 0);
}
public PhotoView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
super.setScaleType(ScaleType.MATRIX);
init();
}
protected void init() {
if (null == mAttacher || null == mAttacher.getImageView()) {
mAttacher = new PhotoViewAttacher(this);
}
if (null != mPendingScaleType) {
setScaleType(mPendingScaleType);
mPendingScaleType = null;
}
}
@Override
public void setRotationTo(float rotationDegree) {
mAttacher.setRotationTo(rotationDegree);
}
@Override
public void setRotationBy(float rotationDegree) {
mAttacher.setRotationBy(rotationDegree);
}
@Override
public boolean canZoom() {
return mAttacher.canZoom();
}
@Override
public RectF getDisplayRect() {
return mAttacher.getDisplayRect();
}
@Override
public void getDisplayMatrix(Matrix matrix) {
mAttacher.getDisplayMatrix(matrix);
}
@Override
public boolean setDisplayMatrix(Matrix finalRectangle) {
return mAttacher.setDisplayMatrix(finalRectangle);
}
@Override
public float getMinimumScale() {
return mAttacher.getMinimumScale();
}
@Override
public float getMediumScale() {
return mAttacher.getMediumScale();
}
@Override
public float getMaximumScale() {
return mAttacher.getMaximumScale();
}
@Override
public float getScale() {
return mAttacher.getScale();
}
@Override
public ScaleType getScaleType() {
return mAttacher.getScaleType();
}
@Override
public Matrix getImageMatrix() {
return mAttacher.getImageMatrix();
}
@Override
public void setAllowParentInterceptOnEdge(boolean allow) {
mAttacher.setAllowParentInterceptOnEdge(allow);
}
@Override
public void setMinimumScale(float minimumScale) {
mAttacher.setMinimumScale(minimumScale);
}
@Override
public void setMediumScale(float mediumScale) {
mAttacher.setMediumScale(mediumScale);
}
@Override
public void setMaximumScale(float maximumScale) {
mAttacher.setMaximumScale(maximumScale);
}
@Override
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
mAttacher.setScaleLevels(minimumScale, mediumScale, maximumScale);
}
@Override
// setImageBitmap calls through to this method
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (null != mAttacher) {
mAttacher.update();
}
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
if (null != mAttacher) {
mAttacher.update();
}
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
if (null != mAttacher) {
mAttacher.update();
}
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
boolean changed = super.setFrame(l, t, r, b);
if (null != mAttacher) {
mAttacher.update();
}
return changed;
}
@Override
public void setOnMatrixChangeListener(PhotoViewAttacher.OnMatrixChangedListener listener) {
mAttacher.setOnMatrixChangeListener(listener);
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
mAttacher.setOnLongClickListener(l);
}
@Override
public void setOnPhotoTapListener(PhotoViewAttacher.OnPhotoTapListener listener) {
mAttacher.setOnPhotoTapListener(listener);
}
@Override
public void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener) {
mAttacher.setOnViewTapListener(listener);
}
@Override
public void setScale(float scale) {
mAttacher.setScale(scale);
}
@Override
public void setScale(float scale, boolean animate) {
mAttacher.setScale(scale, animate);
}
@Override
public void setScale(float scale, float focalX, float focalY, boolean animate) {
mAttacher.setScale(scale, focalX, focalY, animate);
}
@Override
public void setScaleType(ScaleType scaleType) {
if (null != mAttacher) {
mAttacher.setScaleType(scaleType);
} else {
mPendingScaleType = scaleType;
}
}
@Override
public void setZoomable(boolean zoomable) {
mAttacher.setZoomable(zoomable);
}
@Override
public Bitmap getVisibleRectangleBitmap() {
return mAttacher.getVisibleRectangleBitmap();
}
@Override
public void setZoomTransitionDuration(int milliseconds) {
mAttacher.setZoomTransitionDuration(milliseconds);
}
@Override
public IPhotoView getIPhotoViewImplementation() {
return mAttacher;
}
@Override
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
}
@Override
public void setOnScaleChangeListener(PhotoViewAttacher.OnScaleChangeListener onScaleChangeListener) {
mAttacher.setOnScaleChangeListener(onScaleChangeListener);
}
@Override
public void setOnSingleFlingListener(PhotoViewAttacher.OnSingleFlingListener onSingleFlingListener) {
mAttacher.setOnSingleFlingListener(onSingleFlingListener);
}
@Override
protected void onDetachedFromWindow() {
mAttacher.cleanup();
mAttacher.resetMatrix();
mAttacher = null;
super.onDetachedFromWindow();
}
@Override
protected void onAttachedToWindow() {
init();
super.onAttachedToWindow();
}
public void resetMatrix() {
if (mAttacher != null) {
mAttacher.cleanup();
mAttacher.resetMatrix();
}
}
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import androidx.core.view.MotionEventCompat;
import java.lang.ref.WeakReference;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
public class PhotoViewAttacher implements IPhotoView, View.OnTouchListener,
OnGestureListener,
ViewTreeObserver.OnGlobalLayoutListener {
private static final String LOG_TAG = "PhotoViewAttacher";
// let debug flag be dynamic, but still Proguard can be used to remove from
// release builds
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
private Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
int ZOOM_DURATION = DEFAULT_ZOOM_DURATION;
static final int EDGE_NONE = -1;
static final int EDGE_LEFT = 0;
static final int EDGE_RIGHT = 1;
static final int EDGE_BOTH = 2;
static int SINGLE_TOUCH = 1;
private float mMinScale = DEFAULT_MIN_SCALE;
private float mMidScale = DEFAULT_MID_SCALE;
private float mMaxScale = DEFAULT_MAX_SCALE;
private boolean mAllowParentInterceptOnEdge = true;
private boolean mBlockParentIntercept = false;
private static void checkZoomLevels(float minZoom, float midZoom,
float maxZoom) {
if (minZoom >= midZoom) {
throw new IllegalArgumentException(
"Minimum zoom has to be less than Medium zoom. Call setMinimumZoom() with a more appropriate value");
} else if (midZoom >= maxZoom) {
throw new IllegalArgumentException(
"Medium zoom has to be less than Maximum zoom. Call setMaximumZoom() with a more appropriate value");
}
}
/**
* @return true if the ImageView exists, and its Drawable exists
*/
private static boolean hasDrawable(ImageView imageView) {
return null != imageView && null != imageView.getDrawable();
}
/**
* @return true if the ScaleType is supported.
*/
private static boolean isSupportedScaleType(final ScaleType scaleType) {
if (null == scaleType) {
return false;
}
switch (scaleType) {
case MATRIX:
throw new IllegalArgumentException(scaleType.name()
+ " is not supported in PhotoView");
default:
return true;
}
}
/**
* Sets the ImageView's ScaleType to Matrix.
*/
private static void setImageViewScaleTypeMatrix(ImageView imageView) {
/**
* PhotoView sets its own ScaleType to Matrix, then diverts all calls
* setScaleType to this.setScaleType automatically.
*/
if (null != imageView && !(imageView instanceof IPhotoView)) {
if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
imageView.setScaleType(ScaleType.MATRIX);
}
}
}
private WeakReference<ImageView> mImageView;
// Gesture Detectors
private GestureDetector mGestureDetector;
private com.yidianling.consultant.preview.GestureDetector mScaleDragDetector;
// These are set so we don't keep allocating them on the heap
private final Matrix mBaseMatrix = new Matrix();
private final Matrix mDrawMatrix = new Matrix();
private final Matrix mSuppMatrix = new Matrix();
private final RectF mDisplayRect = new RectF();
private final float[] mMatrixValues = new float[9];
// Listeners
private OnMatrixChangedListener mMatrixChangeListener;
private OnPhotoTapListener mPhotoTapListener;
private OnViewTapListener mViewTapListener;
private OnLongClickListener mLongClickListener;
private OnScaleChangeListener mScaleChangeListener;
private OnSingleFlingListener mSingleFlingListener;
private int mIvTop, mIvRight, mIvBottom, mIvLeft;
private FlingRunnable mCurrentFlingRunnable;
private int mScrollEdge = EDGE_BOTH;
private float mBaseRotation;
private boolean mZoomEnabled;
private ScaleType mScaleType = ScaleType.FIT_CENTER;
public PhotoViewAttacher(ImageView imageView) {
this(imageView, true);
}
public PhotoViewAttacher(ImageView imageView, boolean zoomable) {
mImageView = new WeakReference<>(imageView);
imageView.setDrawingCacheEnabled(true);
imageView.setOnTouchListener(this);
ViewTreeObserver observer = imageView.getViewTreeObserver();
if (null != observer)
observer.addOnGlobalLayoutListener(this);
// Make sure we using MATRIX Scale Type
setImageViewScaleTypeMatrix(imageView);
if (imageView.isInEditMode()) {
return;
}
// Create Gesture Detectors...
mScaleDragDetector = VersionedGestureDetector.newInstance(
imageView.getContext(), this);
mGestureDetector = new GestureDetector(imageView.getContext(),
new GestureDetector.SimpleOnGestureListener() {
// forward long click listener
@Override
public void onLongPress(MotionEvent e) {
if (null != getImageView() && null != mLongClickListener && getImageView().getY() == 0 && getImageView().getX() == 0) {
mLongClickListener.onLongClick(getImageView());
}
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if (mSingleFlingListener != null) {
if (getScale() > DEFAULT_MIN_SCALE) {
return false;
}
if (MotionEventCompat.getPointerCount(e1) > SINGLE_TOUCH
|| MotionEventCompat.getPointerCount(e2) > SINGLE_TOUCH) {
return false;
}
return mSingleFlingListener.onFling(e1, e2, velocityX, velocityY);
}
return false;
}
});
mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
mBaseRotation = 0.0f;
// Finally, update the UI so that we're zoomable
setZoomable(zoomable);
}
@Override
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
if (newOnDoubleTapListener != null) {
this.mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
} else {
this.mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
}
}
@Override
public void setOnScaleChangeListener(OnScaleChangeListener onScaleChangeListener) {
this.mScaleChangeListener = onScaleChangeListener;
}
@Override
public void setOnSingleFlingListener(OnSingleFlingListener onSingleFlingListener) {
this.mSingleFlingListener = onSingleFlingListener;
}
@Override
public boolean canZoom() {
return mZoomEnabled;
}
@SuppressWarnings("deprecation")
public void cleanup() {
if (null == mImageView) {
return; // cleanup already done
}
final ImageView imageView = mImageView.get();
if (null != imageView) {
// Remove this as a global layout listener
ViewTreeObserver observer = imageView.getViewTreeObserver();
if (null != observer && observer.isAlive()) {
observer.removeGlobalOnLayoutListener(this);
}
// Remove the ImageView's reference to this
imageView.setOnTouchListener(null);
// make sure a pending fling runnable won't be run
cancelFling();
}
if (null != mGestureDetector) {
mGestureDetector.setOnDoubleTapListener(null);
}
// Clear listeners too
mMatrixChangeListener = null;
mPhotoTapListener = null;
mViewTapListener = null;
// Finally, clear ImageView
mImageView = null;
}
@Override
public RectF getDisplayRect() {
checkMatrixBounds();
return getDisplayRect(getDrawMatrix());
}
@Override
public boolean setDisplayMatrix(Matrix finalMatrix) {
if (finalMatrix == null) {
throw new IllegalArgumentException("Matrix cannot be null");
}
ImageView imageView = getImageView();
if (null == imageView) {
return false;
}
if (null == imageView.getDrawable()) {
return false;
}
mSuppMatrix.set(finalMatrix);
setImageViewMatrix(getDrawMatrix());
checkMatrixBounds();
return true;
}
public void setBaseRotation(final float degrees) {
mBaseRotation = degrees % 360;
update();
setRotationBy(mBaseRotation);
checkAndDisplayMatrix();
}
@Override
public void setRotationTo(float degrees) {
mSuppMatrix.setRotate(degrees % 360);
checkAndDisplayMatrix();
}
@Override
public void setRotationBy(float degrees) {
mSuppMatrix.postRotate(degrees % 360);
checkAndDisplayMatrix();
}
public ImageView getImageView() {
ImageView imageView = null;
if (null != mImageView) {
imageView = mImageView.get();
}
// If we don't have an ImageView, call cleanup()
if (null == imageView) {
cleanup();
Log.i(LOG_TAG,
"ImageView no longer exists. You should not use this PhotoViewAttacher any more.");
}
return imageView;
}
@Override
public float getMinimumScale() {
return mMinScale;
}
@Override
public float getMediumScale() {
return mMidScale;
}
@Override
public float getMaximumScale() {
return mMaxScale;
}
@Override
public float getScale() {
return (float) Math.sqrt((float) Math.pow(getValue(mSuppMatrix, Matrix.MSCALE_X), 2) + (float) Math.pow(getValue(mSuppMatrix, Matrix.MSKEW_Y), 2));
}
@Override
public ScaleType getScaleType() {
return mScaleType;
}
@Override
public void onDrag(float dx, float dy) {
if (mScaleDragDetector.isScaling()) {
return; // Do not drag if we are already scaling
}
if (DEBUG) {
Log.d(LOG_TAG,
String.format("onDrag: dx: %.2f. dy: %.2f", dx, dy));
}
ImageView imageView = getImageView();
mSuppMatrix.postTranslate(dx, dy);
checkAndDisplayMatrix();
/**
* Here we decide whether to let the ImageView's parent to start taking
* over the touch event.
*
* First we check whether this function is enabled. We never want the
* parent to take over if we're scaling. We then check the edge we're
* on, and the direction of the scroll (i.e. if we're pulling against
* the edge, aka 'overscrolling', let the parent take over).
*/
ViewParent parent = imageView.getParent();
if (mAllowParentInterceptOnEdge && !mScaleDragDetector.isScaling() && !mBlockParentIntercept) {
if (mScrollEdge == EDGE_BOTH
|| (mScrollEdge == EDGE_LEFT && dx >= 1f)
|| (mScrollEdge == EDGE_RIGHT && dx <= -1f)) {
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(false);
}
}
} else {
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
@Override
public void onFling(float startX, float startY, float velocityX,
float velocityY) {
if (DEBUG) {
Log.d(
LOG_TAG,
"onFling. sX: " + startX + " sY: " + startY + " Vx: "
+ velocityX + " Vy: " + velocityY);
}
ImageView imageView = getImageView();
mCurrentFlingRunnable = new FlingRunnable(imageView.getContext());
mCurrentFlingRunnable.fling(getImageViewWidth(imageView),
getImageViewHeight(imageView), (int) velocityX, (int) velocityY);
imageView.post(mCurrentFlingRunnable);
}
@Override
public void onGlobalLayout() {
ImageView imageView = getImageView();
if (null != imageView) {
if (mZoomEnabled) {
final int top = imageView.getTop();
final int right = imageView.getRight();
final int bottom = imageView.getBottom();
final int left = imageView.getLeft();
/**
* We need to check whether the ImageView's bounds have changed.
* This would be easier if we targeted API 11+ as we could just use
* View.OnLayoutChangeListener. Instead we have to replicate the
* work, keeping track of the ImageView's bounds and then checking
* if the values change.
*/
if (top != mIvTop || bottom != mIvBottom || left != mIvLeft
|| right != mIvRight) {
// Update our base matrix, as the bounds have changed
updateBaseMatrix(imageView.getDrawable());
// Update values as something has changed
mIvTop = top;
mIvRight = right;
mIvBottom = bottom;
mIvLeft = left;
}
} else {
updateBaseMatrix(imageView.getDrawable());
}
}
}
@Override
public void onScale(float scaleFactor, float focusX, float focusY) {
if (DEBUG) {
Log.d(
LOG_TAG,
String.format("onScale: scale: %.2f. fX: %.2f. fY: %.2f",
scaleFactor, focusX, focusY));
}
if ((getScale() < mMaxScale || scaleFactor < 1f) && (getScale() > mMinScale || scaleFactor > 1f)) {
if (null != mScaleChangeListener) {
mScaleChangeListener.onScaleChange(scaleFactor, focusX, focusY);
}
mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
checkAndDisplayMatrix();
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent ev) {
boolean handled = false;
if (mZoomEnabled && hasDrawable((ImageView) v)) {
ViewParent parent = v.getParent();
switch (ev.getAction()) {
case ACTION_DOWN:
// First, disable the Parent from intercepting the touch
// event
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(true);
} else {
Log.i(LOG_TAG, "onTouch getParent() returned null");
}
// If we're flinging, and the user presses down, cancel
// fling
cancelFling();
break;
case ACTION_CANCEL:
case ACTION_UP:
// If the user has zoomed less than min scale, zoom back
// to min scale
if (getScale() < mMinScale) {
RectF rect = getDisplayRect();
if (null != rect) {
v.post(new AnimatedZoomRunnable(getScale(), mMinScale,
rect.centerX(), rect.centerY()));
handled = true;
}
}
default: {
}
break;
}
// Try the Scale/Drag detector
if (null != mScaleDragDetector) {
boolean wasScaling = mScaleDragDetector.isScaling();
boolean wasDragging = mScaleDragDetector.isDragging();
handled = mScaleDragDetector.onTouchEvent(ev);
boolean didntScale = !wasScaling && !mScaleDragDetector.isScaling();
boolean didntDrag = !wasDragging && !mScaleDragDetector.isDragging();
mBlockParentIntercept = didntScale && didntDrag;
}
// Check to see if the user double tapped
if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
handled = true;
}
}
return handled;
}
@Override
public void setAllowParentInterceptOnEdge(boolean allow) {
mAllowParentInterceptOnEdge = allow;
}
@Override
public void setMinimumScale(float minimumScale) {
checkZoomLevels(minimumScale, mMidScale, mMaxScale);
mMinScale = minimumScale;
}
@Override
public void setMediumScale(float mediumScale) {
checkZoomLevels(mMinScale, mediumScale, mMaxScale);
mMidScale = mediumScale;
}
@Override
public void setMaximumScale(float maximumScale) {
checkZoomLevels(mMinScale, mMidScale, maximumScale);
mMaxScale = maximumScale;
}
@Override
public void setScaleLevels(float minimumScale, float mediumScale, float maximumScale) {
checkZoomLevels(minimumScale, mediumScale, maximumScale);
mMinScale = minimumScale;
mMidScale = mediumScale;
mMaxScale = maximumScale;
}
@Override
public void setOnLongClickListener(OnLongClickListener listener) {
mLongClickListener = listener;
}
@Override
public void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
mMatrixChangeListener = listener;
}
@Override
public void setOnPhotoTapListener(OnPhotoTapListener listener) {
mPhotoTapListener = listener;
}
OnPhotoTapListener getOnPhotoTapListener() {
return mPhotoTapListener;
}
@Override
public void setOnViewTapListener(OnViewTapListener listener) {
mViewTapListener = listener;
}
OnViewTapListener getOnViewTapListener() {
return mViewTapListener;
}
@Override
public void setScale(float scale) {
setScale(scale, false);
}
@Override
public void setScale(float scale, boolean animate) {
ImageView imageView = getImageView();
if (null != imageView) {
setScale(scale,
(imageView.getRight()) / 2,
(imageView.getBottom()) / 2,
animate);
}
}
@Override
public void setScale(float scale, float focalX, float focalY,
boolean animate) {
ImageView imageView = getImageView();
if (null != imageView) {
// Check to see if the scale is within bounds
if (scale < mMinScale || scale > mMaxScale) {
Log.i(LOG_TAG,
"Scale must be within the range of minScale and maxScale");
return;
}
if (animate) {
imageView.post(new AnimatedZoomRunnable(getScale(), scale,
focalX, focalY));
} else {
mSuppMatrix.setScale(scale, scale, focalX, focalY);
checkAndDisplayMatrix();
}
}
}
/**
* Set the zoom interpolator
*
* @param interpolator the zoom interpolator
*/
public void setZoomInterpolator(Interpolator interpolator) {
mInterpolator = interpolator;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (isSupportedScaleType(scaleType) && scaleType != mScaleType) {
mScaleType = scaleType;
// Finally update
update();
}
}
@Override
public void setZoomable(boolean zoomable) {
mZoomEnabled = zoomable;
update();
}
public void update() {
ImageView imageView = getImageView();
if (null != imageView) {
if (mZoomEnabled) {
// Make sure we using MATRIX Scale Type
setImageViewScaleTypeMatrix(imageView);
// Update the base matrix using the current drawable
updateBaseMatrix(imageView.getDrawable());
} else {
// Reset the Matrix...
resetMatrix();
}
}
}
/**
* Get the display matrix
*
* @param matrix target matrix to copy to
*/
@Override
public void getDisplayMatrix(Matrix matrix) {
matrix.set(getDrawMatrix());
}
/**
* Get the current support matrix
*/
public void getSuppMatrix(Matrix matrix) {
matrix.set(mSuppMatrix);
}
private Matrix getDrawMatrix() {
mDrawMatrix.set(mBaseMatrix);
mDrawMatrix.postConcat(mSuppMatrix);
return mDrawMatrix;
}
private void cancelFling() {
if (null != mCurrentFlingRunnable) {
mCurrentFlingRunnable.cancelFling();
mCurrentFlingRunnable = null;
}
}
public Matrix getImageMatrix() {
return mDrawMatrix;
}
/**
* Helper method that simply checks the Matrix, and then displays the result
*/
private void checkAndDisplayMatrix() {
if (checkMatrixBounds()) {
setImageViewMatrix(getDrawMatrix());
}
}
private void checkImageViewScaleType() {
ImageView imageView = getImageView();
/**
* PhotoView's getScaleType() will just divert to this.getScaleType() so
* only call if we're not attached to a PhotoView.
*/
if (null != imageView && !(imageView instanceof IPhotoView)) {
if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {
throw new IllegalStateException(
"The ImageView's ScaleType has been changed since attaching a PhotoViewAttacher. You should call setScaleType on the PhotoViewAttacher instead of on the ImageView");
}
}
}
private boolean checkMatrixBounds() {
final ImageView imageView = getImageView();
if (null == imageView) {
return false;
}
final RectF rect = getDisplayRect(getDrawMatrix());
if (null == rect) {
return false;
}
final float height = rect.height(), width = rect.width();
float deltaX = 0, deltaY = 0;
final int viewHeight = getImageViewHeight(imageView);
if (height <= viewHeight) {
switch (mScaleType) {
case FIT_START:
deltaY = -rect.top;
break;
case FIT_END:
deltaY = viewHeight - height - rect.top;
break;
default:
deltaY = (viewHeight - height) / 2 - rect.top;
break;
}
} else if (rect.top > 0) {
deltaY = -rect.top;
} else if (rect.bottom < viewHeight) {
deltaY = viewHeight - rect.bottom;
}
final int viewWidth = getImageViewWidth(imageView);
if (width <= viewWidth) {
switch (mScaleType) {
case FIT_START:
deltaX = -rect.left;
break;
case FIT_END:
deltaX = viewWidth - width - rect.left;
break;
default:
deltaX = (viewWidth - width) / 2 - rect.left;
break;
}
mScrollEdge = EDGE_BOTH;
} else if (rect.left > 0) {
mScrollEdge = EDGE_LEFT;
deltaX = -rect.left;
} else if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
mScrollEdge = EDGE_RIGHT;
} else {
mScrollEdge = EDGE_NONE;
}
// Finally actually translate the matrix
mSuppMatrix.postTranslate(deltaX, deltaY);
return true;
}
/**
* Helper method that maps the supplied Matrix to the current Drawable
*
* @param matrix - Matrix to map Drawable against
* @return RectF - Displayed Rectangle
*/
private RectF getDisplayRect(Matrix matrix) {
ImageView imageView = getImageView();
if (null != imageView) {
Drawable d = imageView.getDrawable();
if (null != d) {
mDisplayRect.set(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
matrix.mapRect(mDisplayRect);
return mDisplayRect;
}
}
return null;
}
@Override
public Bitmap getVisibleRectangleBitmap() {
ImageView imageView = getImageView();
return imageView == null ? null : imageView.getDrawingCache();
}
@Override
public void setZoomTransitionDuration(int milliseconds) {
if (milliseconds < 0)
milliseconds = DEFAULT_ZOOM_DURATION;
this.ZOOM_DURATION = milliseconds;
}
@Override
public IPhotoView getIPhotoViewImplementation() {
return this;
}
/**
* Helper method that 'unpacks' a Matrix and returns the required value
*
* @param matrix - Matrix to unpack
* @param whichValue - Which value from Matrix.M* to return
* @return float - returned value
*/
private float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
/**
* Resets the Matrix back to FIT_CENTER, and then displays it.s
*/
public void resetMatrix() {
mSuppMatrix.reset();
setRotationBy(mBaseRotation);
setImageViewMatrix(getDrawMatrix());
checkMatrixBounds();
}
private void setImageViewMatrix(Matrix matrix) {
ImageView imageView = getImageView();
if (null != imageView) {
checkImageViewScaleType();
imageView.setImageMatrix(matrix);
// Call MatrixChangedListener if needed
if (null != mMatrixChangeListener) {
RectF displayRect = getDisplayRect(matrix);
if (null != displayRect) {
mMatrixChangeListener.onMatrixChanged(displayRect);
}
}
}
}
/**
* Calculate Matrix for FIT_CENTER
*
* @param d - Drawable being displayed
*/
private void updateBaseMatrix(Drawable d) {
ImageView imageView = getImageView();
if (null == imageView || null == d) {
return;
}
final float viewWidth = getImageViewWidth(imageView);
final float viewHeight = getImageViewHeight(imageView);
final int drawableWidth = d.getIntrinsicWidth();
final int drawableHeight = d.getIntrinsicHeight();
mBaseMatrix.reset();
final float widthScale = viewWidth / drawableWidth;
final float heightScale = viewHeight / drawableHeight;
if (mScaleType == ScaleType.CENTER) {
mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F,
(viewHeight - drawableHeight) / 2F);
} else if (mScaleType == ScaleType.CENTER_CROP) {
float scale = Math.max(widthScale, heightScale);
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else if (mScaleType == ScaleType.CENTER_INSIDE) {
float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else {
RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
if ((int) mBaseRotation % 180 != 0) {
mTempSrc = new RectF(0, 0, drawableHeight, drawableWidth);
}
switch (mScaleType) {
case FIT_CENTER:
mBaseMatrix
.setRectToRect(mTempSrc, mTempDst, ScaleToFit.CENTER);
break;
case FIT_START:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.START);
break;
case FIT_END:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
break;
case FIT_XY:
mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.FILL);
break;
default:
break;
}
}
resetMatrix();
}
private int getImageViewWidth(ImageView imageView) {
if (null == imageView)
return 0;
return imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
}
private int getImageViewHeight(ImageView imageView) {
if (null == imageView)
return 0;
return imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
}
/**
* Interface definition for a callback to be invoked when the internal Matrix has changed for
* this View.
*
* @author Chris Banes
*/
public interface OnMatrixChangedListener {
/**
* Callback for when the Matrix displaying the Drawable has changed. This could be because
* the View's bounds have changed, or the user has zoomed.
*
* @param rect - Rectangle displaying the Drawable's new bounds.
*/
void onMatrixChanged(RectF rect);
}
/**
* Interface definition for callback to be invoked when attached ImageView scale changes
*
* @author Marek Sebera
*/
public interface OnScaleChangeListener {
/**
* Callback for when the scale changes
*
* @param scaleFactor the scale factor (less than 1 for zoom out, greater than 1 for zoom in)
* @param focusX focal point X position
* @param focusY focal point Y position
*/
void onScaleChange(float scaleFactor, float focusX, float focusY);
}
/**
* Interface definition for a callback to be invoked when the Photo is tapped with a single
* tap.
*
* @author Chris Banes
*/
public interface OnPhotoTapListener {
/**
* A callback to receive where the user taps on a photo. You will only receive a callback if
* the user taps on the actual photo, tapping on 'whitespace' will be ignored.
*
* @param view - View the user tapped.
* @param x - where the user tapped from the of the Drawable, as percentage of the
* Drawable width.
* @param y - where the user tapped from the top of the Drawable, as percentage of the
* Drawable height.
*/
void onPhotoTap(View view, float x, float y);
/**
* A simple callback where out of photo happened;
*/
void onOutsidePhotoTap();
}
/**
* Interface definition for a callback to be invoked when the ImageView is tapped with a single
* tap.
*
* @author Chris Banes
*/
public interface OnViewTapListener {
/**
* A callback to receive where the user taps on a ImageView. You will receive a callback if
* the user taps anywhere on the view, tapping on 'whitespace' will not be ignored.
*
* @param view - View the user tapped.
* @param x - where the user tapped from the left of the View.
* @param y - where the user tapped from the top of the View.
*/
void onViewTap(View view, float x, float y);
}
/**
* Interface definition for a callback to be invoked when the ImageView is fling with a single
* touch
*
* @author tonyjs
*/
public interface OnSingleFlingListener {
/**
* A callback to receive where the user flings on a ImageView. You will receive a callback if
* the user flings anywhere on the view.
*
* @param e1 - MotionEvent the user first touch.
* @param e2 - MotionEvent the user last touch.
* @param velocityX - distance of user's horizontal fling.
* @param velocityY - distance of user's vertical fling.
*/
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}
private class AnimatedZoomRunnable implements Runnable {
private final float mFocalX, mFocalY;
private final long mStartTime;
private final float mZoomStart, mZoomEnd;
public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
final float focalX, final float focalY) {
mFocalX = focalX;
mFocalY = focalY;
mStartTime = System.currentTimeMillis();
mZoomStart = currentZoom;
mZoomEnd = targetZoom;
}
@Override
public void run() {
ImageView imageView = getImageView();
if (imageView == null) {
return;
}
float t = interpolate();
float scale = mZoomStart + t * (mZoomEnd - mZoomStart);
float deltaScale = scale / getScale();
onScale(deltaScale, mFocalX, mFocalY);
// We haven't hit our target scale yet, so post ourselves again
if (t < 1f) {
Compat.postOnAnimation(imageView, this);
}
}
private float interpolate() {
float t = 1f * (System.currentTimeMillis() - mStartTime) / ZOOM_DURATION;
t = Math.min(1f, t);
t = mInterpolator.getInterpolation(t);
return t;
}
}
private class FlingRunnable implements Runnable {
private final ScrollerProxy mScroller;
private int mCurrentX, mCurrentY;
public FlingRunnable(Context context) {
mScroller = ScrollerProxy.getScroller(context);
}
public void cancelFling() {
if (DEBUG) {
Log.d(LOG_TAG, "Cancel Fling");
}
mScroller.forceFinished(true);
}
public void fling(int viewWidth, int viewHeight, int velocityX,
int velocityY) {
final RectF rect = getDisplayRect();
if (null == rect) {
return;
}
final int startX = Math.round(-rect.left);
final int minX, maxX, minY, maxY;
if (viewWidth < rect.width()) {
minX = 0;
maxX = Math.round(rect.width() - viewWidth);
} else {
minX = maxX = startX;
}
final int startY = Math.round(-rect.top);
if (viewHeight < rect.height()) {
minY = 0;
maxY = Math.round(rect.height() - viewHeight);
} else {
minY = maxY = startY;
}
mCurrentX = startX;
mCurrentY = startY;
if (DEBUG) {
Log.d(
LOG_TAG,
"fling. StartX:" + startX + " StartY:" + startY
+ " MaxX:" + maxX + " MaxY:" + maxY);
}
// If we actually can move, fling the scroller
if (startX != maxX || startY != maxY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX,
maxX, minY, maxY, 0, 0);
}
}
@Override
public void run() {
if (mScroller.isFinished()) {
return; // remaining post that should not be handled
}
ImageView imageView = getImageView();
if (null != imageView && mScroller.computeScrollOffset()) {
final int newX = mScroller.getCurrX();
final int newY = mScroller.getCurrY();
if (DEBUG) {
Log.d(
LOG_TAG,
"fling run(). CurrentX:" + mCurrentX + " CurrentY:"
+ mCurrentY + " NewX:" + newX + " NewY:"
+ newY);
}
mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
setImageViewMatrix(getDrawMatrix());
mCurrentX = newX;
mCurrentY = newY;
// Post On animation
Compat.postOnAnimation(imageView, this);
}
}
}
}
package com.yidianling.consultant.preview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.viewpager.widget.ViewPager;
/**
* Issues With ViewGroups
*
* @author rainb
*/
public class PhotoViewPager extends ViewPager {
public PhotoViewPager(Context context) {
super(context);
}
public PhotoViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
}
}
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.content.Context;
import android.widget.Scroller;
/**
* @author rainb
*/
public class PreGingerScroller extends ScrollerProxy {
private final Scroller mScroller;
public PreGingerScroller(Context context) {
mScroller = new Scroller(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
@Override
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
int overX, int overY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
}
@Override
public void forceFinished(boolean finished) {
mScroller.forceFinished(finished);
}
@Override
public boolean isFinished() {
return mScroller.isFinished();
}
@Override
public int getCurrX() {
return mScroller.getCurrX();
}
@Override
public int getCurrY() {
return mScroller.getCurrY();
}
}
\ No newline at end of file
/*******************************************************************************
* 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.yidianling.consultant.preview;
import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
/**
* @author rainb
*/
public abstract class ScrollerProxy {
public static ScrollerProxy getScroller(Context context) {
if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
return new PreGingerScroller(context);
} else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
return new GingerScroller(context);
} else {
return new IcsScroller(context);
}
}
public abstract boolean computeScrollOffset();
public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY,
int maxY, int overX, int overY);
public abstract void forceFinished(boolean finished);
public abstract boolean isFinished();
public abstract int getCurrX();
public abstract int getCurrY();
}
package com.yidianling.consultant.preview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import com.ydl.ydlcommon.utils.StatusBarUtils;
import com.yidianling.consultant.R;
/**
* Deprecated: 缩放图片
***/
public class SmoothImageView extends PhotoView {
public enum Status {
STATE_NORMAL,
STATE_IN,
STATE_OUT,
STATE_MOVE,
}
private Status mStatus = Status.STATE_NORMAL;
private static int TRANSFORM_DURATION = 400;
private static boolean ISFUll = false;
private static boolean ISSCALE = false;
private Paint mPaint;
private Matrix matrix;
private Transform startTransform;
private Transform endTransform;
private Transform animTransform;
private Rect thumbRect;
private boolean transformStart;
private int bitmapWidth;
private int bitmapHeight;
private boolean isDrag;
ValueAnimator animator;
private float MAX_TRANS_SCALE = 0.2f;
private boolean isMaskPoint = false;
private View btnLL;
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
bitmapWidth = 0;
bitmapHeight = 0;
thumbRect = null;
btnLL = null;
ISFUll = false;
if (animator != null) {
animator.cancel();
animator.clone();
animator = null;
}
}
private void initSmoothImageView() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(0xFF000000);
matrix = new Matrix();
setScaleType(ImageView.ScaleType.FIT_CENTER);
}
public boolean checkMinScale() {
if (getScale() != 1) {
setScale(1, true);
return false;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
if (mStatus == Status.STATE_OUT || mStatus == Status.STATE_IN) {
if (startTransform == null || endTransform == null || animTransform == null) {
initTransform();
}
if (animTransform == null) {
super.onDraw(canvas);
return;
}
mPaint.setAlpha(animTransform.alpha);
canvas.drawPaint(mPaint);
int saveCount = canvas.getSaveCount();
matrix.setScale(animTransform.scale, animTransform.scale);
float translateX = -(bitmapWidth * animTransform.scale - animTransform.width) / 2;
float translateY = -(bitmapHeight * animTransform.scale - animTransform.height) / 2;
matrix.postTranslate(translateX, translateY);
canvas.translate(animTransform.left, animTransform.top);
canvas.clipRect(0, 0, animTransform.width, animTransform.height);
canvas.concat(matrix);
getDrawable().draw(canvas);
canvas.restoreToCount(saveCount);
if (transformStart) {
startTransform();
}
} else if (mStatus == Status.STATE_MOVE) {
mPaint.setAlpha(0);
canvas.drawPaint(mPaint);
super.onDraw(canvas);
} else {
mPaint.setAlpha(255);
canvas.drawPaint(mPaint);
super.onDraw(canvas);
}
}
private int downX, downY;
private boolean isMoved = false;
private boolean isDownPhoto = false;
private int alpha = 0;
private static final int MIN_TRANS_DEST = 5;
private void actionDown(MotionEvent event) {
isMaskPoint = false;
downX = (int) event.getX();
downY = (int) event.getY();
if (markTransform == null) {
initTransform();
}
isDownPhoto = false;
if (markTransform != null) {
int startY = (int) markTransform.top;
int endY = (int) (markTransform.height + markTransform.top);
if (downY >= startY && endY >= downY) {
isDownPhoto = true;
}
}
isMoved = false;
}
private boolean actionMove(MotionEvent event) {
if (!isDownPhoto && event.getPointerCount() == 1) {
return super.dispatchTouchEvent(event);
}
int mx = (int) event.getX();
int my = (int) event.getY();
int offsetX = mx - downX;
int offsetY = my - downY;
// 水平方向移动不予处理
boolean s = !isMoved && (Math.abs(offsetX) > Math.abs(offsetY) || Math.abs(offsetY) < MIN_TRANS_DEST);
if (s) {
return super.dispatchTouchEvent(event);
} else {
if (isDrag || isMaskPoint) {
return super.dispatchTouchEvent(event);
}
// 一指滑动时,才对图片进行移动缩放处理
if (event.getPointerCount() == 1) {
mStatus = Status.STATE_MOVE;
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
float scale = moveScale();
float scaleXY = 1 - scale * 0.1f;
setScaleY(scaleXY);
setScaleX(scaleXY);
isMoved = true;
alpha = (int) (255 * (1 - scale * 0.5f));
invalidate();
if (alpha < 0) {
alpha = 0;
}
if (btnLL != null && btnLL.getVisibility() == View.VISIBLE) {
btnLL.setVisibility(INVISIBLE);
}
if (alphaChangeListener != null) {
alphaChangeListener.onAlphaChange(alpha);
}
return true;
} else {
return super.dispatchTouchEvent(event);
}
}
}
private boolean actionCancel() {
if (moveScale() <= MAX_TRANS_SCALE) {
moveToOldPosition();
if (btnLL != null && btnLL.getVisibility() != View.VISIBLE) {
btnLL.setVisibility(VISIBLE);
}
} else {
changeTransform();
setTag(R.id.consultant_item_image_key, true);
if (transformOutListener != null) {
transformOutListener.onTransformOut();
}
}
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
if (ISSCALE) {
if (getScale() == 1) {
switch (action) {
case MotionEvent.ACTION_DOWN:
actionDown(event);
break;
case MotionEvent.ACTION_MOVE:
return actionMove(event);
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isMoved) {
return actionCancel();
}
break;
default: {
}
}
return super.dispatchTouchEvent(event);
} else {
switch (action) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isMoved && getScale() <= 1.0) {
return actionCancel();
}
break;
default: {
}
}
return super.dispatchTouchEvent(event);
}
} else {
switch (action) {
case MotionEvent.ACTION_DOWN:
actionDown(event);
break;
case MotionEvent.ACTION_MOVE:
return actionMove(event);
case MotionEvent.ACTION_POINTER_DOWN:
isMaskPoint = true;
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (isMoved) {
if (isMaskPoint) {
return true;
} else {
return actionCancel();
}
}
break;
default: {
}
}
return super.dispatchTouchEvent(event);
}
}
/**
* 未达到关闭的阈值松手时,返回到初始位置
*/
private void moveToOldPosition() {
ValueAnimator va = ValueAnimator.ofInt(getTop(), 0);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int startValue = 0;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
if (startValue != 0) {
offsetTopAndBottom(value - startValue);
}
startValue = value;
}
});
ValueAnimator leftAnim = ValueAnimator.ofInt(getLeft(), 0);
leftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int startValue = 0;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
if (startValue != 0) {
offsetLeftAndRight(value - startValue);
}
startValue = value;
}
});
ValueAnimator alphaAnim = ValueAnimator.ofInt(alpha, 255);
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (alphaChangeListener != null) {
alphaChangeListener.onAlphaChange((Integer) animation.getAnimatedValue());
}
}
});
ValueAnimator scaleAnim = ValueAnimator.ofFloat(getScaleX(), 1);
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float scale = (float) animation.getAnimatedValue();
setScaleX(scale);
setScaleY(scale);
}
});
AnimatorSet as = new AnimatorSet();
as.setDuration(TRANSFORM_DURATION);
as.setInterpolator(new AccelerateDecelerateInterpolator());
as.playTogether(va, leftAnim, scaleAnim, alphaAnim);
as.start();
}
private float moveScale() {
if (markTransform == null) {
initTransform();
}
return Math.abs(getTop() / markTransform.height);
}
private OnAlphaChangeListener alphaChangeListener;
private OnTransformOutListener transformOutListener;
public void setTransformOutListener(OnTransformOutListener transformOutListener) {
this.transformOutListener = transformOutListener;
}
public void setAlphaChangeListener(OnAlphaChangeListener alphaChangeListener) {
this.alphaChangeListener = alphaChangeListener;
}
public interface OnTransformOutListener {
void onTransformOut();
}
public interface OnAlphaChangeListener {
void onAlphaChange(int alpha);
}
private Transform markTransform;
private void changeTransform() {
if (markTransform != null) {
Transform tempTransform = markTransform.clone();
tempTransform.top = markTransform.top + getTop();
tempTransform.left = markTransform.left + getLeft();
tempTransform.alpha = alpha;
tempTransform.scale = markTransform.scale - (1 - getScaleX()) * markTransform.scale;
animTransform = tempTransform.clone();
endTransform = tempTransform.clone();
}
}
private void startTransform() {
transformStart = false;
if (animTransform == null) {
return;
}
animator = new ValueAnimator();
animator.setDuration(TRANSFORM_DURATION);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
if (mStatus == Status.STATE_IN) {
PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("animScale", startTransform.scale, endTransform.scale);
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("animAlpha", startTransform.alpha, endTransform.alpha);
PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("animLeft", startTransform.left, endTransform.left);
PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("animTop", startTransform.top, endTransform.top);
PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("animWidth", startTransform.width, endTransform.width);
PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("animHeight", startTransform.height, endTransform.height);
animator.setValues(scaleHolder, alphaHolder, leftHolder, topHolder, widthHolder, heightHolder);
} else if (mStatus == Status.STATE_OUT) {
PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("animScale", endTransform.scale, startTransform.scale);
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("animAlpha", endTransform.alpha, startTransform.alpha);
PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("animLeft", endTransform.left, startTransform.left);
PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("animTop", endTransform.top, startTransform.top);
PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("animWidth", endTransform.width, startTransform.width);
PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("animHeight", endTransform.height, startTransform.height);
animator.setValues(scaleHolder, alphaHolder, leftHolder, topHolder, widthHolder, heightHolder);
}
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animTransform.alpha = (Integer) animation.getAnimatedValue("animAlpha");
animTransform.scale = (float) animation.getAnimatedValue("animScale");
animTransform.left = (float) animation.getAnimatedValue("animLeft");
animTransform.top = (float) animation.getAnimatedValue("animTop");
animTransform.width = (float) animation.getAnimatedValue("animWidth");
animTransform.height = (float) animation.getAnimatedValue("animHeight");
invalidate();
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
if (getTag(R.id.consultant_item_image_key) != null) {
setTag(R.id.consultant_item_image_key, null);
setOnLongClickListener(null);
}
}
@Override
public void onAnimationEnd(Animator animation) {
/*
* 如果是进入的话,当然是希望最后停留在center_crop的区域。但是如果是out的话,就不应该是center_crop的位置了
* , 而应该是最后变化的位置,因为当out的时候结束时,不回复视图是Normal,要不然会有一个突然闪动回去的bug
*/
if (onTransformListener != null) {
onTransformListener.onTransformCompleted(mStatus);
}
if (mStatus == Status.STATE_IN) {
mStatus = Status.STATE_NORMAL;
}
}
});
animator.start();
}
public void transformIn(onTransformListener listener) {
setOnTransformListener(listener);
transformStart = true;
mStatus = Status.STATE_IN;
invalidate();
}
public void transformOut(onTransformListener listener) {
if (getTop() != 0) {
offsetTopAndBottom(-getTop());
}
if (getLeft() != 0) {
offsetLeftAndRight(-getLeft());
}
if (getScaleX() != 1) {
setScaleX(1);
setScaleY(1);
}
setOnTransformListener(listener);
transformStart = true;
mStatus = Status.STATE_OUT;
invalidate();
}
/**
* 设置起始位置图片的Rect
* g
*
* @param thumbRect 参数
*/
public void setThumbRect(Rect thumbRect) {
this.thumbRect = thumbRect;
}
public void setBtnLL(View view) {
this.btnLL = view;
}
private void initTransform() {
if (getDrawable() == null) {
return;
}
if (startTransform != null && endTransform != null && animTransform != null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
if (getDrawable() instanceof BitmapDrawable) {
Bitmap mBitmap = ((BitmapDrawable) getDrawable()).getBitmap();
bitmapWidth = mBitmap.getWidth();
bitmapHeight = mBitmap.getHeight();
} else if (getDrawable() instanceof ColorDrawable) {
ColorDrawable colorDrawable = (ColorDrawable) getDrawable();
bitmapWidth = colorDrawable.getIntrinsicWidth();
bitmapHeight = colorDrawable.getIntrinsicHeight();
} else {
Bitmap mBitmap = Bitmap.createBitmap(getDrawable().getIntrinsicWidth(),
getDrawable().getIntrinsicHeight(), Bitmap.Config.RGB_565);
bitmapWidth = mBitmap.getWidth();
bitmapHeight = mBitmap.getHeight();
}
startTransform = new Transform();
startTransform.alpha = 0;
if (thumbRect == null) {
thumbRect = new Rect();
}
startTransform.left = thumbRect.left;
if (ISFUll) {
startTransform.top = thumbRect.top;
} else {
startTransform.top = thumbRect.top - StatusBarUtils.Companion.getStatusBarHeight(getContext().getApplicationContext());
}
startTransform.width = thumbRect.width();
startTransform.height = thumbRect.height();
//开始时以CenterCrop方式显示,缩放图片使图片的一边等于起始区域的一边,另一边大于起始区域
float startScaleX = (float) thumbRect.width() / bitmapWidth;
float startScaleY = (float) thumbRect.height() / bitmapHeight;
startTransform.scale = startScaleX > startScaleY ? startScaleX : startScaleY;
//结束时以fitCenter方式显示,缩放图片使图片的一边等于View的一边,另一边大于View
float endScaleX = (float) getWidth() / bitmapWidth;
float endScaleY = (float) getHeight() / bitmapHeight;
endTransform = new Transform();
endTransform.scale = endScaleX < endScaleY ? endScaleX : endScaleY;
endTransform.alpha = 255;
int endBitmapWidth = (int) (endTransform.scale * bitmapWidth);
int endBitmapHeight = (int) (endTransform.scale * bitmapHeight);
endTransform.left = (getWidth() - endBitmapWidth) / 2;
endTransform.top = (getHeight() - endBitmapHeight) / 2;
endTransform.width = endBitmapWidth;
endTransform.height = endBitmapHeight;
if (mStatus == Status.STATE_IN) {
animTransform = startTransform.clone();
} else if (mStatus == Status.STATE_OUT) {
animTransform = endTransform.clone();
}
markTransform = endTransform;
}
private onTransformListener onTransformListener;
public void setOnTransformListener(SmoothImageView.onTransformListener onTransformListener) {
this.onTransformListener = onTransformListener;
}
public interface onTransformListener {
void onTransformCompleted(Status status);
}
private class Transform implements Cloneable {
float left, top, width, height;
int alpha;
float scale;
@Override
public Transform clone() {
Transform obj = null;
try {
obj = (Transform) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return obj;
}
}
public SmoothImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initSmoothImageView();
}
public SmoothImageView(Context context) {
super(context);
initSmoothImageView();
}
/***
* 设置图片拖拽返回
* @param isDrag true 可以 false 默认 true
* **/
public void setDrag(boolean isDrag, float sensitivity) {
this.isDrag = isDrag;
this.MAX_TRANS_SCALE = sensitivity;
}
/***
* 设置动画的时长
* @param duration 单位毫秒
* **/
public static void setDuration(int duration) {
TRANSFORM_DURATION = duration;
}
/***
* 获取动画的时长
* **/
public static int getDuration() {
return TRANSFORM_DURATION;
}
/***
* 设置是否全屏
* @param isFull true 全屏
* **/
public static void setFullscreen(boolean isFull) {
ISFUll = isFull;
}
/***
* 设置只有图片没有放大或者的缩小状态触退出
* @param isScale true false
* **/
public static void setIsScale(boolean isScale) {
ISSCALE = isScale;
}
}
package com.yidianling.consultant.preview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import org.jetbrains.annotations.NotNull;
/**
* @author rainb
*/
public class TestImageLoader implements IZoomMediaLoader {
@Override
public void displayImage(@NonNull Fragment context, @NonNull String path, final ImageView imageView, @NonNull final MySimpleTarget simpleTarget) {
Glide.with(context).asBitmap().load(path)
// .placeholder(android.R.color.darker_gray)
.fitCenter()
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull @NotNull Bitmap resource, @Nullable @org.jetbrains.annotations.Nullable Transition<? super Bitmap> transition) {
simpleTarget.onResourceReady();
imageView.setImageBitmap(resource);
}
});
}
@Override
public void displayGifImage(@NonNull Fragment context, @NonNull String path, ImageView imageView, @NonNull final MySimpleTarget simpleTarget) {
}
@Override
public void onStop(@NonNull Fragment context) {
Glide.with(context).onStop();
}
@Override
public void clearMemory(@NonNull Context c) {
Glide.get(c).clearMemory();
}
}
package com.yidianling.consultant.preview;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Deprecated: 图片预览实体类
*
* @author rainb
*/
public class UserViewInfo implements IThumbViewInfo {
private String url; //图片地址
private Rect mBounds; // 记录坐标
private String user = "用户字段";
private String videoUrl;
public UserViewInfo(String url) {
this.url = url;
}
public UserViewInfo(String videoUrl, String url) {
this.url = url;
this.videoUrl = videoUrl;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
@Override
public String getUrl() {//将你的图片地址字段返回
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public Rect getBounds() {//将你的图片显示坐标字段返回
return mBounds;
}
@Override
public String getVideoUrl() {
return videoUrl;
}
public void setBounds(Rect bounds) {
mBounds = bounds;
}
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.url);
dest.writeParcelable(this.mBounds, flags);
dest.writeString(this.user);
dest.writeString(this.videoUrl);
}
protected UserViewInfo(Parcel in) {
this.url = in.readString();
this.mBounds = in.readParcelable(Rect.class.getClassLoader());
this.user = in.readString();
this.videoUrl = in.readString();
}
public static final Parcelable.Creator<UserViewInfo> CREATOR = new Parcelable.Creator<UserViewInfo>() {
@Override
public UserViewInfo createFromParcel(Parcel source) {
return new UserViewInfo(source);
}
@Override
public UserViewInfo[] newArray(int size) {
return new UserViewInfo[size];
}
};
}
package com.yidianling.consultant.preview;
/*******************************************************************************
* 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.
*******************************************************************************/
import android.content.Context;
import android.os.Build;
/**
* @author rainb
*/
public final class VersionedGestureDetector {
public static GestureDetector newInstance(Context context,
OnGestureListener listener) {
final int sdkVersion = Build.VERSION.SDK_INT;
GestureDetector detector;
if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
detector = new CupcakeGestureDetector(context);
} else if (sdkVersion < Build.VERSION_CODES.FROYO) {
detector = new EclairGestureDetector(context);
} else {
detector = new FroyoGestureDetector(context);
}
detector.setOnGestureListener(listener);
return detector;
}
}
\ No newline at end of file
package com.yidianling.consultant.preview;
/**
* Deprecated: 图片加载管理器
*
* @author rainb
*/
public class ZoomMediaLoader {
private volatile IZoomMediaLoader loader;
public static ZoomMediaLoader getInstance() {
return Holder.holder;
}
private ZoomMediaLoader() {
}
private static class Holder {
static ZoomMediaLoader holder = new ZoomMediaLoader();
}
/****
* 初始化加载图片类
* @param loader 自定义
* **/
public void init(IZoomMediaLoader loader) {
this.loader = loader;
}
public IZoomMediaLoader getLoader() {
if (loader == null) {
throw new NullPointerException("ZoomMediaLoader loader no init");
}
return loader;
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.yidianling.consultant.preview.PhotoViewPager
android:background="@android:color/transparent"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:clickable="false"
android:contentDescription="@null"
android:focusable="false"
android:scaleType="centerCrop"/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<GridView
android:id="@+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:layout_marginLeft="@dimen/platform_dp_10"
android:layout_marginRight="@dimen/platform_dp_10"
android:horizontalSpacing="@dimen/platform_dp_10"
android:verticalSpacing="@dimen/platform_dp_10"/>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
tools:ignore="ResourceName">
<com.yidianling.consultant.preview.SmoothImageView
android:id="@+id/photoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:scaleType="centerInside" />
<RelativeLayout
android:id="@+id/videoContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.dou361.ijkplayer.widget.IjkVideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/btnLL"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/platform_dp_40">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/platform_dp_20"
android:layout_marginRight="@dimen/platform_dp_20"
android:layout_weight="1"
android:background="@drawable/bg_btn_dis" />
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/platform_dp_20"
android:layout_marginRight="@dimen/platform_dp_20"
android:layout_weight="1"
android:background="@color/green_btn" />
</LinearLayout>
<ProgressBar
android:id="@+id/loading"
style="@android:style/Widget.DeviceDefault.Light.ProgressBar"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:visibility="visible" />
<ImageView
android:id="@+id/btnVideo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerInParent="true"
android:alpha="0"
android:visibility="gone" />
</RelativeLayout>
\ No newline at end of file
......@@ -8,4 +8,7 @@
<string name="consultant_reload_hint">加载失败,换个网络环境试试吧</string>
<item name="consultant_item_image_key" type="id" />
</resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment