Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
InstiApp
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
RAHUL SHARMA
InstiApp
Commits
3541aa3c
Commit
3541aa3c
authored
Jul 18, 2018
by
Sajal Narang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Zoom images on click
parent
4eefdbff
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
2059 additions
and
203 deletions
+2059
-203
app/src/main/java/app/insti/TouchImageView.java
app/src/main/java/app/insti/TouchImageView.java
+1265
-0
app/src/main/java/app/insti/fragment/BackHandledFragment.java
...src/main/java/app/insti/fragment/BackHandledFragment.java
+30
-0
app/src/main/java/app/insti/fragment/BodyFragment.java
app/src/main/java/app/insti/fragment/BodyFragment.java
+190
-9
app/src/main/java/app/insti/fragment/EventFragment.java
app/src/main/java/app/insti/fragment/EventFragment.java
+180
-5
app/src/main/java/app/insti/fragment/ProfileFragment.java
app/src/main/java/app/insti/fragment/ProfileFragment.java
+181
-5
app/src/main/res/layout/fragment_body.xml
app/src/main/res/layout/fragment_body.xml
+24
-16
app/src/main/res/layout/fragment_event.xml
app/src/main/res/layout/fragment_event.xml
+181
-168
app/src/main/res/layout/fragment_profile.xml
app/src/main/res/layout/fragment_profile.xml
+8
-0
No files found.
app/src/main/java/app/insti/TouchImageView.java
0 → 100644
View file @
3541aa3c
package
app.insti
;
import
android.annotation.TargetApi
;
import
android.content.Context
;
import
android.content.res.Configuration
;
import
android.graphics.Bitmap
;
import
android.graphics.Canvas
;
import
android.graphics.Matrix
;
import
android.graphics.PointF
;
import
android.graphics.RectF
;
import
android.graphics.drawable.Drawable
;
import
android.net.Uri
;
import
android.os.Build
;
import
android.os.Build.VERSION
;
import
android.os.Build.VERSION_CODES
;
import
android.os.Bundle
;
import
android.os.Parcelable
;
import
android.util.AttributeSet
;
import
android.util.Log
;
import
android.view.GestureDetector
;
import
android.view.MotionEvent
;
import
android.view.ScaleGestureDetector
;
import
android.view.View
;
import
android.view.animation.AccelerateDecelerateInterpolator
;
import
android.widget.ImageView
;
import
android.widget.OverScroller
;
import
android.widget.Scroller
;
public
class
TouchImageView
extends
android
.
support
.
v7
.
widget
.
AppCompatImageView
{
private
static
final
String
DEBUG
=
"DEBUG"
;
//
// SuperMin and SuperMax multipliers. Determine how much the image can be
// zoomed below or above the zoom boundaries, before animating back to the
// min/max zoom boundary.
//
private
static
final
float
SUPER_MIN_MULTIPLIER
=
.
75
f
;
private
static
final
float
SUPER_MAX_MULTIPLIER
=
1.25f
;
//
// Scale of image ranges from minScale to maxScale, where minScale == 1
// when the image is stretched to fit view.
//
private
float
normalizedScale
;
//
// Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal.
// MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix
// saved prior to the screen rotating.
//
private
Matrix
matrix
,
prevMatrix
;
private
static
enum
State
{
NONE
,
DRAG
,
ZOOM
,
FLING
,
ANIMATE_ZOOM
};
private
State
state
;
private
float
minScale
;
private
float
maxScale
;
private
float
superMinScale
;
private
float
superMaxScale
;
private
float
[]
m
;
private
Context
context
;
private
Fling
fling
;
private
ScaleType
mScaleType
;
private
boolean
imageRenderedAtLeastOnce
;
private
boolean
onDrawReady
;
private
ZoomVariables
delayedZoomVariables
;
//
// Size of view and previous view size (ie before rotation)
//
private
int
viewWidth
,
viewHeight
,
prevViewWidth
,
prevViewHeight
;
//
// Size of image when it is stretched to fit view. Before and After rotation.
//
private
float
matchViewWidth
,
matchViewHeight
,
prevMatchViewWidth
,
prevMatchViewHeight
;
private
ScaleGestureDetector
mScaleDetector
;
private
GestureDetector
mGestureDetector
;
private
GestureDetector
.
OnDoubleTapListener
doubleTapListener
=
null
;
private
OnTouchListener
userTouchListener
=
null
;
private
OnTouchImageViewListener
touchImageViewListener
=
null
;
public
TouchImageView
(
Context
context
)
{
super
(
context
);
sharedConstructing
(
context
);
}
public
TouchImageView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
sharedConstructing
(
context
);
}
public
TouchImageView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
sharedConstructing
(
context
);
}
private
void
sharedConstructing
(
Context
context
)
{
super
.
setClickable
(
true
);
this
.
context
=
context
;
mScaleDetector
=
new
ScaleGestureDetector
(
context
,
new
ScaleListener
());
mGestureDetector
=
new
GestureDetector
(
context
,
new
GestureListener
());
matrix
=
new
Matrix
();
prevMatrix
=
new
Matrix
();
m
=
new
float
[
9
];
normalizedScale
=
1
;
if
(
mScaleType
==
null
)
{
mScaleType
=
ScaleType
.
FIT_CENTER
;
}
minScale
=
1
;
maxScale
=
3
;
superMinScale
=
SUPER_MIN_MULTIPLIER
*
minScale
;
superMaxScale
=
SUPER_MAX_MULTIPLIER
*
maxScale
;
setImageMatrix
(
matrix
);
setScaleType
(
ScaleType
.
MATRIX
);
setState
(
State
.
NONE
);
onDrawReady
=
false
;
super
.
setOnTouchListener
(
new
PrivateOnTouchListener
());
}
@Override
public
void
setOnTouchListener
(
View
.
OnTouchListener
l
)
{
userTouchListener
=
l
;
}
public
void
setOnTouchImageViewListener
(
OnTouchImageViewListener
l
)
{
touchImageViewListener
=
l
;
}
public
void
setOnDoubleTapListener
(
GestureDetector
.
OnDoubleTapListener
l
)
{
doubleTapListener
=
l
;
}
@Override
public
void
setImageResource
(
int
resId
)
{
super
.
setImageResource
(
resId
);
savePreviousImageValues
();
fitImageToView
();
}
@Override
public
void
setImageBitmap
(
Bitmap
bm
)
{
super
.
setImageBitmap
(
bm
);
savePreviousImageValues
();
fitImageToView
();
}
@Override
public
void
setImageDrawable
(
Drawable
drawable
)
{
super
.
setImageDrawable
(
drawable
);
savePreviousImageValues
();
fitImageToView
();
}
@Override
public
void
setImageURI
(
Uri
uri
)
{
super
.
setImageURI
(
uri
);
savePreviousImageValues
();
fitImageToView
();
}
@Override
public
void
setScaleType
(
ScaleType
type
)
{
if
(
type
==
ScaleType
.
FIT_START
||
type
==
ScaleType
.
FIT_END
)
{
throw
new
UnsupportedOperationException
(
"TouchImageView does not support FIT_START or FIT_END"
);
}
if
(
type
==
ScaleType
.
MATRIX
)
{
super
.
setScaleType
(
ScaleType
.
MATRIX
);
}
else
{
mScaleType
=
type
;
if
(
onDrawReady
)
{
//
// If the image is already rendered, scaleType has been called programmatically
// and the TouchImageView should be updated with the new scaleType.
//
setZoom
(
this
);
}
}
}
@Override
public
ScaleType
getScaleType
()
{
return
mScaleType
;
}
/**
* Returns false if image is in initial, unzoomed state. False, otherwise.
* @return true if image is zoomed
*/
public
boolean
isZoomed
()
{
return
normalizedScale
!=
1
;
}
/**
* Return a Rect representing the zoomed image.
* @return rect representing zoomed image
*/
public
RectF
getZoomedRect
()
{
if
(
mScaleType
==
ScaleType
.
FIT_XY
)
{
throw
new
UnsupportedOperationException
(
"getZoomedRect() not supported with FIT_XY"
);
}
PointF
topLeft
=
transformCoordTouchToBitmap
(
0
,
0
,
true
);
PointF
bottomRight
=
transformCoordTouchToBitmap
(
viewWidth
,
viewHeight
,
true
);
float
w
=
getDrawable
().
getIntrinsicWidth
();
float
h
=
getDrawable
().
getIntrinsicHeight
();
return
new
RectF
(
topLeft
.
x
/
w
,
topLeft
.
y
/
h
,
bottomRight
.
x
/
w
,
bottomRight
.
y
/
h
);
}
/**
* Save the current matrix and view dimensions
* in the prevMatrix and prevView variables.
*/
private
void
savePreviousImageValues
()
{
if
(
matrix
!=
null
&&
viewHeight
!=
0
&&
viewWidth
!=
0
)
{
matrix
.
getValues
(
m
);
prevMatrix
.
setValues
(
m
);
prevMatchViewHeight
=
matchViewHeight
;
prevMatchViewWidth
=
matchViewWidth
;
prevViewHeight
=
viewHeight
;
prevViewWidth
=
viewWidth
;
}
}
@Override
public
Parcelable
onSaveInstanceState
()
{
Bundle
bundle
=
new
Bundle
();
bundle
.
putParcelable
(
"instanceState"
,
super
.
onSaveInstanceState
());
bundle
.
putFloat
(
"saveScale"
,
normalizedScale
);
bundle
.
putFloat
(
"matchViewHeight"
,
matchViewHeight
);
bundle
.
putFloat
(
"matchViewWidth"
,
matchViewWidth
);
bundle
.
putInt
(
"viewWidth"
,
viewWidth
);
bundle
.
putInt
(
"viewHeight"
,
viewHeight
);
matrix
.
getValues
(
m
);
bundle
.
putFloatArray
(
"matrix"
,
m
);
bundle
.
putBoolean
(
"imageRendered"
,
imageRenderedAtLeastOnce
);
return
bundle
;
}
@Override
public
void
onRestoreInstanceState
(
Parcelable
state
)
{
if
(
state
instanceof
Bundle
)
{
Bundle
bundle
=
(
Bundle
)
state
;
normalizedScale
=
bundle
.
getFloat
(
"saveScale"
);
m
=
bundle
.
getFloatArray
(
"matrix"
);
prevMatrix
.
setValues
(
m
);
prevMatchViewHeight
=
bundle
.
getFloat
(
"matchViewHeight"
);
prevMatchViewWidth
=
bundle
.
getFloat
(
"matchViewWidth"
);
prevViewHeight
=
bundle
.
getInt
(
"viewHeight"
);
prevViewWidth
=
bundle
.
getInt
(
"viewWidth"
);
imageRenderedAtLeastOnce
=
bundle
.
getBoolean
(
"imageRendered"
);
super
.
onRestoreInstanceState
(
bundle
.
getParcelable
(
"instanceState"
));
return
;
}
super
.
onRestoreInstanceState
(
state
);
}
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
onDrawReady
=
true
;
imageRenderedAtLeastOnce
=
true
;
if
(
delayedZoomVariables
!=
null
)
{
setZoom
(
delayedZoomVariables
.
scale
,
delayedZoomVariables
.
focusX
,
delayedZoomVariables
.
focusY
,
delayedZoomVariables
.
scaleType
);
delayedZoomVariables
=
null
;
}
super
.
onDraw
(
canvas
);
}
@Override
public
void
onConfigurationChanged
(
Configuration
newConfig
)
{
super
.
onConfigurationChanged
(
newConfig
);
savePreviousImageValues
();
}
/**
* Get the max zoom multiplier.
* @return max zoom multiplier.
*/
public
float
getMaxZoom
()
{
return
maxScale
;
}
/**
* Set the max zoom multiplier. Default value: 3.
* @param max max zoom multiplier.
*/
public
void
setMaxZoom
(
float
max
)
{
maxScale
=
max
;
superMaxScale
=
SUPER_MAX_MULTIPLIER
*
maxScale
;
}
/**
* Get the min zoom multiplier.
* @return min zoom multiplier.
*/
public
float
getMinZoom
()
{
return
minScale
;
}
/**
* Get the current zoom. This is the zoom relative to the initial
* scale, not the original resource.
* @return current zoom multiplier.
*/
public
float
getCurrentZoom
()
{
return
normalizedScale
;
}
/**
* Set the min zoom multiplier. Default value: 1.
* @param min min zoom multiplier.
*/
public
void
setMinZoom
(
float
min
)
{
minScale
=
min
;
superMinScale
=
SUPER_MIN_MULTIPLIER
*
minScale
;
}
/**
* Reset zoom and translation to initial state.
*/
public
void
resetZoom
()
{
normalizedScale
=
1
;
fitImageToView
();
}
/**
* Set zoom to the specified scale. Image will be centered by default.
* @param scale
*/
public
void
setZoom
(
float
scale
)
{
setZoom
(
scale
,
0.5f
,
0.5f
);
}
/**
* Set zoom to the specified scale. Image will be centered around the point
* (focusX, focusY). These floats range from 0 to 1 and denote the focus point
* as a fraction from the left and top of the view. For example, the top left
* corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
* @param scale
* @param focusX
* @param focusY
*/
public
void
setZoom
(
float
scale
,
float
focusX
,
float
focusY
)
{
setZoom
(
scale
,
focusX
,
focusY
,
mScaleType
);
}
/**
* Set zoom to the specified scale. Image will be centered around the point
* (focusX, focusY). These floats range from 0 to 1 and denote the focus point
* as a fraction from the left and top of the view. For example, the top left
* corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
* @param scale
* @param focusX
* @param focusY
* @param scaleType
*/
public
void
setZoom
(
float
scale
,
float
focusX
,
float
focusY
,
ScaleType
scaleType
)
{
//
// setZoom can be called before the image is on the screen, but at this point,
// image and view sizes have not yet been calculated in onMeasure. Thus, we should
// delay calling setZoom until the view has been measured.
//
if
(!
onDrawReady
)
{
delayedZoomVariables
=
new
ZoomVariables
(
scale
,
focusX
,
focusY
,
scaleType
);
return
;
}
if
(
scaleType
!=
mScaleType
)
{
setScaleType
(
scaleType
);
}
resetZoom
();
scaleImage
(
scale
,
viewWidth
/
2
,
viewHeight
/
2
,
true
);
matrix
.
getValues
(
m
);
m
[
Matrix
.
MTRANS_X
]
=
-((
focusX
*
getImageWidth
())
-
(
viewWidth
*
0.5f
));
m
[
Matrix
.
MTRANS_Y
]
=
-((
focusY
*
getImageHeight
())
-
(
viewHeight
*
0.5f
));
matrix
.
setValues
(
m
);
fixTrans
();
setImageMatrix
(
matrix
);
}
/**
* Set zoom parameters equal to another TouchImageView. Including scale, position,
* and ScaleType.
* @param TouchImageView
*/
public
void
setZoom
(
TouchImageView
img
)
{
PointF
center
=
img
.
getScrollPosition
();
setZoom
(
img
.
getCurrentZoom
(),
center
.
x
,
center
.
y
,
img
.
getScaleType
());
}
/**
* Return the point at the center of the zoomed image. The PointF coordinates range
* in value between 0 and 1 and the focus point is denoted as a fraction from the left
* and top of the view. For example, the top left corner of the image would be (0, 0).
* And the bottom right corner would be (1, 1).
* @return PointF representing the scroll position of the zoomed image.
*/
public
PointF
getScrollPosition
()
{
Drawable
drawable
=
getDrawable
();
if
(
drawable
==
null
)
{
return
null
;
}
int
drawableWidth
=
drawable
.
getIntrinsicWidth
();
int
drawableHeight
=
drawable
.
getIntrinsicHeight
();
PointF
point
=
transformCoordTouchToBitmap
(
viewWidth
/
2
,
viewHeight
/
2
,
true
);
point
.
x
/=
drawableWidth
;
point
.
y
/=
drawableHeight
;
return
point
;
}
/**
* Set the focus point of the zoomed image. The focus points are denoted as a fraction from the
* left and top of the view. The focus points can range in value between 0 and 1.
* @param focusX
* @param focusY
*/
public
void
setScrollPosition
(
float
focusX
,
float
focusY
)
{
setZoom
(
normalizedScale
,
focusX
,
focusY
);
}
/**
* Performs boundary checking and fixes the image matrix if it
* is out of bounds.
*/
private
void
fixTrans
()
{
matrix
.
getValues
(
m
);
float
transX
=
m
[
Matrix
.
MTRANS_X
];
float
transY
=
m
[
Matrix
.
MTRANS_Y
];
float
fixTransX
=
getFixTrans
(
transX
,
viewWidth
,
getImageWidth
());
float
fixTransY
=
getFixTrans
(
transY
,
viewHeight
,
getImageHeight
());
if
(
fixTransX
!=
0
||
fixTransY
!=
0
)
{
matrix
.
postTranslate
(
fixTransX
,
fixTransY
);
}
}
/**
* When transitioning from zooming from focus to zoom from center (or vice versa)
* the image can become unaligned within the view. This is apparent when zooming
* quickly. When the content size is less than the view size, the content will often
* be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and
* then makes sure the image is centered correctly within the view.
*/
private
void
fixScaleTrans
()
{
fixTrans
();
matrix
.
getValues
(
m
);
if
(
getImageWidth
()
<
viewWidth
)
{
m
[
Matrix
.
MTRANS_X
]
=
(
viewWidth
-
getImageWidth
())
/
2
;
}
if
(
getImageHeight
()
<
viewHeight
)
{
m
[
Matrix
.
MTRANS_Y
]
=
(
viewHeight
-
getImageHeight
())
/
2
;
}
matrix
.
setValues
(
m
);
}
private
float
getFixTrans
(
float
trans
,
float
viewSize
,
float
contentSize
)
{
float
minTrans
,
maxTrans
;
if
(
contentSize
<=
viewSize
)
{
minTrans
=
0
;
maxTrans
=
viewSize
-
contentSize
;
}
else
{
minTrans
=
viewSize
-
contentSize
;
maxTrans
=
0
;
}
if
(
trans
<
minTrans
)
return
-
trans
+
minTrans
;
if
(
trans
>
maxTrans
)
return
-
trans
+
maxTrans
;
return
0
;
}
private
float
getFixDragTrans
(
float
delta
,
float
viewSize
,
float
contentSize
)
{
if
(
contentSize
<=
viewSize
)
{
return
0
;
}
return
delta
;
}
private
float
getImageWidth
()
{
return
matchViewWidth
*
normalizedScale
;
}
private
float
getImageHeight
()
{
return
matchViewHeight
*
normalizedScale
;
}
@Override
protected
void
onMeasure
(
int
widthMeasureSpec
,
int
heightMeasureSpec
)
{
Drawable
drawable
=
getDrawable
();
if
(
drawable
==
null
||
drawable
.
getIntrinsicWidth
()
==
0
||
drawable
.
getIntrinsicHeight
()
==
0
)
{
setMeasuredDimension
(
0
,
0
);
return
;
}
int
drawableWidth
=
drawable
.
getIntrinsicWidth
();
int
drawableHeight
=
drawable
.
getIntrinsicHeight
();
int
widthSize
=
MeasureSpec
.
getSize
(
widthMeasureSpec
);
int
widthMode
=
MeasureSpec
.
getMode
(
widthMeasureSpec
);
int
heightSize
=
MeasureSpec
.
getSize
(
heightMeasureSpec
);
int
heightMode
=
MeasureSpec
.
getMode
(
heightMeasureSpec
);
viewWidth
=
setViewSize
(
widthMode
,
widthSize
,
drawableWidth
);
viewHeight
=
setViewSize
(
heightMode
,
heightSize
,
drawableHeight
);
//
// Set view dimensions
//
setMeasuredDimension
(
viewWidth
,
viewHeight
);
//
// Fit content within view
//
fitImageToView
();
}
/**
* If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise,
* it is made to fit the screen according to the dimensions of the previous image matrix. This
* allows the image to maintain its zoom after rotation.
*/
private
void
fitImageToView
()
{
Drawable
drawable
=
getDrawable
();
if
(
drawable
==
null
||
drawable
.
getIntrinsicWidth
()
==
0
||
drawable
.
getIntrinsicHeight
()
==
0
)
{
return
;
}
if
(
matrix
==
null
||
prevMatrix
==
null
)
{
return
;
}
int
drawableWidth
=
drawable
.
getIntrinsicWidth
();
int
drawableHeight
=
drawable
.
getIntrinsicHeight
();
//
// Scale image for view
//
float
scaleX
=
(
float
)
viewWidth
/
drawableWidth
;
float
scaleY
=
(
float
)
viewHeight
/
drawableHeight
;
switch
(
mScaleType
)
{
case
CENTER:
scaleX
=
scaleY
=
1
;
break
;
case
CENTER_CROP:
scaleX
=
scaleY
=
Math
.
max
(
scaleX
,
scaleY
);
break
;
case
CENTER_INSIDE:
scaleX
=
scaleY
=
Math
.
min
(
1
,
Math
.
min
(
scaleX
,
scaleY
));
case
FIT_CENTER:
scaleX
=
scaleY
=
Math
.
min
(
scaleX
,
scaleY
);
break
;
case
FIT_XY:
break
;
default
:
//
// FIT_START and FIT_END not supported
//
throw
new
UnsupportedOperationException
(
"TouchImageView does not support FIT_START or FIT_END"
);
}
//
// Center the image
//
float
redundantXSpace
=
viewWidth
-
(
scaleX
*
drawableWidth
);
float
redundantYSpace
=
viewHeight
-
(
scaleY
*
drawableHeight
);
matchViewWidth
=
viewWidth
-
redundantXSpace
;
matchViewHeight
=
viewHeight
-
redundantYSpace
;
if
(!
isZoomed
()
&&
!
imageRenderedAtLeastOnce
)
{
//
// Stretch and center image to fit view
//
matrix
.
setScale
(
scaleX
,
scaleY
);
matrix
.
postTranslate
(
redundantXSpace
/
2
,
redundantYSpace
/
2
);
normalizedScale
=
1
;
}
else
{
//
// These values should never be 0 or we will set viewWidth and viewHeight
// to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues
// to set them equal to the current values.
//
if
(
prevMatchViewWidth
==
0
||
prevMatchViewHeight
==
0
)
{
savePreviousImageValues
();
}
prevMatrix
.
getValues
(
m
);
//
// Rescale Matrix after rotation
//
m
[
Matrix
.
MSCALE_X
]
=
matchViewWidth
/
drawableWidth
*
normalizedScale
;
m
[
Matrix
.
MSCALE_Y
]
=
matchViewHeight
/
drawableHeight
*
normalizedScale
;
//
// TransX and TransY from previous matrix
//
float
transX
=
m
[
Matrix
.
MTRANS_X
];
float
transY
=
m
[
Matrix
.
MTRANS_Y
];
//
// Width
//
float
prevActualWidth
=
prevMatchViewWidth
*
normalizedScale
;
float
actualWidth
=
getImageWidth
();
translateMatrixAfterRotate
(
Matrix
.
MTRANS_X
,
transX
,
prevActualWidth
,
actualWidth
,
prevViewWidth
,
viewWidth
,
drawableWidth
);
//
// Height
//
float
prevActualHeight
=
prevMatchViewHeight
*
normalizedScale
;
float
actualHeight
=
getImageHeight
();
translateMatrixAfterRotate
(
Matrix
.
MTRANS_Y
,
transY
,
prevActualHeight
,
actualHeight
,
prevViewHeight
,
viewHeight
,
drawableHeight
);
//
// Set the matrix to the adjusted scale and translate values.
//
matrix
.
setValues
(
m
);
}
fixTrans
();
setImageMatrix
(
matrix
);
}
/**
* Set view dimensions based on layout params
*
* @param mode
* @param size
* @param drawableWidth
* @return
*/
private
int
setViewSize
(
int
mode
,
int
size
,
int
drawableWidth
)
{
int
viewSize
;
switch
(
mode
)
{
case
MeasureSpec
.
EXACTLY
:
viewSize
=
size
;
break
;
case
MeasureSpec
.
AT_MOST
:
viewSize
=
Math
.
min
(
drawableWidth
,
size
);
break
;
case
MeasureSpec
.
UNSPECIFIED
:
viewSize
=
drawableWidth
;
break
;
default
:
viewSize
=
size
;
break
;
}
return
viewSize
;
}
/**
* After rotating, the matrix needs to be translated. This function finds the area of image
* which was previously centered and adjusts translations so that is again the center, post-rotation.
*
* @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y
* @param trans the value of trans in that axis before the rotation
* @param prevImageSize the width/height of the image before the rotation
* @param imageSize width/height of the image after rotation
* @param prevViewSize width/height of view before rotation
* @param viewSize width/height of view after rotation
* @param drawableSize width/height of drawable
*/
private
void
translateMatrixAfterRotate
(
int
axis
,
float
trans
,
float
prevImageSize
,
float
imageSize
,
int
prevViewSize
,
int
viewSize
,
int
drawableSize
)
{
if
(
imageSize
<
viewSize
)
{
//
// The width/height of image is less than the view's width/height. Center it.
//
m
[
axis
]
=
(
viewSize
-
(
drawableSize
*
m
[
Matrix
.
MSCALE_X
]))
*
0.5f
;
}
else
if
(
trans
>
0
)
{
//
// The image is larger than the view, but was not before rotation. Center it.
//
m
[
axis
]
=
-((
imageSize
-
viewSize
)
*
0.5f
);
}
else
{
//
// Find the area of the image which was previously centered in the view. Determine its distance
// from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage
// to calculate the trans in the new view width/height.
//
float
percentage
=
(
Math
.
abs
(
trans
)
+
(
0.5f
*
prevViewSize
))
/
prevImageSize
;
m
[
axis
]
=
-((
percentage
*
imageSize
)
-
(
viewSize
*
0.5f
));
}
}
private
void
setState
(
State
state
)
{
this
.
state
=
state
;
}
public
boolean
canScrollHorizontallyFroyo
(
int
direction
)
{
return
canScrollHorizontally
(
direction
);
}
@Override
public
boolean
canScrollHorizontally
(
int
direction
)
{
matrix
.
getValues
(
m
);
float
x
=
m
[
Matrix
.
MTRANS_X
];
if
(
getImageWidth
()
<
viewWidth
)
{
return
false
;
}
else
if
(
x
>=
-
1
&&
direction
<
0
)
{
return
false
;
}
else
if
(
Math
.
abs
(
x
)
+
viewWidth
+
1
>=
getImageWidth
()
&&
direction
>
0
)
{
return
false
;
}
return
true
;
}
/**
* Gesture Listener detects a single click or long click and passes that on
* to the view's listener.
* @author Ortiz
*
*/
private
class
GestureListener
extends
GestureDetector
.
SimpleOnGestureListener
{
@Override
public
boolean
onSingleTapConfirmed
(
MotionEvent
e
)
{
if
(
doubleTapListener
!=
null
)
{
return
doubleTapListener
.
onSingleTapConfirmed
(
e
);
}
return
performClick
();
}
@Override
public
void
onLongPress
(
MotionEvent
e
)
{
performLongClick
();
}
@Override
public
boolean
onFling
(
MotionEvent
e1
,
MotionEvent
e2
,
float
velocityX
,
float
velocityY
)
{
if
(
fling
!=
null
)
{
//
// If a previous fling is still active, it should be cancelled so that two flings
// are not run simultaenously.
//
fling
.
cancelFling
();
}
fling
=
new
Fling
((
int
)
velocityX
,
(
int
)
velocityY
);
compatPostOnAnimation
(
fling
);
return
super
.
onFling
(
e1
,
e2
,
velocityX
,
velocityY
);
}
@Override
public
boolean
onDoubleTap
(
MotionEvent
e
)
{
boolean
consumed
=
false
;
if
(
doubleTapListener
!=
null
)
{
consumed
=
doubleTapListener
.
onDoubleTap
(
e
);
}
if
(
state
==
State
.
NONE
)
{
float
targetZoom
=
(
normalizedScale
==
minScale
)
?
maxScale
:
minScale
;
DoubleTapZoom
doubleTap
=
new
DoubleTapZoom
(
targetZoom
,
e
.
getX
(),
e
.
getY
(),
false
);
compatPostOnAnimation
(
doubleTap
);
consumed
=
true
;
}
return
consumed
;
}
@Override
public
boolean
onDoubleTapEvent
(
MotionEvent
e
)
{
if
(
doubleTapListener
!=
null
)
{
return
doubleTapListener
.
onDoubleTapEvent
(
e
);
}
return
false
;
}
}
public
interface
OnTouchImageViewListener
{
public
void
onMove
();
}
/**
* Responsible for all touch events. Handles the heavy lifting of drag and also sends
* touch events to Scale Detector and Gesture Detector.
* @author Ortiz
*
*/
private
class
PrivateOnTouchListener
implements
OnTouchListener
{
//
// Remember last point position for dragging
//
private
PointF
last
=
new
PointF
();
@Override
public
boolean
onTouch
(
View
v
,
MotionEvent
event
)
{
mScaleDetector
.
onTouchEvent
(
event
);
mGestureDetector
.
onTouchEvent
(
event
);
PointF
curr
=
new
PointF
(
event
.
getX
(),
event
.
getY
());
if
(
state
==
State
.
NONE
||
state
==
State
.
DRAG
||
state
==
State
.
FLING
)
{
switch
(
event
.
getAction
())
{
case
MotionEvent
.
ACTION_DOWN
:
last
.
set
(
curr
);
if
(
fling
!=
null
)
fling
.
cancelFling
();
setState
(
State
.
DRAG
);
break
;
case
MotionEvent
.
ACTION_MOVE
:
if
(
state
==
State
.
DRAG
)
{
float
deltaX
=
curr
.
x
-
last
.
x
;
float
deltaY
=
curr
.
y
-
last
.
y
;
float
fixTransX
=
getFixDragTrans
(
deltaX
,
viewWidth
,
getImageWidth
());
float
fixTransY
=
getFixDragTrans
(
deltaY
,
viewHeight
,
getImageHeight
());
matrix
.
postTranslate
(
fixTransX
,
fixTransY
);
fixTrans
();
last
.
set
(
curr
.
x
,
curr
.
y
);
}
break
;
case
MotionEvent
.
ACTION_UP
:
case
MotionEvent
.
ACTION_POINTER_UP
:
setState
(
State
.
NONE
);
break
;
}
}
setImageMatrix
(
matrix
);
//
// User-defined OnTouchListener
//
if
(
userTouchListener
!=
null
)
{
userTouchListener
.
onTouch
(
v
,
event
);
}
//
// OnTouchImageViewListener is set: TouchImageView dragged by user.
//
if
(
touchImageViewListener
!=
null
)
{
touchImageViewListener
.
onMove
();
}
//
// indicate event was handled
//
return
true
;
}
}
/**
* ScaleListener detects user two finger scaling and scales image.
* @author Ortiz
*
*/
private
class
ScaleListener
extends
ScaleGestureDetector
.
SimpleOnScaleGestureListener
{
@Override
public
boolean
onScaleBegin
(
ScaleGestureDetector
detector
)
{
setState
(
State
.
ZOOM
);
return
true
;
}
@Override
public
boolean
onScale
(
ScaleGestureDetector
detector
)
{
scaleImage
(
detector
.
getScaleFactor
(),
detector
.
getFocusX
(),
detector
.
getFocusY
(),
true
);
//
// OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
//
if
(
touchImageViewListener
!=
null
)
{
touchImageViewListener
.
onMove
();
}
return
true
;
}
@Override
public
void
onScaleEnd
(
ScaleGestureDetector
detector
)
{
super
.
onScaleEnd
(
detector
);
setState
(
State
.
NONE
);
boolean
animateToZoomBoundary
=
false
;
float
targetZoom
=
normalizedScale
;
if
(
normalizedScale
>
maxScale
)
{
targetZoom
=
maxScale
;
animateToZoomBoundary
=
true
;
}
else
if
(
normalizedScale
<
minScale
)
{
targetZoom
=
minScale
;
animateToZoomBoundary
=
true
;
}
if
(
animateToZoomBoundary
)
{
DoubleTapZoom
doubleTap
=
new
DoubleTapZoom
(
targetZoom
,
viewWidth
/
2
,
viewHeight
/
2
,
true
);
compatPostOnAnimation
(
doubleTap
);
}
}
}
private
void
scaleImage
(
double
deltaScale
,
float
focusX
,
float
focusY
,
boolean
stretchImageToSuper
)
{
float
lowerScale
,
upperScale
;
if
(
stretchImageToSuper
)
{
lowerScale
=
superMinScale
;
upperScale
=
superMaxScale
;
}
else
{
lowerScale
=
minScale
;
upperScale
=
maxScale
;
}
float
origScale
=
normalizedScale
;
normalizedScale
*=
deltaScale
;
if
(
normalizedScale
>
upperScale
)
{
normalizedScale
=
upperScale
;
deltaScale
=
upperScale
/
origScale
;
}
else
if
(
normalizedScale
<
lowerScale
)
{
normalizedScale
=
lowerScale
;
deltaScale
=
lowerScale
/
origScale
;
}
matrix
.
postScale
((
float
)
deltaScale
,
(
float
)
deltaScale
,
focusX
,
focusY
);
fixScaleTrans
();
}
/**
* DoubleTapZoom calls a series of runnables which apply
* an animated zoom in/out graphic to the image.
* @author Ortiz
*
*/
private
class
DoubleTapZoom
implements
Runnable
{
private
long
startTime
;
private
static
final
float
ZOOM_TIME
=
500
;
private
float
startZoom
,
targetZoom
;
private
float
bitmapX
,
bitmapY
;
private
boolean
stretchImageToSuper
;
private
AccelerateDecelerateInterpolator
interpolator
=
new
AccelerateDecelerateInterpolator
();
private
PointF
startTouch
;
private
PointF
endTouch
;
DoubleTapZoom
(
float
targetZoom
,
float
focusX
,
float
focusY
,
boolean
stretchImageToSuper
)
{
setState
(
State
.
ANIMATE_ZOOM
);
startTime
=
System
.
currentTimeMillis
();
this
.
startZoom
=
normalizedScale
;
this
.
targetZoom
=
targetZoom
;
this
.
stretchImageToSuper
=
stretchImageToSuper
;
PointF
bitmapPoint
=
transformCoordTouchToBitmap
(
focusX
,
focusY
,
false
);
this
.
bitmapX
=
bitmapPoint
.
x
;
this
.
bitmapY
=
bitmapPoint
.
y
;
//
// Used for translating image during scaling
//
startTouch
=
transformCoordBitmapToTouch
(
bitmapX
,
bitmapY
);
endTouch
=
new
PointF
(
viewWidth
/
2
,
viewHeight
/
2
);
}
@Override
public
void
run
()
{
float
t
=
interpolate
();
double
deltaScale
=
calculateDeltaScale
(
t
);
scaleImage
(
deltaScale
,
bitmapX
,
bitmapY
,
stretchImageToSuper
);
translateImageToCenterTouchPosition
(
t
);
fixScaleTrans
();
setImageMatrix
(
matrix
);
//
// OnTouchImageViewListener is set: double tap runnable updates listener
// with every frame.
//
if
(
touchImageViewListener
!=
null
)
{
touchImageViewListener
.
onMove
();
}
if
(
t
<
1
f
)
{
//
// We haven't finished zooming
//
compatPostOnAnimation
(
this
);
}
else
{
//
// Finished zooming
//
setState
(
State
.
NONE
);
}
}
/**
* Interpolate between where the image should start and end in order to translate
* the image so that the point that is touched is what ends up centered at the end
* of the zoom.
* @param t
*/
private
void
translateImageToCenterTouchPosition
(
float
t
)
{
float
targetX
=
startTouch
.
x
+
t
*
(
endTouch
.
x
-
startTouch
.
x
);
float
targetY
=
startTouch
.
y
+
t
*
(
endTouch
.
y
-
startTouch
.
y
);
PointF
curr
=
transformCoordBitmapToTouch
(
bitmapX
,
bitmapY
);
matrix
.
postTranslate
(
targetX
-
curr
.
x
,
targetY
-
curr
.
y
);
}
/**
* Use interpolator to get t
* @return
*/
private
float
interpolate
()
{
long
currTime
=
System
.
currentTimeMillis
();
float
elapsed
=
(
currTime
-
startTime
)
/
ZOOM_TIME
;
elapsed
=
Math
.
min
(
1
f
,
elapsed
);
return
interpolator
.
getInterpolation
(
elapsed
);
}
/**
* Interpolate the current targeted zoom and get the delta
* from the current zoom.
* @param t
* @return
*/
private
double
calculateDeltaScale
(
float
t
)
{
double
zoom
=
startZoom
+
t
*
(
targetZoom
-
startZoom
);
return
zoom
/
normalizedScale
;
}
}
/**
* This function will transform the coordinates in the touch event to the coordinate
* system of the drawable that the imageview contain
* @param x x-coordinate of touch event
* @param y y-coordinate of touch event
* @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip return value
* to the bounds of the bitmap size.
* @return Coordinates of the point touched, in the coordinate system of the original drawable.
*/
private
PointF
transformCoordTouchToBitmap
(
float
x
,
float
y
,
boolean
clipToBitmap
)
{
matrix
.
getValues
(
m
);
float
origW
=
getDrawable
().
getIntrinsicWidth
();
float
origH
=
getDrawable
().
getIntrinsicHeight
();
float
transX
=
m
[
Matrix
.
MTRANS_X
];
float
transY
=
m
[
Matrix
.
MTRANS_Y
];
float
finalX
=
((
x
-
transX
)
*
origW
)
/
getImageWidth
();
float
finalY
=
((
y
-
transY
)
*
origH
)
/
getImageHeight
();
if
(
clipToBitmap
)
{
finalX
=
Math
.
min
(
Math
.
max
(
finalX
,
0
),
origW
);
finalY
=
Math
.
min
(
Math
.
max
(
finalY
,
0
),
origH
);
}
return
new
PointF
(
finalX
,
finalY
);
}
/**
* Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the
* drawable's coordinate system to the view's coordinate system.
* @param bx x-coordinate in original bitmap coordinate system
* @param by y-coordinate in original bitmap coordinate system
* @return Coordinates of the point in the view's coordinate system.
*/
private
PointF
transformCoordBitmapToTouch
(
float
bx
,
float
by
)
{
matrix
.
getValues
(
m
);
float
origW
=
getDrawable
().
getIntrinsicWidth
();
float
origH
=
getDrawable
().
getIntrinsicHeight
();
float
px
=
bx
/
origW
;
float
py
=
by
/
origH
;
float
finalX
=
m
[
Matrix
.
MTRANS_X
]
+
getImageWidth
()
*
px
;
float
finalY
=
m
[
Matrix
.
MTRANS_Y
]
+
getImageHeight
()
*
py
;
return
new
PointF
(
finalX
,
finalY
);
}
/**
* Fling launches sequential runnables which apply
* the fling graphic to the image. The values for the translation
* are interpolated by the Scroller.
* @author Ortiz
*
*/
private
class
Fling
implements
Runnable
{
CompatScroller
scroller
;
int
currX
,
currY
;
Fling
(
int
velocityX
,
int
velocityY
)
{
setState
(
State
.
FLING
);
scroller
=
new
CompatScroller
(
context
);
matrix
.
getValues
(
m
);
int
startX
=
(
int
)
m
[
Matrix
.
MTRANS_X
];
int
startY
=
(
int
)
m
[
Matrix
.
MTRANS_Y
];
int
minX
,
maxX
,
minY
,
maxY
;
if
(
getImageWidth
()
>
viewWidth
)
{
minX
=
viewWidth
-
(
int
)
getImageWidth
();
maxX
=
0
;
}
else
{
minX
=
maxX
=
startX
;
}
if
(
getImageHeight
()
>
viewHeight
)
{
minY
=
viewHeight
-
(
int
)
getImageHeight
();
maxY
=
0
;
}
else
{
minY
=
maxY
=
startY
;
}
scroller
.
fling
(
startX
,
startY
,
(
int
)
velocityX
,
(
int
)
velocityY
,
minX
,
maxX
,
minY
,
maxY
);
currX
=
startX
;
currY
=
startY
;
}
public
void
cancelFling
()
{
if
(
scroller
!=
null
)
{
setState
(
State
.
NONE
);
scroller
.
forceFinished
(
true
);
}
}
@Override
public
void
run
()
{
//
// OnTouchImageViewListener is set: TouchImageView listener has been flung by user.
// Listener runnable updated with each frame of fling animation.
//
if
(
touchImageViewListener
!=
null
)
{
touchImageViewListener
.
onMove
();
}
if
(
scroller
.
isFinished
())
{
scroller
=
null
;
return
;
}
if
(
scroller
.
computeScrollOffset
())
{
int
newX
=
scroller
.
getCurrX
();
int
newY
=
scroller
.
getCurrY
();
int
transX
=
newX
-
currX
;
int
transY
=
newY
-
currY
;
currX
=
newX
;
currY
=
newY
;
matrix
.
postTranslate
(
transX
,
transY
);
fixTrans
();
setImageMatrix
(
matrix
);
compatPostOnAnimation
(
this
);
}
}
}
@TargetApi
(
Build
.
VERSION_CODES
.
GINGERBREAD
)
private
class
CompatScroller
{
Scroller
scroller
;
OverScroller
overScroller
;
boolean
isPreGingerbread
;
public
CompatScroller
(
Context
context
)
{
if
(
VERSION
.
SDK_INT
<
VERSION_CODES
.
GINGERBREAD
)
{
isPreGingerbread
=
true
;
scroller
=
new
Scroller
(
context
);
}
else
{
isPreGingerbread
=
false
;
overScroller
=
new
OverScroller
(
context
);
}
}
public
void
fling
(
int
startX
,
int
startY
,
int
velocityX
,
int
velocityY
,
int
minX
,
int
maxX
,
int
minY
,
int
maxY
)
{
if
(
isPreGingerbread
)
{
scroller
.
fling
(
startX
,
startY
,
velocityX
,
velocityY
,
minX
,
maxX
,
minY
,
maxY
);
}
else
{
overScroller
.
fling
(
startX
,
startY
,
velocityX
,
velocityY
,
minX
,
maxX
,
minY
,
maxY
);
}
}
public
void
forceFinished
(
boolean
finished
)
{
if
(
isPreGingerbread
)
{
scroller
.
forceFinished
(
finished
);
}
else
{
overScroller
.
forceFinished
(
finished
);
}
}
public
boolean
isFinished
()
{
if
(
isPreGingerbread
)
{
return
scroller
.
isFinished
();
}
else
{
return
overScroller
.
isFinished
();
}
}
public
boolean
computeScrollOffset
()
{
if
(
isPreGingerbread
)
{
return
scroller
.
computeScrollOffset
();
}
else
{
overScroller
.
computeScrollOffset
();
return
overScroller
.
computeScrollOffset
();
}
}
public
int
getCurrX
()
{
if
(
isPreGingerbread
)
{
return
scroller
.
getCurrX
();
}
else
{
return
overScroller
.
getCurrX
();
}
}
public
int
getCurrY
()
{
if
(
isPreGingerbread
)
{
return
scroller
.
getCurrY
();
}
else
{
return
overScroller
.
getCurrY
();
}
}
}
@TargetApi
(
Build
.
VERSION_CODES
.
JELLY_BEAN
)
private
void
compatPostOnAnimation
(
Runnable
runnable
)
{
if
(
VERSION
.
SDK_INT
>=
VERSION_CODES
.
JELLY_BEAN
)
{
postOnAnimation
(
runnable
);
}
else
{
postDelayed
(
runnable
,
1000
/
60
);
}
}
private
class
ZoomVariables
{
public
float
scale
;
public
float
focusX
;
public
float
focusY
;
public
ScaleType
scaleType
;
public
ZoomVariables
(
float
scale
,
float
focusX
,
float
focusY
,
ScaleType
scaleType
)
{
this
.
scale
=
scale
;
this
.
focusX
=
focusX
;
this
.
focusY
=
focusY
;
this
.
scaleType
=
scaleType
;
}
}
private
void
printMatrixInfo
()
{
float
[]
n
=
new
float
[
9
];
matrix
.
getValues
(
n
);
Log
.
d
(
DEBUG
,
"Scale: "
+
n
[
Matrix
.
MSCALE_X
]
+
" TransX: "
+
n
[
Matrix
.
MTRANS_X
]
+
" TransY: "
+
n
[
Matrix
.
MTRANS_Y
]);
}
}
app/src/main/java/app/insti/fragment/BackHandledFragment.java
0 → 100644
View file @
3541aa3c
package
app.insti.fragment
;
import
android.os.Bundle
;
public
abstract
class
BackHandledFragment
extends
BaseFragment
{
protected
BackHandlerInterface
backHandlerInterface
;
public
abstract
boolean
onBackPressed
();
@Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
if
(!(
getActivity
()
instanceof
BackHandlerInterface
))
{
throw
new
ClassCastException
(
"Hosting activity must implement BackHandlerInterface"
);
}
else
{
backHandlerInterface
=
(
BackHandlerInterface
)
getActivity
();
}
}
@Override
public
void
onStart
()
{
super
.
onStart
();
// Mark this fragment as the selected Fragment.
backHandlerInterface
.
setSelectedFragment
(
this
);
}
public
interface
BackHandlerInterface
{
public
void
setSelectedFragment
(
BackHandledFragment
backHandledFragment
);
}
}
\ No newline at end of file
app/src/main/java/app/insti/fragment/BodyFragment.java
View file @
3541aa3c
package
app.insti.fragment
;
import
android.animation.Animator
;
import
android.animation.AnimatorListenerAdapter
;
import
android.animation.AnimatorSet
;
import
android.animation.ObjectAnimator
;
import
android.content.Intent
;
import
android.graphics.Color
;
import
android.graphics.Point
;
import
android.graphics.Rect
;
import
android.net.Uri
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
...
...
@@ -14,6 +21,7 @@ import android.support.v7.widget.Toolbar;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.view.animation.DecelerateInterpolator
;
import
android.widget.Button
;
import
android.widget.ImageButton
;
import
android.widget.ImageView
;
...
...
@@ -51,7 +59,7 @@ import ru.noties.markwon.Markwon;
* Use the {@link BodyFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public
class
BodyFragment
extends
Fragment
{
public
class
BodyFragment
extends
BackHandled
Fragment
{
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
...
...
@@ -63,10 +71,36 @@ public class BodyFragment extends Fragment {
private
SwipeRefreshLayout
bodySwipeRefreshLayout
;
// Hold a reference to the current animator,
// so that it can be canceled mid-way.
private
Animator
mCurrentAnimator
;
// The system "short" animation time duration, in milliseconds. This
// duration is ideal for subtle animations or animations that occur
// very frequently.
private
int
mShortAnimationDuration
;
private
boolean
zoomMode
;
private
ImageView
expandedImageView
;
private
Rect
startBounds
;
private
float
startScaleFinal
;
private
ImageView
bodyPicture
;
private
Body
body
;
public
BodyFragment
()
{
// Required empty public constructor
}
@Override
public
boolean
onBackPressed
()
{
if
(
zoomMode
)
{
zoomOut
(
expandedImageView
,
startBounds
,
startScaleFinal
,
bodyPicture
);
zoomMode
=
false
;
return
true
;
}
return
false
;
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
...
...
@@ -97,7 +131,8 @@ public class BodyFragment extends Fragment {
/* Initialize */
appDatabase
=
AppDatabase
.
getAppDatabase
(
getContext
());
displayBody
(
min_body
);
body
=
min_body
;
displayBody
();
new
getDbBody
().
execute
(
min_body
.
getBodyID
());
bodySwipeRefreshLayout
=
getActivity
().
findViewById
(
R
.
id
.
body_swipe_refresh_layout
);
bodySwipeRefreshLayout
.
setOnRefreshListener
(
new
SwipeRefreshLayout
.
OnRefreshListener
()
{
...
...
@@ -117,11 +152,12 @@ public class BodyFragment extends Fragment {
@Override
public
void
onResponse
(
Call
<
Body
>
call
,
Response
<
Body
>
response
)
{
if
(
response
.
isSuccessful
())
{
Body
body
=
response
.
body
();
Body
body
Response
=
response
.
body
();
new
updateDbBody
().
execute
(
body
);
new
updateDbBody
().
execute
(
body
Response
);
displayBody
(
body
);
body
=
bodyResponse
;
displayBody
();
bodySwipeRefreshLayout
.
setRefreshing
(
false
);
}
}
...
...
@@ -142,13 +178,13 @@ public class BodyFragment extends Fragment {
}
}
private
void
displayBody
(
final
Body
body
)
{
private
void
displayBody
()
{
/* Skip if we're already destroyed */
if
(
getView
()
==
null
)
return
;
TextView
bodyName
=
(
TextView
)
getView
().
findViewById
(
R
.
id
.
body_name
);
TextView
bodyDescription
=
(
TextView
)
getView
().
findViewById
(
R
.
id
.
body_description
);
ImageView
event
Picture
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
body_picture
);
body
Picture
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
body_picture
);
ImageButton
webBodyButton
=
getActivity
().
findViewById
(
R
.
id
.
web_body_button
);
ImageButton
shareBodyButton
=
getActivity
().
findViewById
(
R
.
id
.
share_body_button
);
final
Button
followButton
=
getActivity
().
findViewById
(
R
.
id
.
follow_button
);
...
...
@@ -161,7 +197,15 @@ public class BodyFragment extends Fragment {
/* Set body information */
bodyName
.
setText
(
body
.
getBodyName
());
Picasso
.
get
().
load
(
body
.
getBodyImageURL
()).
into
(
eventPicture
);
Picasso
.
get
().
load
(
body
.
getBodyImageURL
()).
into
(
bodyPicture
);
bodyPicture
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
zoomImageFromThumb
(
bodyPicture
);
}
});
mShortAnimationDuration
=
getResources
().
getInteger
(
android
.
R
.
integer
.
config_shortAnimTime
);
/* Return if it's a min body */
if
(
body
.
getBodyDescription
()
==
null
)
{
...
...
@@ -346,11 +390,148 @@ public class BodyFragment extends Fragment {
@Override
protected
void
onPostExecute
(
Body
[]
result
)
{
if
(
result
.
length
>
0
)
{
displayBody
(
result
[
0
]);
body
=
result
[
0
];
displayBody
();
}
else
{
updateBody
();
}
}
}
private
void
zoomOut
(
final
ImageView
expandedImageView
,
Rect
startBounds
,
float
startScaleFinal
,
final
View
thumbView
)
{
expandedImageView
.
setBackgroundColor
(
0x00000000
);
if
(
mCurrentAnimator
!=
null
)
{
mCurrentAnimator
.
cancel
();
}
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
AnimatorSet
set
=
new
AnimatorSet
();
set
.
play
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
X
,
startBounds
.
left
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
Y
,
startBounds
.
top
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_X
,
startScaleFinal
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_Y
,
startScaleFinal
));
set
.
setDuration
(
mShortAnimationDuration
);
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
thumbView
.
setAlpha
(
1
f
);
expandedImageView
.
setVisibility
(
View
.
GONE
);
mCurrentAnimator
=
null
;
}
@Override
public
void
onAnimationCancel
(
Animator
animation
)
{
thumbView
.
setAlpha
(
1
f
);
expandedImageView
.
setVisibility
(
View
.
GONE
);
mCurrentAnimator
=
null
;
}
});
set
.
start
();
mCurrentAnimator
=
set
;
}
private
void
zoomImageFromThumb
(
final
ImageView
thumbView
)
{
// If there's an animation in progress, cancel it
// immediately and proceed with this one.
if
(
mCurrentAnimator
!=
null
)
{
mCurrentAnimator
.
cancel
();
}
// Load the high-resolution "zoomed-in" image.
expandedImageView
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
expanded_image_body
);
expandedImageView
.
setImageDrawable
(
thumbView
.
getDrawable
());
// Calculate the starting and ending bounds for the zoomed-in image.
// This step involves lots of math. Yay, math.
startBounds
=
new
Rect
();
final
Rect
finalBounds
=
new
Rect
();
final
Point
globalOffset
=
new
Point
();
// The start bounds are the global visible rectangle of the thumbnail,
// and the final bounds are the global visible rectangle of the container
// view. Also set the container view's offset as the origin for the
// bounds, since that's the origin for the positioning animation
// properties (X, Y).
thumbView
.
getGlobalVisibleRect
(
startBounds
);
getActivity
().
findViewById
(
R
.
id
.
container_body
)
.
getGlobalVisibleRect
(
finalBounds
,
globalOffset
);
startBounds
.
offset
(-
globalOffset
.
x
,
-
globalOffset
.
y
);
finalBounds
.
offset
(-
globalOffset
.
x
,
-
globalOffset
.
y
);
// Adjust the start bounds to be the same aspect ratio as the final
// bounds using the "center crop" technique. This prevents undesirable
// stretching during the animation. Also calculate the start scaling
// factor (the end scaling factor is always 1.0).
float
startScale
;
if
((
float
)
finalBounds
.
width
()
/
finalBounds
.
height
()
>
(
float
)
startBounds
.
width
()
/
startBounds
.
height
())
{
// Extend start bounds horizontally
startScale
=
(
float
)
startBounds
.
height
()
/
finalBounds
.
height
();
float
startWidth
=
startScale
*
finalBounds
.
width
();
float
deltaWidth
=
(
startWidth
-
startBounds
.
width
())
/
2
;
startBounds
.
left
-=
deltaWidth
;
startBounds
.
right
+=
deltaWidth
;
}
else
{
// Extend start bounds vertically
startScale
=
(
float
)
startBounds
.
width
()
/
finalBounds
.
width
();
float
startHeight
=
startScale
*
finalBounds
.
height
();
float
deltaHeight
=
(
startHeight
-
startBounds
.
height
())
/
2
;
startBounds
.
top
-=
deltaHeight
;
startBounds
.
bottom
+=
deltaHeight
;
}
// Hide the thumbnail and show the zoomed-in view. When the animation
// begins, it will position the zoomed-in view in the place of the
// thumbnail.
thumbView
.
setAlpha
(
0
f
);
expandedImageView
.
setVisibility
(
View
.
VISIBLE
);
// Set the pivot point for SCALE_X and SCALE_Y transformations
// to the top-left corner of the zoomed-in view (the default
// is the center of the view).
expandedImageView
.
setPivotX
(
0
f
);
expandedImageView
.
setPivotY
(
0
f
);
// Construct and run the parallel animation of the four translation and
// scale properties (X, Y, SCALE_X, and SCALE_Y).
AnimatorSet
set
=
new
AnimatorSet
();
set
.
play
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
X
,
startBounds
.
left
,
finalBounds
.
left
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
Y
,
startBounds
.
top
,
finalBounds
.
top
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_X
,
startScale
,
1
f
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_Y
,
startScale
,
1
f
));
set
.
setDuration
(
mShortAnimationDuration
);
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
mCurrentAnimator
=
null
;
expandedImageView
.
setBackgroundColor
(
Color
.
parseColor
(
"#9E9E9E"
));
}
@Override
public
void
onAnimationCancel
(
Animator
animation
)
{
mCurrentAnimator
=
null
;
}
});
set
.
start
();
mCurrentAnimator
=
set
;
startScaleFinal
=
startScale
;
zoomMode
=
true
;
}
}
app/src/main/java/app/insti/fragment/EventFragment.java
View file @
3541aa3c
package
app.insti.fragment
;
import
android.animation.Animator
;
import
android.animation.AnimatorListenerAdapter
;
import
android.animation.AnimatorSet
;
import
android.animation.ObjectAnimator
;
import
android.content.Intent
;
import
android.graphics.Color
;
import
android.graphics.Typeface
;
import
android.graphics.Point
;
import
android.graphics.Rect
;
import
android.net.Uri
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
...
...
@@ -16,11 +21,11 @@ import android.text.Spannable;
import
android.text.SpannableString
;
import
android.text.style.ForegroundColorSpan
;
import
android.text.style.RelativeSizeSpan
;
import
android.text.style.StyleSpan
;
import
android.util.Log
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.view.animation.DecelerateInterpolator
;
import
android.widget.Button
;
import
android.widget.ImageButton
;
import
android.widget.ImageView
;
...
...
@@ -55,7 +60,7 @@ import ru.noties.markwon.Markwon;
/**
* A simple {@link Fragment} subclass.
*/
public
class
EventFragment
extends
Ba
se
Fragment
{
public
class
EventFragment
extends
Ba
ckHandled
Fragment
{
Event
event
;
Button
goingButton
;
Button
interestedButton
;
...
...
@@ -66,6 +71,21 @@ public class EventFragment extends BaseFragment {
String
TAG
=
"EventFragment"
;
private
AppDatabase
appDatabase
;
// Hold a reference to the current animator,
// so that it can be canceled mid-way.
private
Animator
mCurrentAnimator
;
// The system "short" animation time duration, in milliseconds. This
// duration is ideal for subtle animations or animations that occur
// very frequently.
private
int
mShortAnimationDuration
;
private
boolean
zoomMode
;
private
ImageView
expandedImageView
;
private
Rect
startBounds
;
private
float
startScaleFinal
;
private
ImageView
eventPicture
;
public
EventFragment
()
{
// Required empty public constructor
}
...
...
@@ -78,6 +98,16 @@ public class EventFragment extends BaseFragment {
return
inflater
.
inflate
(
R
.
layout
.
fragment_event
,
container
,
false
);
}
@Override
public
boolean
onBackPressed
()
{
if
(
zoomMode
)
{
zoomOut
(
expandedImageView
,
startBounds
,
startScaleFinal
,
eventPicture
);
zoomMode
=
false
;
return
true
;
}
return
false
;
}
@Override
public
void
onStart
()
{
super
.
onStart
();
...
...
@@ -96,7 +126,7 @@ public class EventFragment extends BaseFragment {
}
private
void
inflateViews
(
final
Event
event
)
{
ImageView
eventPicture
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
event_picture_2
);
eventPicture
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
event_picture_2
);
TextView
eventTitle
=
(
TextView
)
getActivity
().
findViewById
(
R
.
id
.
event_page_title
);
TextView
eventDate
=
(
TextView
)
getActivity
().
findViewById
(
R
.
id
.
event_page_date
);
TextView
eventTime
=
(
TextView
)
getActivity
().
findViewById
(
R
.
id
.
event_page_time
);
...
...
@@ -190,6 +220,14 @@ public class EventFragment extends BaseFragment {
}
});
}
eventPicture
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
zoomImageFromThumb
(
eventPicture
);
}
});
mShortAnimationDuration
=
getResources
().
getInteger
(
android
.
R
.
integer
.
config_shortAnimTime
);
}
void
setFollowButtonColors
(
int
status
)
{
...
...
@@ -203,7 +241,8 @@ public class EventFragment extends BaseFragment {
/**
* Get a spannable with a small count badge to set for an element text
* @param text Text to show in the spannable
*
* @param text Text to show in the spannable
* @param count integer count to show in the badge
* @return spannable to be used as view.setText(spannable)
*/
...
...
@@ -255,4 +294,140 @@ public class EventFragment extends BaseFragment {
}
}
private
void
zoomImageFromThumb
(
final
ImageView
thumbView
)
{
// If there's an animation in progress, cancel it
// immediately and proceed with this one.
if
(
mCurrentAnimator
!=
null
)
{
mCurrentAnimator
.
cancel
();
}
// Load the high-resolution "zoomed-in" image.
expandedImageView
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
expanded_image_event
);
expandedImageView
.
setImageDrawable
(
thumbView
.
getDrawable
());
// Calculate the starting and ending bounds for the zoomed-in image.
// This step involves lots of math. Yay, math.
startBounds
=
new
Rect
();
final
Rect
finalBounds
=
new
Rect
();
final
Point
globalOffset
=
new
Point
();
// The start bounds are the global visible rectangle of the thumbnail,
// and the final bounds are the global visible rectangle of the container
// view. Also set the container view's offset as the origin for the
// bounds, since that's the origin for the positioning animation
// properties (X, Y).
thumbView
.
getGlobalVisibleRect
(
startBounds
);
getActivity
().
findViewById
(
R
.
id
.
container_event
)
.
getGlobalVisibleRect
(
finalBounds
,
globalOffset
);
startBounds
.
offset
(-
globalOffset
.
x
,
-
globalOffset
.
y
);
finalBounds
.
offset
(-
globalOffset
.
x
,
-
globalOffset
.
y
);
// Adjust the start bounds to be the same aspect ratio as the final
// bounds using the "center crop" technique. This prevents undesirable
// stretching during the animation. Also calculate the start scaling
// factor (the end scaling factor is always 1.0).
float
startScale
;
if
((
float
)
finalBounds
.
width
()
/
finalBounds
.
height
()
>
(
float
)
startBounds
.
width
()
/
startBounds
.
height
())
{
// Extend start bounds horizontally
startScale
=
(
float
)
startBounds
.
height
()
/
finalBounds
.
height
();
float
startWidth
=
startScale
*
finalBounds
.
width
();
float
deltaWidth
=
(
startWidth
-
startBounds
.
width
())
/
2
;
startBounds
.
left
-=
deltaWidth
;
startBounds
.
right
+=
deltaWidth
;
}
else
{
// Extend start bounds vertically
startScale
=
(
float
)
startBounds
.
width
()
/
finalBounds
.
width
();
float
startHeight
=
startScale
*
finalBounds
.
height
();
float
deltaHeight
=
(
startHeight
-
startBounds
.
height
())
/
2
;
startBounds
.
top
-=
deltaHeight
;
startBounds
.
bottom
+=
deltaHeight
;
}
// Hide the thumbnail and show the zoomed-in view. When the animation
// begins, it will position the zoomed-in view in the place of the
// thumbnail.
thumbView
.
setAlpha
(
0
f
);
expandedImageView
.
setVisibility
(
View
.
VISIBLE
);
// Set the pivot point for SCALE_X and SCALE_Y transformations
// to the top-left corner of the zoomed-in view (the default
// is the center of the view).
expandedImageView
.
setPivotX
(
0
f
);
expandedImageView
.
setPivotY
(
0
f
);
// Construct and run the parallel animation of the four translation and
// scale properties (X, Y, SCALE_X, and SCALE_Y).
AnimatorSet
set
=
new
AnimatorSet
();
set
.
play
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
X
,
startBounds
.
left
,
finalBounds
.
left
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
Y
,
startBounds
.
top
,
finalBounds
.
top
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_X
,
startScale
,
1
f
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_Y
,
startScale
,
1
f
));
set
.
setDuration
(
mShortAnimationDuration
);
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
mCurrentAnimator
=
null
;
expandedImageView
.
setBackgroundColor
(
Color
.
parseColor
(
"#9E9E9E"
));
}
@Override
public
void
onAnimationCancel
(
Animator
animation
)
{
mCurrentAnimator
=
null
;
}
});
set
.
start
();
mCurrentAnimator
=
set
;
startScaleFinal
=
startScale
;
zoomMode
=
true
;
}
private
void
zoomOut
(
final
ImageView
expandedImageView
,
Rect
startBounds
,
float
startScaleFinal
,
final
View
thumbView
)
{
expandedImageView
.
setBackgroundColor
(
0x00000000
);
if
(
mCurrentAnimator
!=
null
)
{
mCurrentAnimator
.
cancel
();
}
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
AnimatorSet
set
=
new
AnimatorSet
();
set
.
play
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
X
,
startBounds
.
left
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
Y
,
startBounds
.
top
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_X
,
startScaleFinal
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_Y
,
startScaleFinal
));
set
.
setDuration
(
mShortAnimationDuration
);
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
thumbView
.
setAlpha
(
1
f
);
expandedImageView
.
setVisibility
(
View
.
GONE
);
mCurrentAnimator
=
null
;
}
@Override
public
void
onAnimationCancel
(
Animator
animation
)
{
thumbView
.
setAlpha
(
1
f
);
expandedImageView
.
setVisibility
(
View
.
GONE
);
mCurrentAnimator
=
null
;
}
});
set
.
start
();
mCurrentAnimator
=
set
;
}
}
app/src/main/java/app/insti/fragment/ProfileFragment.java
View file @
3541aa3c
package
app.insti.fragment
;
import
android.animation.Animator
;
import
android.animation.AnimatorListenerAdapter
;
import
android.animation.AnimatorSet
;
import
android.animation.ObjectAnimator
;
import
android.graphics.Color
;
import
android.graphics.Point
;
import
android.graphics.Rect
;
import
android.os.Bundle
;
import
android.support.design.widget.TabLayout
;
import
android.support.v4.app.Fragment
;
...
...
@@ -12,10 +19,10 @@ import android.support.v7.widget.Toolbar;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.view.animation.DecelerateInterpolator
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
com.google.gson.Gson
;
import
com.squareup.picasso.Picasso
;
import
java.util.List
;
...
...
@@ -38,8 +45,22 @@ import retrofit2.Response;
/**
* A simple {@link Fragment} subclass.
*/
public
class
ProfileFragment
extends
BaseFragment
{
User
user
;
public
class
ProfileFragment
extends
BackHandledFragment
{
private
User
user
;
// Hold a reference to the current animator,
// so that it can be canceled mid-way.
private
Animator
mCurrentAnimator
;
// The system "short" animation time duration, in milliseconds. This
// duration is ideal for subtle animations or animations that occur
// very frequently.
private
int
mShortAnimationDuration
;
private
boolean
zoomMode
;
private
ImageView
expandedImageView
;
private
Rect
startBounds
;
private
float
startScaleFinal
;
private
ImageView
userProfilePictureImageView
;
public
ProfileFragment
()
{
// Required empty public constructor
...
...
@@ -53,6 +74,16 @@ public class ProfileFragment extends BaseFragment {
return
inflater
.
inflate
(
R
.
layout
.
fragment_profile
,
container
,
false
);
}
@Override
public
boolean
onBackPressed
()
{
if
(
zoomMode
)
{
zoomOut
(
expandedImageView
,
startBounds
,
startScaleFinal
,
userProfilePictureImageView
);
zoomMode
=
false
;
return
true
;
}
return
false
;
}
@Override
public
void
onStart
()
{
super
.
onStart
();
...
...
@@ -81,13 +112,13 @@ public class ProfileFragment extends BaseFragment {
}
private
void
populateViews
()
{
ImageView
userProfilePictureImageView
=
getActivity
().
findViewById
(
R
.
id
.
user_profile_picture_profile
);
userProfilePictureImageView
=
getActivity
().
findViewById
(
R
.
id
.
user_profile_picture_profile
);
TextView
userNameTextView
=
getActivity
().
findViewById
(
R
.
id
.
user_name_profile
);
TextView
userRollNumberTextView
=
getActivity
().
findViewById
(
R
.
id
.
user_rollno_profile
);
TextView
userEmailIDTextView
=
getActivity
().
findViewById
(
R
.
id
.
user_email_profile
);
TextView
userContactNumberTextView
=
getActivity
().
findViewById
(
R
.
id
.
user_contact_no_profile
);
/*
*
Show tabs */
/* Show tabs */
getActivity
().
findViewById
(
R
.
id
.
tab_layout
).
setVisibility
(
View
.
VISIBLE
);
final
List
<
Role
>
roleList
=
user
.
getUserRoles
();
...
...
@@ -115,6 +146,14 @@ public class ProfileFragment extends BaseFragment {
.
placeholder
(
R
.
drawable
.
user_placeholder
)
.
into
(
userProfilePictureImageView
);
userProfilePictureImageView
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
zoomImageFromThumb
(
userProfilePictureImageView
);
}
});
mShortAnimationDuration
=
getResources
().
getInteger
(
android
.
R
.
integer
.
config_shortAnimTime
);
final
List
<
Body
>
bodyList
=
user
.
getUserFollowedBodies
();
final
List
<
Event
>
eventList
=
user
.
getUserGoingEvents
();
final
List
<
Event
>
eventInterestedList
=
user
.
getUserInterestedEvents
();
...
...
@@ -141,6 +180,47 @@ public class ProfileFragment extends BaseFragment {
getActivity
().
findViewById
(
R
.
id
.
loadingPanel
).
setVisibility
(
View
.
GONE
);
}
private
void
zoomOut
(
final
ImageView
expandedImageView
,
Rect
startBounds
,
float
startScaleFinal
,
final
View
thumbView
)
{
expandedImageView
.
setBackgroundColor
(
0x00000000
);
if
(
mCurrentAnimator
!=
null
)
{
mCurrentAnimator
.
cancel
();
}
// Animate the four positioning/sizing properties in parallel,
// back to their original values.
AnimatorSet
set
=
new
AnimatorSet
();
set
.
play
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
X
,
startBounds
.
left
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
Y
,
startBounds
.
top
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_X
,
startScaleFinal
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_Y
,
startScaleFinal
));
set
.
setDuration
(
mShortAnimationDuration
);
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
thumbView
.
setAlpha
(
1
f
);
expandedImageView
.
setVisibility
(
View
.
GONE
);
mCurrentAnimator
=
null
;
}
@Override
public
void
onAnimationCancel
(
Animator
animation
)
{
thumbView
.
setAlpha
(
1
f
);
expandedImageView
.
setVisibility
(
View
.
GONE
);
mCurrentAnimator
=
null
;
}
});
set
.
start
();
mCurrentAnimator
=
set
;
}
public
static
ProfileFragment
newInstance
(
String
userID
)
{
ProfileFragment
fragment
=
new
ProfileFragment
();
Bundle
args
=
new
Bundle
();
...
...
@@ -148,4 +228,100 @@ public class ProfileFragment extends BaseFragment {
fragment
.
setArguments
(
args
);
return
fragment
;
}
private
void
zoomImageFromThumb
(
final
ImageView
thumbView
)
{
// If there's an animation in progress, cancel it
// immediately and proceed with this one.
if
(
mCurrentAnimator
!=
null
)
{
mCurrentAnimator
.
cancel
();
}
// Load the high-resolution "zoomed-in" image.
expandedImageView
=
(
ImageView
)
getActivity
().
findViewById
(
R
.
id
.
expanded_image_profile
);
expandedImageView
.
setImageDrawable
(
thumbView
.
getDrawable
());
// Calculate the starting and ending bounds for the zoomed-in image.
// This step involves lots of math. Yay, math.
startBounds
=
new
Rect
();
final
Rect
finalBounds
=
new
Rect
();
final
Point
globalOffset
=
new
Point
();
// The start bounds are the global visible rectangle of the thumbnail,
// and the final bounds are the global visible rectangle of the container
// view. Also set the container view's offset as the origin for the
// bounds, since that's the origin for the positioning animation
// properties (X, Y).
thumbView
.
getGlobalVisibleRect
(
startBounds
);
getActivity
().
findViewById
(
R
.
id
.
container_profile
)
.
getGlobalVisibleRect
(
finalBounds
,
globalOffset
);
startBounds
.
offset
(-
globalOffset
.
x
,
-
globalOffset
.
y
);
finalBounds
.
offset
(-
globalOffset
.
x
,
-
globalOffset
.
y
);
// Adjust the start bounds to be the same aspect ratio as the final
// bounds using the "center crop" technique. This prevents undesirable
// stretching during the animation. Also calculate the start scaling
// factor (the end scaling factor is always 1.0).
float
startScale
;
if
((
float
)
finalBounds
.
width
()
/
finalBounds
.
height
()
>
(
float
)
startBounds
.
width
()
/
startBounds
.
height
())
{
// Extend start bounds horizontally
startScale
=
(
float
)
startBounds
.
height
()
/
finalBounds
.
height
();
float
startWidth
=
startScale
*
finalBounds
.
width
();
float
deltaWidth
=
(
startWidth
-
startBounds
.
width
())
/
2
;
startBounds
.
left
-=
deltaWidth
;
startBounds
.
right
+=
deltaWidth
;
}
else
{
// Extend start bounds vertically
startScale
=
(
float
)
startBounds
.
width
()
/
finalBounds
.
width
();
float
startHeight
=
startScale
*
finalBounds
.
height
();
float
deltaHeight
=
(
startHeight
-
startBounds
.
height
())
/
2
;
startBounds
.
top
-=
deltaHeight
;
startBounds
.
bottom
+=
deltaHeight
;
}
// Hide the thumbnail and show the zoomed-in view. When the animation
// begins, it will position the zoomed-in view in the place of the
// thumbnail.
thumbView
.
setAlpha
(
0
f
);
expandedImageView
.
setVisibility
(
View
.
VISIBLE
);
// Set the pivot point for SCALE_X and SCALE_Y transformations
// to the top-left corner of the zoomed-in view (the default
// is the center of the view).
expandedImageView
.
setPivotX
(
0
f
);
expandedImageView
.
setPivotY
(
0
f
);
// Construct and run the parallel animation of the four translation and
// scale properties (X, Y, SCALE_X, and SCALE_Y).
AnimatorSet
set
=
new
AnimatorSet
();
set
.
play
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
X
,
startBounds
.
left
,
finalBounds
.
left
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
Y
,
startBounds
.
top
,
finalBounds
.
top
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_X
,
startScale
,
1
f
))
.
with
(
ObjectAnimator
.
ofFloat
(
expandedImageView
,
View
.
SCALE_Y
,
startScale
,
1
f
));
set
.
setDuration
(
mShortAnimationDuration
);
set
.
setInterpolator
(
new
DecelerateInterpolator
());
set
.
addListener
(
new
AnimatorListenerAdapter
()
{
@Override
public
void
onAnimationEnd
(
Animator
animation
)
{
mCurrentAnimator
=
null
;
expandedImageView
.
setBackgroundColor
(
Color
.
parseColor
(
"#9E9E9E"
));
}
@Override
public
void
onAnimationCancel
(
Animator
animation
)
{
mCurrentAnimator
=
null
;
}
});
set
.
start
();
mCurrentAnimator
=
set
;
startScaleFinal
=
startScale
;
zoomMode
=
true
;
}
}
app/src/main/res/layout/fragment_body.xml
View file @
3541aa3c
...
...
@@ -2,6 +2,7 @@
<FrameLayout
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/container_body"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
...
...
@@ -128,75 +129,75 @@
<TextView
android:id=
"@+id/body_events_title"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"15dp"
android:fontFamily=
"sans-serif-light"
android:text=
"Events"
android:textSize=
"20sp"
/>
android:textSize=
"20sp"
android:visibility=
"gone"
/>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/event_card_recycler_view"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:nestedScrollingEnabled=
"false"
/>
android:nestedScrollingEnabled=
"false"
android:visibility=
"gone"
/>
<TextView
android:id=
"@+id/body_orgs_title"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"15dp"
android:fontFamily=
"sans-serif-light"
android:text=
"Organizations"
android:textSize=
"20sp"
/>
android:textSize=
"20sp"
android:visibility=
"gone"
/>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/org_card_recycler_view"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:nestedScrollingEnabled=
"false"
/>
android:nestedScrollingEnabled=
"false"
android:visibility=
"gone"
/>
<TextView
android:id=
"@+id/body_people_title"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"15dp"
android:fontFamily=
"sans-serif-light"
android:text=
"People"
android:textSize=
"20sp"
/>
android:textSize=
"20sp"
android:visibility=
"gone"
/>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/people_card_recycler_view"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:nestedScrollingEnabled=
"false"
/>
android:nestedScrollingEnabled=
"false"
android:visibility=
"gone"
/>
<TextView
android:id=
"@+id/body_parents_title"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginLeft=
"15dp"
android:fontFamily=
"sans-serif-light"
android:text=
"Part of"
android:textSize=
"20sp"
/>
android:textSize=
"20sp"
android:visibility=
"gone"
/>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/parentorg_card_recycler_view"
android:visibility=
"gone"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:nestedScrollingEnabled=
"false"
/>
android:nestedScrollingEnabled=
"false"
android:visibility=
"gone"
/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
...
...
@@ -213,4 +214,11 @@
android:layout_height=
"wrap_content"
android:indeterminate=
"true"
/>
</RelativeLayout>
<app.insti.TouchImageView
android:id=
"@+id/expanded_image_body"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:contentDescription=
"Zoomed Image"
android:visibility=
"gone"
/>
</FrameLayout>
\ No newline at end of file
app/src/main/res/layout/fragment_event.xml
View file @
3541aa3c
<
Linear
Layout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<
Frame
Layout
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/container_event"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
tools:context=
"app.insti.fragment.EventFragment"
>
<
ScrollView
<
LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
android:layout_height=
"match_parent"
android:orientation=
"vertical"
>
<
LinearLayout
<
ScrollView
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"1"
android:orientation=
"vertical"
>
android:layout_height=
"wrap_content"
>
<ImageView
android:id=
"@+id/event_picture_2"
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"
30
0dp"
android:
adjustViewBounds=
"true
"
android:
scaleType=
"centerCrop"
/
>
android:layout_height=
"0dp"
android:
layout_weight=
"1
"
android:
orientation=
"vertical"
>
<android.support.v7.widget.CardView
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
app:cardBackgroundColor=
"@color/colorPrimary"
>
<ImageView
android:id=
"@+id/event_picture_2"
android:layout_width=
"match_parent"
android:layout_height=
"300dp"
android:adjustViewBounds=
"true"
android:scaleType=
"centerCrop"
/>
<
LinearLayout
<
android.support.v7.widget.CardView
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginBottom=
"12dp"
android:layout_marginEnd=
"16dp"
android:layout_marginStart=
"16dp"
android:layout_marginTop=
"12dp"
android:layout_weight=
"3"
android:orientation=
"vertical"
>
app:cardBackgroundColor=
"@color/colorPrimary"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<TextView
android:id=
"@+id/event_page_title"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"10"
android:text=
"Event Title"
android:textColor=
"#fff"
android:textSize=
"21sp"
android:textStyle=
"bold"
/>
<ImageButton
android:id=
"@+id/web_event_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginStart=
"8dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"Event Website"
android:tint=
"@color/colorWhite"
android:visibility=
"invisible"
app:srcCompat=
"@drawable/ic_language_black_24dp"
/>
<ImageButton
android:id=
"@+id/navigate_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginStart=
"8dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"Navigate"
android:tint=
"@color/colorWhite"
app:srcCompat=
"@drawable/baseline_navigation_24"
/>
<ImageButton
android:id=
"@+id/share_event_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginStart=
"8dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"Share Event"
android:src=
"@drawable/ic_menu_share"
android:tint=
"@color/colorWhite"
/>
</LinearLayout>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<TextView
android:id=
"@+id/event_page_date"
android:layout_width=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginBottom=
"12dp"
android:layout_marginEnd=
"16dp"
android:layout_marginStart=
"16dp"
android:layout_marginTop=
"12dp"
android:layout_weight=
"3"
android:orientation=
"vertical"
>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:text=
"No Date Specified"
android:textColor=
"#fff"
android:textSize=
"16sp"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
" | "
android:textColor=
"#fff"
android:textSize=
"20sp"
/>
<TextView
android:id=
"@+id/event_page_time"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"No Time Specified"
android:textColor=
"#fff"
android:textSize=
"16sp"
/>
<TextView
android:orientation=
"horizontal"
>
<TextView
android:id=
"@+id/event_page_title"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_weight=
"10"
android:text=
"Event Title"
android:textColor=
"#fff"
android:textSize=
"21sp"
android:textStyle=
"bold"
/>
<ImageButton
android:id=
"@+id/web_event_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginStart=
"8dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"Event Website"
android:tint=
"@color/colorWhite"
android:visibility=
"invisible"
app:srcCompat=
"@drawable/ic_language_black_24dp"
/>
<ImageButton
android:id=
"@+id/navigate_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginStart=
"8dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"Navigate"
android:tint=
"@color/colorWhite"
app:srcCompat=
"@drawable/baseline_navigation_24"
/>
<ImageButton
android:id=
"@+id/share_event_button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical"
android:layout_marginStart=
"8dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"Share Event"
android:src=
"@drawable/ic_menu_share"
android:tint=
"@color/colorWhite"
/>
</LinearLayout>
<LinearLayout
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
" | "
android:textColor=
"#fff"
android:textSize=
"20sp"
/>
android:orientation=
"horizontal"
>
<TextView
android:id=
"@+id/event_page_date"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"No Date Specified"
android:textColor=
"#fff"
android:textSize=
"16sp"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
" | "
android:textColor=
"#fff"
android:textSize=
"20sp"
/>
<TextView
android:id=
"@+id/event_page_time"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"No Time Specified"
android:textColor=
"#fff"
android:textSize=
"16sp"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
" | "
android:textColor=
"#fff"
android:textSize=
"20sp"
/>
<TextView
android:id=
"@+id/event_page_venue"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:text=
"No Venue Specified"
android:textColor=
"#fff"
android:textSize=
"16sp"
/>
</LinearLayout>
<TextView
android:id=
"@+id/event_page_venue"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:text=
"No Venue Specified"
android:textColor=
"#fff"
android:textSize=
"16sp"
/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v7.widget.CardView>
<LinearLayout
style=
"?android:attr/buttonBarStyle"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<LinearLayout
style=
"?android:attr/buttonBarStyle"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<Button
android:id=
"@+id/going_button"
style=
"?android:attr/buttonBarButtonStyle"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_margin=
"0dp"
android:layout_weight=
"1"
android:text=
"Going"
android:textColor=
"@color/secondaryTextColor"
/>
<View
android:layout_width=
"1dp"
android:layout_height=
"match_parent"
android:layout_marginBottom=
"6dp"
android:layout_marginTop=
"10dp"
android:background=
"#aaa"
>
</View>
<Button
android:id=
"@+id/interested_button"
style=
"?android:attr/buttonBarButtonStyle"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_margin=
"0dp"
android:layout_weight=
"1"
android:text=
"Interested"
android:textColor=
"@color/secondaryTextColor"
/>
<Button
android:id=
"@+id/going_button"
style=
"?android:attr/buttonBarButtonStyle"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_margin=
"0dp"
android:layout_weight=
"1"
android:text=
"Going"
android:textColor=
"@color/secondaryTextColor"
/>
</LinearLayout>
<View
android:layout_width=
"
1dp
"
android:layout_height=
"
match_parent
"
android:layout_margin
Bottom=
"6
dp"
android:layout_margin
Top=
"10
dp"
android:layout_width=
"
match_parent
"
android:layout_height=
"
1dp
"
android:layout_margin
Left=
"8
dp"
android:layout_margin
Right=
"8
dp"
android:background=
"#aaa"
>
</View>
<Button
android:id=
"@+id/interested_button"
style=
"?android:attr/buttonBarButtonStyle"
android:layout_width=
"0dp"
<TextView
android:id=
"@+id/event_page_description"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_margin=
"0dp"
android:layout_weight=
"1"
android:text=
"Interested"
android:textColor=
"@color/secondaryTextColor"
/>
</LinearLayout>
<View
android:layout_width=
"match_parent"
android:layout_height=
"1dp"
android:layout_marginLeft=
"8dp"
android:layout_marginRight=
"8dp"
android:background=
"#aaa"
>
android:layout_marginBottom=
"16dp"
android:layout_marginEnd=
"10dp"
android:layout_marginStart=
"10dp"
android:layout_marginTop=
"12dp"
android:textColor=
"#777"
android:textSize=
"16sp"
/>
</View>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/body_card_recycler_view"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"10dp"
/>
<TextView
android:id=
"@+id/event_page_description"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"16dp"
android:layout_marginEnd=
"10dp"
android:layout_marginStart=
"10dp"
android:layout_marginTop=
"12dp"
android:textColor=
"#777"
android:textSize=
"16sp"
/>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/body_card_recycler_view"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"10dp"
/>
</LinearLayout>
</ScrollView>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
<app.insti.TouchImageView
android:id=
"@+id/expanded_image_event"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:contentDescription=
"Zoomed Image"
android:visibility=
"gone"
/>
</FrameLayout>
app/src/main/res/layout/fragment_profile.xml
View file @
3541aa3c
<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:id=
"@+id/container_profile"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
...
...
@@ -103,4 +104,11 @@
android:layout_height=
"wrap_content"
android:indeterminate=
"true"
/>
</RelativeLayout>
<app.insti.TouchImageView
android:id=
"@+id/expanded_image_profile"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:visibility=
"gone"
android:contentDescription=
"Zoomed Image"
/>
</RelativeLayout>
\ No newline at end of file
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