Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
YDL-Component-Medical
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
杨凯
YDL-Component-Medical
Commits
cce84b56
Commit
cce84b56
authored
Jul 05, 2022
by
fengquan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 咨询师图片/视频预览
parent
cea87958
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
4502 additions
and
1 deletions
+4502
-1
ComponentTestApp.java
app/src/main/java/com/ydl/component/base/ComponentTestApp.java
+3
-1
build.gradle
m-consultant/build.gradle
+1
-0
AndroidManifest.xml
m-consultant/src/main/AndroidManifest.xml
+8
-0
BasePhotoFragment.java
m-consultant/src/main/java/com/yidianling/consultant/preview/BasePhotoFragment.java
+322
-0
Compat.java
m-consultant/src/main/java/com/yidianling/consultant/preview/Compat.java
+62
-0
CupcakeGestureDetector.java
m-consultant/src/main/java/com/yidianling/consultant/preview/CupcakeGestureDetector.java
+151
-0
DefaultOnDoubleTapListener.java
m-consultant/src/main/java/com/yidianling/consultant/preview/DefaultOnDoubleTapListener.java
+100
-0
EclairGestureDetector.java
m-consultant/src/main/java/com/yidianling/consultant/preview/EclairGestureDetector.java
+92
-0
FroyoGestureDetector.java
m-consultant/src/main/java/com/yidianling/consultant/preview/FroyoGestureDetector.java
+76
-0
GPreviewActivity.java
m-consultant/src/main/java/com/yidianling/consultant/preview/GPreviewActivity.java
+185
-0
GPreviewBuilder.java
m-consultant/src/main/java/com/yidianling/consultant/preview/GPreviewBuilder.java
+90
-0
GestureDetector.java
m-consultant/src/main/java/com/yidianling/consultant/preview/GestureDetector.java
+33
-0
GingerScroller.java
m-consultant/src/main/java/com/yidianling/consultant/preview/GingerScroller.java
+65
-0
GridPreviewActivity.java
m-consultant/src/main/java/com/yidianling/consultant/preview/GridPreviewActivity.java
+120
-0
IPhotoView.java
m-consultant/src/main/java/com/yidianling/consultant/preview/IPhotoView.java
+272
-0
IThumbViewInfo.java
m-consultant/src/main/java/com/yidianling/consultant/preview/IThumbViewInfo.java
+34
-0
IZoomMediaLoader.java
m-consultant/src/main/java/com/yidianling/consultant/preview/IZoomMediaLoader.java
+46
-0
IcsScroller.java
m-consultant/src/main/java/com/yidianling/consultant/preview/IcsScroller.java
+36
-0
ImageUrlConfig.java
m-consultant/src/main/java/com/yidianling/consultant/preview/ImageUrlConfig.java
+145
-0
MySimpleTarget.java
m-consultant/src/main/java/com/yidianling/consultant/preview/MySimpleTarget.java
+31
-0
OnGestureListener.java
m-consultant/src/main/java/com/yidianling/consultant/preview/OnGestureListener.java
+31
-0
PhotoView.java
m-consultant/src/main/java/com/yidianling/consultant/preview/PhotoView.java
+277
-0
PhotoViewAttacher.java
m-consultant/src/main/java/com/yidianling/consultant/preview/PhotoViewAttacher.java
+1186
-0
PhotoViewPager.java
m-consultant/src/main/java/com/yidianling/consultant/preview/PhotoViewPager.java
+33
-0
PreGingerScroller.java
m-consultant/src/main/java/com/yidianling/consultant/preview/PreGingerScroller.java
+63
-0
ScrollerProxy.java
m-consultant/src/main/java/com/yidianling/consultant/preview/ScrollerProxy.java
+51
-0
SmoothImageView.java
m-consultant/src/main/java/com/yidianling/consultant/preview/SmoothImageView.java
+629
-0
TestImageLoader.java
m-consultant/src/main/java/com/yidianling/consultant/preview/TestImageLoader.java
+53
-0
UserViewInfo.java
m-consultant/src/main/java/com/yidianling/consultant/preview/UserViewInfo.java
+95
-0
VersionedGestureDetector.java
m-consultant/src/main/java/com/yidianling/consultant/preview/VersionedGestureDetector.java
+46
-0
ZoomMediaLoader.java
m-consultant/src/main/java/com/yidianling/consultant/preview/ZoomMediaLoader.java
+38
-0
consultant_image_preview_photo.xml
m-consultant/src/main/res/layout/consultant_image_preview_photo.xml
+12
-0
consultant_item_image.xml
m-consultant/src/main/res/layout/consultant_item_image.xml
+21
-0
consultant_picture_preview.xml
m-consultant/src/main/res/layout/consultant_picture_preview.xml
+18
-0
fragment_image_photo_layout.xml
m-consultant/src/main/res/layout/fragment_image_photo_layout.xml
+74
-0
strings.xml
m-consultant/src/main/res/values/strings.xml
+3
-0
No files found.
app/src/main/java/com/ydl/component/base/ComponentTestApp.java
View file @
cce84b56
...
...
@@ -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
...
...
m-consultant/build.gradle
View file @
cce84b56
...
...
@@ -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'
)
...
...
m-consultant/src/main/AndroidManifest.xml
View file @
cce84b56
...
...
@@ -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
m-consultant/src/main/java/com/yidianling/consultant/preview/BasePhotoFragment.java
0 → 100644
View file @
cce84b56
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
/
255
f
,
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
;
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/Compat.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
;
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/CupcakeGestureDetector.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
;
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/DefaultOnDoubleTapListener.java
0 → 100644
View file @
cce84b56
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
;
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/EclairGestureDetector.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
;
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/FroyoGestureDetector.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
;
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/GPreviewActivity.java
0 → 100644
View file @
cce84b56
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
();
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/GPreviewBuilder.java
0 → 100644
View file @
cce84b56
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
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/GestureDetector.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
);
}
m-consultant/src/main/java/com/yidianling/consultant/preview/GingerScroller.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
m-consultant/src/main/java/com/yidianling/consultant/preview/GridPreviewActivity.java
0 → 100644
View file @
cce84b56
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
;
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/IPhotoView.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
);
}
m-consultant/src/main/java/com/yidianling/consultant/preview/IThumbViewInfo.java
0 → 100644
View file @
cce84b56
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
();
}
m-consultant/src/main/java/com/yidianling/consultant/preview/IZoomMediaLoader.java
0 → 100644
View file @
cce84b56
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
);
}
m-consultant/src/main/java/com/yidianling/consultant/preview/IcsScroller.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
();
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/ImageUrlConfig.java
0 → 100644
View file @
cce84b56
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
;
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/MySimpleTarget.java
0 → 100644
View file @
cce84b56
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
);
}
m-consultant/src/main/java/com/yidianling/consultant/preview/OnGestureListener.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
m-consultant/src/main/java/com/yidianling/consultant/preview/PhotoView.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
();
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/PhotoViewAttacher.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
>=
1
f
)
||
(
mScrollEdge
==
EDGE_RIGHT
&&
dx
<=
-
1
f
))
{
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
<
1
f
)
&&
(
getScale
()
>
mMinScale
||
scaleFactor
>
1
f
))
{
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
)
/
2
F
,
(
viewHeight
-
drawableHeight
)
/
2
F
);
}
else
if
(
mScaleType
==
ScaleType
.
CENTER_CROP
)
{
float
scale
=
Math
.
max
(
widthScale
,
heightScale
);
mBaseMatrix
.
postScale
(
scale
,
scale
);
mBaseMatrix
.
postTranslate
((
viewWidth
-
drawableWidth
*
scale
)
/
2
F
,
(
viewHeight
-
drawableHeight
*
scale
)
/
2
F
);
}
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
)
/
2
F
,
(
viewHeight
-
drawableHeight
*
scale
)
/
2
F
);
}
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
<
1
f
)
{
Compat
.
postOnAnimation
(
imageView
,
this
);
}
}
private
float
interpolate
()
{
float
t
=
1
f
*
(
System
.
currentTimeMillis
()
-
mStartTime
)
/
ZOOM_DURATION
;
t
=
Math
.
min
(
1
f
,
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
);
}
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/PhotoViewPager.java
0 → 100644
View file @
cce84b56
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
;
}
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/PreGingerScroller.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
m-consultant/src/main/java/com/yidianling/consultant/preview/ScrollerProxy.java
0 → 100644
View file @
cce84b56
/*******************************************************************************
* 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
();
}
m-consultant/src/main/java/com/yidianling/consultant/preview/SmoothImageView.java
0 → 100644
View file @
cce84b56
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
;
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/TestImageLoader.java
0 → 100644
View file @
cce84b56
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
();
}
}
m-consultant/src/main/java/com/yidianling/consultant/preview/UserViewInfo.java
0 → 100644
View file @
cce84b56
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
];
}
};
}
m-consultant/src/main/java/com/yidianling/consultant/preview/VersionedGestureDetector.java
0 → 100644
View file @
cce84b56
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
m-consultant/src/main/java/com/yidianling/consultant/preview/ZoomMediaLoader.java
0 → 100644
View file @
cce84b56
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
;
}
}
m-consultant/src/main/res/layout/consultant_image_preview_photo.xml
0 → 100644
View file @
cce84b56
<?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>
m-consultant/src/main/res/layout/consultant_item_image.xml
0 → 100644
View file @
cce84b56
<?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
m-consultant/src/main/res/layout/consultant_picture_preview.xml
0 → 100644
View file @
cce84b56
<?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
m-consultant/src/main/res/layout/fragment_image_photo_layout.xml
0 → 100644
View file @
cce84b56
<?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
m-consultant/src/main/res/values/strings.xml
View file @
cce84b56
...
...
@@ -8,4 +8,7 @@
<string
name=
"consultant_reload_hint"
>
加载失败,换个网络环境试试吧
</string>
<item
name=
"consultant_item_image_key"
type=
"id"
/>
</resources>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment