Commit 893c9986 by chengfengpiaopiao

图片选择器

parent 34c76b40
Showing with 7846 additions and 76 deletions
......@@ -9,6 +9,7 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/multi-image-selector" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
......
......@@ -6,6 +6,7 @@
<module fileurl="file://$PROJECT_DIR$/DuoBaoJingCai2.iml" filepath="$PROJECT_DIR$/DuoBaoJingCai2.iml" />
<module fileurl="file://G:/Product/Android/DuoBaoJingCai/DuoBaoJingCai2.iml" filepath="G:/Product/Android/DuoBaoJingCai/DuoBaoJingCai2.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/multi-image-selector/multi-image-selector.iml" filepath="$PROJECT_DIR$/multi-image-selector/multi-image-selector.iml" />
</modules>
</component>
</project>
\ No newline at end of file
......@@ -106,4 +106,6 @@ dependencies {
compile 'com.umeng.analytics:analytics:latest.integration'
compile 'com.meituan.android.walle:library:1.1.5' //walle
compile project(path: ':multi-image-selector')
}
......@@ -70,7 +70,10 @@
</intent-filter>
</activity>
<!-- 个人信息页面设置的activity -->
<activity
android:name=".view.activity.ImageCropHeadActivity"
android:screenOrientation="portrait" />
<!-- 微信 -->
<activity
android:name=".wxapi.WXEntryActivity"
......
package com.maile.jingcai.base;
import android.os.Environment;
import com.maile.jingcai.BuildConfig;
/**
......@@ -24,6 +26,15 @@ public class Constant {
public static final String WEIXIN_AUTH_LOGIN_INFO_SCOPE = "snsapi_userinfo";
public static final String WEIXIN_AUTH_LOGIN_INFO_STATE = "wtf";
public final static String SDCARD = Environment.getExternalStorageDirectory().getPath();
public static String sBANANA_DIR = SDCARD + "/duobaojingcai";
//用户信息路径
public final static String ACCOUNT_DIR = sBANANA_DIR + "/account/";
//裁剪图片临时缓冲文件
public final static String ACCOUNT_CROP_DIR = ACCOUNT_DIR + "/crop";
//分享图片路径
public final static String SHARE_DIR = sBANANA_DIR + "/share/";
//正式地址
public static final String RELEASE_BASE_URL = "http://700sport.com/";
......
/*******************************************************************************
* 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.maile.jingcai.commponent;
import android.annotation.TargetApi;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.view.MotionEvent;
import android.view.View;
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;
}
}
package com.maile.jingcai.commponent;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.maile.jingcai.R;
import com.maile.jingcai.util.DrawUtil;
import com.maile.jingcai.util.PaintUtil;
/**
* @author GT Modified/stripped down Code from cropper library : https://github.com/edmodo/cropper
*/
public class CropOverlayView extends View implements IGetImageBounds {
//Defaults
private boolean DEFAULT_GUIDELINES = true;
private int DEFAULT_MARGINTOP = 100;
private int DEFAULT_MARGINSIDE = 50;
private int DEFAULT_MIN_WIDTH = 500;
private int DEFAULT_MAX_WIDTH = 700;
// we are cropping square image so width and height will always be equal
private int DEFAULT_CROPWIDTH = 600;
private static final int DEFAULT_CORNER_RADIUS = 6;
private static final int DEFAULT_OVERLAY_COLOR = Color.argb(102, 0, 0, 0);
// The Paint used to darken the surrounding areas outside the crop area.
private Paint mBackgroundPaint;
// The Paint used to draw the white rectangle around the crop area.
private Paint mBorderPaint;
// The Paint used to draw the guidelines within the crop area.
private Paint mGuidelinePaint;
private Path mClipPath;
// The bounding box around the Bitmap that we are cropping.
private RectF mBitmapRect;
private int cropHeight = DEFAULT_CROPWIDTH;
private int cropWidth = DEFAULT_CROPWIDTH;
private boolean mGuidelines;
private int mMarginTop;
private int mMarginSide;
private int mMinWidth;
private int mMaxWidth;
private int mCornerRadius;
private int mOverlayColor;
private Context mContext;
public CropOverlayView(Context context) {
super(context);
init(context);
mContext = context;
}
public CropOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CropOverlayView, 0, 0);
try {
mGuidelines = ta.getBoolean(R.styleable.CropOverlayView_guideLines, DEFAULT_GUIDELINES);
mMarginTop = ta.getDimensionPixelSize(R.styleable.CropOverlayView_marginTop, DEFAULT_MARGINTOP);
mMarginSide = ta.getDimensionPixelSize(R.styleable.CropOverlayView_marginSide, DEFAULT_MARGINSIDE);
mMinWidth = ta.getDimensionPixelSize(R.styleable.CropOverlayView_minWidth, DEFAULT_MIN_WIDTH);
mMaxWidth = ta.getDimensionPixelSize(R.styleable.CropOverlayView_maxWidth, DEFAULT_MAX_WIDTH);
final float defaultRadius = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_RADIUS, mContext.getResources().getDisplayMetrics());
mCornerRadius = ta.getDimensionPixelSize(R.styleable.CropOverlayView_cornerRadius, (int) defaultRadius);
mOverlayColor = ta.getColor(R.styleable.CropOverlayView_overlayColor, DEFAULT_OVERLAY_COLOR);
} finally {
ta.recycle();
}
init(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//BUG FIX : Turn of hardware acceleration. Clip path doesn't work with hardware acceleration
//BUG FIX : Will have to do it here @ View level. Activity level not working on HTC ONE X
//http://stackoverflow.com/questions/8895677/work-around-canvas-clippath-that-is-not-supported-in-android-any-more/8895894#8895894
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
canvas.save();
mBitmapRect.left = Edge.LEFT.getCoordinate();
mBitmapRect.top = Edge.TOP.getCoordinate();
mBitmapRect.right = Edge.RIGHT.getCoordinate();
mBitmapRect.bottom = Edge.BOTTOM.getCoordinate();
mClipPath.addRoundRect(mBitmapRect, mCornerRadius, mCornerRadius, Path.Direction.CW);
canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
canvas.drawColor(mOverlayColor);
mClipPath.reset();
canvas.restore();
canvas.drawRoundRect(mBitmapRect, mCornerRadius, mCornerRadius, mBorderPaint);
//GT : Drop shadow not working right now. Commenting the code now
// //Draw shadow
// Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// paint.setShadowLayer(12, 0, 0, Color.YELLOW);
// paint.setAlpha(0);
if (mGuidelines) {
drawRuleOfThirdsGuidelines(canvas);
}
}
@Override
public Rect getImageBounds() {
return new Rect(
(int) Edge.LEFT.getCoordinate(), (int) Edge.TOP.getCoordinate(),
(int) Edge.RIGHT.getCoordinate(), (int) Edge.BOTTOM.getCoordinate());
}
// Private Methods /////////////////////////////////////////////////////////
private void init(Context context) {
int w = context.getResources().getDisplayMetrics().widthPixels;
cropWidth = w - 2 * mMarginSide;
//noinspection SuspiciousNameCombination
cropHeight = cropWidth;
mMarginTop = (DrawUtil.sHeightPixels - DrawUtil.dip2px(120) - w)/2; //居中
int edgeT = mMarginTop;
int edgeB = mMarginTop + cropHeight;
int edgeL = mMarginSide;
int edgeR = mMarginSide + cropWidth;
mBackgroundPaint = PaintUtil.newBackgroundPaint(context);
mBorderPaint = PaintUtil.newBorderPaint(context);
mGuidelinePaint = PaintUtil.newGuidelinePaint();
Edge.TOP.setCoordinate(edgeT);
Edge.BOTTOM.setCoordinate(edgeB);
Edge.LEFT.setCoordinate(edgeL);
Edge.RIGHT.setCoordinate(edgeR);
mBitmapRect = new RectF(edgeL, edgeT, edgeR, edgeB);
mClipPath = new Path();
}
private void drawRuleOfThirdsGuidelines(Canvas canvas) {
final float left = Edge.LEFT.getCoordinate();
final float top = Edge.TOP.getCoordinate();
final float right = Edge.RIGHT.getCoordinate();
final float bottom = Edge.BOTTOM.getCoordinate();
// Draw vertical guidelines.
final float oneThirdCropWidth = Edge.getWidth() / 3;
final float x1 = left + oneThirdCropWidth;
canvas.drawLine(x1, top, x1, bottom, mGuidelinePaint);
final float x2 = right - oneThirdCropWidth;
canvas.drawLine(x2, top, x2, bottom, mGuidelinePaint);
// Draw horizontal guidelines.
final float oneThirdCropHeight = Edge.getHeight() / 3;
final float y1 = top + oneThirdCropHeight;
canvas.drawLine(left, y1, right, y1, mGuidelinePaint);
final float y2 = bottom - oneThirdCropHeight;
canvas.drawLine(left, y2, right, y2, mGuidelinePaint);
}
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.maile.jingcai.commponent;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
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();
}
public boolean isScaling() {
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mVelocityTracker = VelocityTracker.obtain();
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
} else {
Log.i(LOG_TAG, "Velocity tracker is null");
}
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
mIsDragging = false;
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);
final float dx = x - mLastTouchX, dy = y - mLastTouchY;
if (!mIsDragging) {
// Use Pythagoras to see if drag length is larger than
// touch slop
mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
}
if (mIsDragging) {
mListener.onDrag(dx, dy);
mLastTouchX = x;
mLastTouchY = y;
if (null != mVelocityTracker) {
mVelocityTracker.addMovement(ev);
}
}
break;
}
case MotionEvent.ACTION_CANCEL: {
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
case MotionEvent.ACTION_UP: {
if (mIsDragging) {
if (null != mVelocityTracker) {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
// Compute velocity within the last 1000ms
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000);
final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker
.getYVelocity();
// If the velocity is greater than minVelocity, call
// listener
if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
mListener.onFling(mLastTouchX, mLastTouchY, -vX,
-vY);
}
}
}
// Recycle Velocity Tracker
if (null != mVelocityTracker) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
}
return true;
}
}
package com.maile.jingcai.commponent;
import android.graphics.RectF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ImageView;
/**
* Provided default implementation of GestureDetector.OnDoubleTapListener, to be overriden with custom behavior, if needed
*/
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;
}
}
}
if (null != photoViewAttacher.getOnViewTapListener()) {
photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY());
}
return false;
}
@Override
public boolean onDoubleTap(MotionEvent ev) {
if (photoViewAttacher == null)
return false;
try {
float scale = photoViewAttacher.getScale();
float x = ev.getX();
float y = ev.getY();
if (scale < photoViewAttacher.getMediumScale()) {
photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true);
} else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) {
photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true);
} else {
photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true);
}
} catch (ArrayIndexOutOfBoundsException e) {
// Can sometimes happen when getX() and getY() is called
}
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// Wait for the confirmed onDoubleTap() instead
return false;
}
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* 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.maile.jingcai.commponent;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.MotionEvent;
@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);
return super.onTouchEvent(ev);
}
}
/*
* Copyright 2013, Edmodo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
* You may obtain a copy of the License in the LICENSE file, or 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.maile.jingcai.commponent;
/**
* Enum representing an edge in the crop window.
*/
public enum Edge {
LEFT,
TOP,
RIGHT,
BOTTOM;
// Member Variables ////////////////////////////////////////////////////////
private float mCoordinate;
// Public Methods //////////////////////////////////////////////////////////
/**
* Sets the coordinate of the Edge. The coordinate will represent the
* x-coordinate for LEFT and RIGHT Edges and the y-coordinate for TOP and
* BOTTOM edges.
*
* @param coordinate the position of the edge
*/
public void setCoordinate(float coordinate) {
mCoordinate = coordinate;
}
/**
* Gets the coordinate of the Edge
*
* @return the Edge coordinate (x-coordinate for LEFT and RIGHT Edges and
* the y-coordinate for TOP and BOTTOM edges)
*/
public float getCoordinate() {
return mCoordinate;
}
/**
* Gets the current width of the crop window.
*/
public static float getWidth() {
return Edge.RIGHT.getCoordinate() - Edge.LEFT.getCoordinate();
}
/**
* Gets the current height of the crop window.
*/
public static float getHeight() {
return Edge.BOTTOM.getCoordinate() - Edge.TOP.getCoordinate();
}
}
/*******************************************************************************
* 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.maile.jingcai.commponent;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
@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) {
mDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
}
/*******************************************************************************
* 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.maile.jingcai.commponent;
import android.view.MotionEvent;
public interface GestureDetector {
boolean onTouchEvent(MotionEvent ev);
boolean isScaling();
void setOnGestureListener(OnGestureListener listener);
}
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.maile.jingcai.commponent;
import android.annotation.TargetApi;
import android.content.Context;
import android.widget.OverScroller;
@TargetApi(9)
public class GingerScroller extends ScrollerProxy {
protected final OverScroller mScroller;
private boolean mFirstScroll = false;
public GingerScroller(Context context) {
mScroller = new OverScroller(context);
}
@Override
public boolean computeScrollOffset() {
// Workaround for first scroll returning 0 for the direction of the edge it hits.
// Simply recompute values.
if (mFirstScroll) {
mScroller.computeScrollOffset();
mFirstScroll = false;
}
return mScroller.computeScrollOffset();
}
@Override
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY,
int overX, int overY) {
mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY);
}
@Override
public void forceFinished(boolean finished) {
mScroller.forceFinished(finished);
}
@Override
public boolean isFinished() {
return mScroller.isFinished();
}
@Override
public int getCurrX() {
return mScroller.getCurrX();
}
@Override
public int getCurrY() {
return mScroller.getCurrY();
}
}
\ No newline at end of file
package com.maile.jingcai.commponent;
import android.graphics.Rect;
/**
* Used by the PhotoView for calculating the crop overlay bounds.
*/
public interface IGetImageBounds {
/**
* Returns the current image cropping bounds.
*
* @return A Rect with the current image bounds
*/
Rect getImageBounds();
}
\ No newline at end of file
/*******************************************************************************
* 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.maile.jingcai.commponent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.view.GestureDetector;
import android.view.View;
import android.widget.ImageView;
public interface IPhotoView {
public static final float DEFAULT_MAX_SCALE = 3.0f;
public static final float DEFAULT_MID_SCALE = 1.75f;
public static final float DEFAULT_MIN_SCALE = 1.0f;
public static final int DEFAULT_ZOOM_DURATION = 200;
public static final int DEFAULT_ROTATE_DURATION = 250;
/**
* 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);
/**
* Gets the Display Matrix of the currently displayed Drawable. The Rectangle is considered
* relative to this View and includes all scaling and translations.
*
* @return - true if rectangle was applied successfully
*/
Matrix getDisplayMatrix();
/**
* Use {@link #getMinimumScale()} instead, this will be removed in future release
*
* @return The current minimum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
@Deprecated
float getMinScale();
/**
* @return The current minimum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMinimumScale();
/**
* Use {@link #getMediumScale()} instead, this will be removed in future release
*
* @return The current middle scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
@Deprecated
float getMidScale();
/**
* @return The current medium scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
float getMediumScale();
/**
* Use {@link #getMaximumScale()} instead, this will be removed in future release
*
* @return The current maximum scale level. What this value represents depends on the current
* {@link ImageView.ScaleType}.
*/
@Deprecated
float getMaxScale();
/**
* @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);
/**
* Use {@link #setMinimumScale(float minimumScale)} instead, this will be removed in future
* release <p>&nbsp;</p> Sets the minimum scale level. What this value represents depends on the
* current {@link ImageView.ScaleType}.
*
* @param minScale minimum allowed scale
*/
@Deprecated
void setMinScale(float minScale);
/**
* 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 minimum scale level so that the passed Drawable's shortest side fits exactly the
* bounds of the cropping view.
*
* @param drawable The Drawable to extract the sizes from
* @return The value of the set minimum scale
*/
float setMinimumScaleToFit(Drawable drawable);
/**
* Use {@link #setMediumScale(float mediumScale)} instead, this will be removed in future
* release <p>&nbsp;</p> Sets the middle scale level. What this value represents depends on the
* current {@link ImageView.ScaleType}.
*
* @param midScale medium scale preset
*/
@Deprecated
void setMidScale(float midScale);
/*
* Sets the medium scale level. What this value represents depends on the current {@link android.widget.ImageView.ScaleType}.
*
* @param mediumScale medium scale preset
*/
void setMediumScale(float mediumScale);
/**
* Use {@link #setMaximumScale(float maximumScale)} instead, this will be removed in future
* release <p>&nbsp;</p> Sets the maximum scale level. What this value represents depends on the
* current {@link ImageView.ScaleType}.
*
* @param maxScale maximum allowed scale preset
*/
@Deprecated
void setMaxScale(float maxScale);
/**
* 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);
/**
* 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);
/**
* Returns a listener to be invoked when the Photo displayed by this View is tapped with a
* single tap.
*
* @return PhotoViewAttacher.OnPhotoTapListener currently set, may be null
*/
PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener();
/**
* 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 with no animation via PhotoView internal functions.
*
* @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
*/
void setRotationBy(float rotationDegree);
/**
* Enables rotation via PhotoView internal functions.
*
* @param rotationDegree - Degree to rotate PhotoView by, should be in range 0 to 360
* @param animate true to animate the rotation
*/
void setRotationBy(float rotationDegree, boolean animate);
/**
* Returns a callback listener to be invoked when the View is tapped with a single tap.
*
* @return PhotoViewAttacher.OnViewTapListener currently set, may be null
*/
PhotoViewAttacher.OnViewTapListener getOnViewTapListener();
/**
* 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);
/**
* Enables rotation via PhotoView internal functions. Name is chosen so it won't collide with
* View.setRotation(float) in API since 11
*
* @param rotationDegree - Degree to rotate PhotoView to, should be in range 0 to 360
* @deprecated use {@link #setRotationTo(float)}
*/
void setPhotoViewRotation(float rotationDegree);
/**
* 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();
/**
* Returns the image cropped within the boundaries of the overlaying crop view.
*
* @return The generated cropped Bitmap
*/
Bitmap getCroppedImage();
/**
* Sets custom sencond_min 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);
/**
* Updates the current image after a layout or other events that could require changes.
*/
void update();
/**
* Resets the modifications to the current image.
*/
void reset();
void setImageBoundsListener(IGetImageBounds listener);
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.maile.jingcai.commponent;
import android.annotation.TargetApi;
import android.content.Context;
@TargetApi(14)
public class IcsScroller extends GingerScroller {
public IcsScroller(Context context) {
super(context);
}
@Override
public boolean computeScrollOffset() {
return mScroller.computeScrollOffset();
}
}
/*******************************************************************************
* 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.maile.jingcai.commponent;
public interface OnGestureListener {
void onDrag(float dx, float dy);
void onFling(float startX, float startY, float velocityX, float velocityY);
void onScale(float scaleFactor, float focusX, float focusY);
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
* <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.maile.jingcai.commponent;
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;
import android.widget.ImageView;
public class PhotoView extends ImageView implements IPhotoView {
private final 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);
mAttacher = new PhotoViewAttacher(this);
if (null != mPendingScaleType) {
setScaleType(mPendingScaleType);
mPendingScaleType = null;
}
}
/**
* @deprecated use {@link #setRotationTo(float)}
*/
@Override
public void setPhotoViewRotation(float rotationDegree) {
mAttacher.setRotationTo(rotationDegree);
}
@Override
public void setRotationTo(float rotationDegree) {
mAttacher.setRotationTo(rotationDegree);
}
@Override
public void setRotationBy(float rotationDegree) {
mAttacher.setRotationBy(rotationDegree);
}
@Override
public void setRotationBy(float rotationDegree, boolean animate) {
mAttacher.setRotationBy(rotationDegree, animate);
}
@Override
public boolean canZoom() {
return mAttacher.canZoom();
}
@Override
public RectF getDisplayRect() {
return mAttacher.getDisplayRect();
}
@Override
public Matrix getDisplayMatrix() {
return mAttacher.getDrawMatrix();
}
@Override
public boolean setDisplayMatrix(Matrix finalRectangle) {
return mAttacher.setDisplayMatrix(finalRectangle);
}
@Override
@Deprecated
public float getMinScale() {
return getMinimumScale();
}
@Override
public float getMinimumScale() {
return mAttacher.getMinimumScale();
}
@Override
@Deprecated
public float getMidScale() {
return getMediumScale();
}
@Override
public float getMediumScale() {
return mAttacher.getMediumScale();
}
@Override
@Deprecated
public float getMaxScale() {
return getMaximumScale();
}
@Override
public float getMaximumScale() {
return mAttacher.getMaximumScale();
}
@Override
public float getScale() {
return mAttacher.getScale();
}
@Override
public ScaleType getScaleType() {
return mAttacher.getScaleType();
}
@Override
public void setAllowParentInterceptOnEdge(boolean allow) {
mAttacher.setAllowParentInterceptOnEdge(allow);
}
@Override
@Deprecated
public void setMinScale(float minScale) {
setMinimumScale(minScale);
}
@Override
public void setMinimumScale(float minimumScale) {
mAttacher.setMinimumScale(minimumScale);
}
@Override
@Deprecated
public void setMidScale(float midScale) {
setMediumScale(midScale);
}
@Override
public void setMediumScale(float mediumScale) {
mAttacher.setMediumScale(mediumScale);
}
@Override
@Deprecated
public void setMaxScale(float maxScale) {
setMaximumScale(maxScale);
}
@Override
public void setMaximumScale(float maximumScale) {
mAttacher.setMaximumScale(maximumScale);
}
@Override
// setImageBitmap calls through to this method
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
postUpdate();
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
postUpdate();
}
@Override
public void setImageURI(Uri uri) {
super.setImageURI(uri);
postUpdate();
}
private void postUpdate() {
post(new Runnable() { // need time to layout
@Override
public void run() {
if (null != mAttacher) {
mAttacher.update();
}
}
});
}
@Override
public float setMinimumScaleToFit(Drawable drawable) {
return mAttacher.setMinimumScaleToFit(drawable);
}
@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 PhotoViewAttacher.OnPhotoTapListener getOnPhotoTapListener() {
return mAttacher.getOnPhotoTapListener();
}
@Override
public void setOnViewTapListener(PhotoViewAttacher.OnViewTapListener listener) {
mAttacher.setOnViewTapListener(listener);
}
@Override
public PhotoViewAttacher.OnViewTapListener getOnViewTapListener() {
return mAttacher.getOnViewTapListener();
}
@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 Bitmap getCroppedImage() {
return mAttacher.getCroppedImage();
}
@Override
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
mAttacher.setOnDoubleTapListener(newOnDoubleTapListener);
}
@Override
public void update() {
mAttacher.update();
}
@Override
public void reset() {
mAttacher.reset();
}
@Override
protected void onDetachedFromWindow() {
mAttacher.cleanup();
super.onDetachedFromWindow();
}
@Override
public void setImageBoundsListener(IGetImageBounds listener) {
mAttacher.setImageBoundsListener(listener);
}
}
\ No newline at end of file
/*******************************************************************************
* 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.maile.jingcai.commponent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
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 com.maile.jingcai.util.ImageViewUtil;
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);
static final Interpolator sInterpolator = 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;
private float mMinScale = DEFAULT_MIN_SCALE;
private float mMidScale = DEFAULT_MID_SCALE;
private float mMaxScale = DEFAULT_MAX_SCALE;
private boolean mAllowParentInterceptOnEdge = true;
private static void checkZoomLevels(float minZoom, float midZoom, float maxZoom) {
//TODO : Commenting this check for now. Loading image with different dimension causes this exception
// if (minZoom >= midZoom) {
// throw new IllegalArgumentException(
// "MinZoom has to be less than MidZoom");
// } else if (midZoom >= maxZoom) {
// throw new IllegalArgumentException(
// "MidZoom has to be less than MaxZoom");
// }
}
/**
* @return true if the ImageView exists, and it's Drawable existss
*/
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;
}
}
/**
* Set's 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.maile.jingcai.commponent.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 int mIvTop, mIvRight, mIvBottom, mIvLeft;
private FlingRunnable mCurrentFlingRunnable;
private int mScrollEdge = EDGE_BOTH;
private boolean mZoomEnabled;
private ScaleType mScaleType = ScaleType.FIT_CENTER;
private float mRotation;
public PhotoViewAttacher(ImageView imageView) {
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 != mLongClickListener) {
mLongClickListener.onLongClick(getImageView());
}
}
});
mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
// Finally, update the UI so that we're zoomable
setZoomable(true);
}
@Override
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener newOnDoubleTapListener) {
if (newOnDoubleTapListener != null)
mGestureDetector.setOnDoubleTapListener(newOnDoubleTapListener);
else
mGestureDetector.setOnDoubleTapListener(new DefaultOnDoubleTapListener(this));
}
@Override
public boolean canZoom() {
return mZoomEnabled;
}
/**
* Clean-up the resources attached to this object. This needs to be called when the ImageView
* is no longer used. A good example is from {@link View#onDetachedFromWindow()}
* or from {@link android.app.Activity#onDestroy()}.
*/
@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;
}
/**
* @deprecated use {@link #setRotationTo(float)}
*/
@Override
public void setPhotoViewRotation(float degrees) {
setRotationTo(degrees);
}
@Override
public void setRotationTo(float degrees) {
Rect imageBounds = getImageBounds();
mSuppMatrix.setRotate(degrees % 360, imageBounds.centerX(), imageBounds.centerY());
checkAndDisplayMatrix();
}
@Override
public void setRotationBy(float rotationDegree) {
setRotationBy(rotationDegree, false);
}
@Override
public void setRotationBy(float degrees, boolean animate) {
ImageView imageView = getImageView();
if (imageView == null) {
return;
}
final Rect imageBounds = getImageBounds();
final int centerX = imageBounds.centerX();
final int centerY = imageBounds.centerY();
final float oldRotation = mRotation;
// final float degreesNorm = degrees % 360;
final float degreesNorm = degrees;
if (degreesNorm == 0) { // reset matrix and rotation
mRotation = 0;
} else {
// mRotation = (mRotation + degreesNorm) % 360; //为了产品的需求,我只能把这么完美的功能给屏蔽了
mRotation = degreesNorm % 360;
}
if (animate) {
imageView.post(new AnimatedRotateRunnable(oldRotation, degreesNorm, centerX, centerY));
} else {
mSuppMatrix.postRotate(degreesNorm, centerX, centerY);
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
@Deprecated
public float getMinScale() {
return getMinimumScale();
}
@Override
public float getMinimumScale() {
return mMinScale;
}
@Override
@Deprecated
public float getMidScale() {
return getMediumScale();
}
@Override
public float getMediumScale() {
return mMidScale;
}
@Override
@Deprecated
public float getMaxScale() {
return getMaximumScale();
}
@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()) {
if (mScrollEdge == EDGE_BOTH
|| (mScrollEdge == EDGE_LEFT && dx >= 1f)
|| (mScrollEdge == EDGE_RIGHT && dx <= -1f)) {
if (null != parent)
parent.requestDisallowInterceptTouchEvent(false);
}
} else {
if (null != parent) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
@Override
public void onFling(float startX, float startY, float velocityX, float velocityY) {
if (DEBUG) {
Log.d(LOG_TAG, "onFling. sX: " + startX + " sY: " + startY + " Vx: " + velocityX + " Vy: " + velocityY);
}
ImageView imageView = getImageView();
mCurrentFlingRunnable = new FlingRunnable(imageView.getContext());
mCurrentFlingRunnable.fling(getImageViewWidth(imageView), getImageViewHeight(imageView), (int) velocityX, (int) velocityY);
imageView.post(mCurrentFlingRunnable);
}
@Override
public void onGlobalLayout() {
ImageView imageView = getImageView();
if (null != imageView) {
if (mZoomEnabled) {
final int top = imageView.getTop();
final int right = imageView.getRight();
final int bottom = imageView.getBottom();
final int left = imageView.getLeft();
/**
* We need to check whether the ImageView's bounds have changed.
* This would be easier if we targeted API 11+ as we could just use
* View.OnLayoutChangeListener. Instead we have to replicate the
* work, keeping track of the ImageView's bounds and then checking
* if the values change.
*/
if (top != mIvTop || bottom != mIvBottom || left != mIvLeft
|| right != mIvRight) {
// Update our base matrix, as the bounds have changed
updateBaseMatrix(imageView.getDrawable());
// Update values as something has changed
mIvTop = top;
mIvRight = right;
mIvBottom = bottom;
mIvLeft = left;
}
} else {
updateBaseMatrix(imageView.getDrawable());
}
}
}
@Override
public void onScale(float scaleFactor, float focusX, float focusY) {
if (DEBUG) {
Log.d(LOG_TAG, String.format("onScale: scale: %.2f. fX: %.2f. fY: %.2f", scaleFactor, focusX, focusY));
}
if (getScale() < mMaxScale || scaleFactor < 1f) {
mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
checkAndDisplayMatrix();
}
}
@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;
}
}
break;
}
// Try the Scale/Drag detector
if (null != mScaleDragDetector && mScaleDragDetector.onTouchEvent(ev)) {
handled = true;
}
// Check to see if the user sencond_min tapped
if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
handled = true;
}
}
return handled;
}
@Override
public void setAllowParentInterceptOnEdge(boolean allow) {
mAllowParentInterceptOnEdge = allow;
}
@Override
@Deprecated
public void setMinScale(float minScale) {
setMinimumScale(minScale);
}
@Override
public void setMinimumScale(float minimumScale) {
checkZoomLevels(minimumScale, mMidScale, mMaxScale);
mMinScale = minimumScale;
}
@Override
public float setMinimumScaleToFit(Drawable drawable) {
float minScale = 1f;
int h = drawable.getIntrinsicHeight();
int w = drawable.getIntrinsicWidth();
final float cropWindowWidth = Edge.getWidth();
final float cropWindowHeight = Edge.getHeight();
if (h <= w) {
//Set the image view height to
//HACK : Have to add 1f.
minScale = (cropWindowHeight + 1f) / h;
} else if (w < h) {
//HACK : Have to add 1f.
minScale = (cropWindowWidth + 1f) / w;
}
setMinimumScale(minScale);
return minScale;
}
@Override
@Deprecated
public void setMidScale(float midScale) {
setMediumScale(midScale);
}
@Override
public void setMediumScale(float mediumScale) {
checkZoomLevels(mMinScale, mediumScale, mMaxScale);
mMidScale = mediumScale;
}
@Override
@Deprecated
public void setMaxScale(float maxScale) {
setMaximumScale(maxScale);
}
@Override
public void setMaximumScale(float maximumScale) {
checkZoomLevels(mMinScale, mMidScale, maximumScale);
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;
}
@Override
public OnPhotoTapListener getOnPhotoTapListener() {
return mPhotoTapListener;
}
@Override
public void setOnViewTapListener(OnViewTapListener listener) {
mViewTapListener = listener;
}
@Override
public 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();
}
}
}
@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();
}
@Override
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();
}
setScale(getMinimumScale());
}
}
@Override
public void reset() {
update();
}
@Override
public Matrix getDisplayMatrix() {
return new Matrix(getDrawMatrix());
}
public Matrix getDrawMatrix() {
mDrawMatrix.set(mBaseMatrix);
mDrawMatrix.postConcat(mSuppMatrix);
return mDrawMatrix;
}
private void cancelFling() {
if (null != mCurrentFlingRunnable) {
mCurrentFlingRunnable.cancelFling();
mCurrentFlingRunnable = null;
}
}
/**
* 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");
}
}
}
IGetImageBounds mBoundsListener;
@Override
public void setImageBoundsListener(IGetImageBounds listener) {
mBoundsListener = listener;
}
public Rect getImageBounds() {
if (getImageView() == null) {
return new Rect();
} else if (mBoundsListener != null) {
return mBoundsListener.getImageBounds();
} else {
return new Rect(getImageViewWidth(getImageView()), 0, 0, getImageViewHeight(getImageView()));
}
// int cropHeight = 500;
// int cropWidth = 500;
// DisplayMetrics displayMetrics = getImageView().getContext().getResources().getDisplayMetrics();
// int h = displayMetrics.heightPixels;
// int w = displayMetrics.widthPixels;
// int edgeT = Math.round(h/2) - Math.round(cropHeight/2);
// int edgeB = Math.round(h/2) + Math.round(cropHeight/2);
// int edgeL = Math.round(w/2) - Math.round(cropWidth/2);
// int edgeR = Math.round(w/2) + Math.round(cropWidth/2);
// return new Rect(edgeL, edgeT, edgeR, edgeB);
}
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;
Rect overlayImageBounds = getImageBounds();
final int overlayViewHeight = overlayImageBounds.height();
final int viewHeight = getImageViewHeight(imageView);
if (height <= overlayViewHeight) {
switch (mScaleType) {
case FIT_START:
deltaY = -rect.top;
break;
case FIT_END:
deltaY = overlayViewHeight - height - rect.top;
break;
default:
// TODO : Need to fix this ..Need to do something to be more accurate...
deltaY = 0;//(overlayViewHeight - height) / 2 ;//- rect.top;
break;
}
} else if (rect.top > overlayImageBounds.top) {
deltaY = -(rect.top - overlayImageBounds.top);
} else if (rect.bottom < overlayImageBounds.bottom) {
//TODO: Need to do something to be accurate...
deltaY = (overlayImageBounds.bottom - rect.bottom);
}
final int overlayViewWidth = overlayImageBounds.width();
if (width <= overlayViewWidth) {
switch (mScaleType) {
case FIT_START:
deltaX = -rect.left;
break;
case FIT_END:
deltaX = overlayViewWidth - width - rect.left;
break;
default:
deltaX = (overlayViewWidth - width) / 2 - rect.left;
break;
}
mScrollEdge = EDGE_BOTH;
} else if (rect.left > overlayImageBounds.left) {
mScrollEdge = EDGE_LEFT;
deltaX = -(rect.left - overlayImageBounds.left); // -rect.left;
} else if (rect.right < overlayImageBounds.right) {
deltaX = (overlayImageBounds.right - 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();
if (imageView == null) {
return null;
}
Bitmap visibleBitmap = imageView.getDrawingCache();
if (visibleBitmap == null) {
visibleBitmap = Bitmap.createBitmap(imageView.getWidth(), imageView.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(visibleBitmap);
imageView.draw(c);
}
return visibleBitmap;
}
@Override
public void setZoomTransitionDuration(int milliseconds) {
if (milliseconds < 0)
milliseconds = DEFAULT_ZOOM_DURATION;
this.ZOOM_DURATION = milliseconds;
}
@Override
public IPhotoView getIPhotoViewImplementation() {
return this;
}
@Override
public Bitmap getCroppedImage() {
Bitmap visibleBitmap = getVisibleRectangleBitmap();
Rect displayedImageRect = ImageViewUtil.getBitmapRectCenterInside(visibleBitmap, getImageView());
// Get the scale factor between the actual Bitmap dimensions and the
// displayed dimensions for width.
float actualImageWidth = visibleBitmap.getWidth();
float displayedImageWidth = displayedImageRect.width();
float scaleFactorWidth = actualImageWidth / displayedImageWidth;
// Get the scale factor between the actual Bitmap dimensions and the
// displayed dimensions for height.
float actualImageHeight = visibleBitmap.getHeight();
float displayedImageHeight = displayedImageRect.height();
float scaleFactorHeight = actualImageHeight / displayedImageHeight;
// Get crop window position relative to the displayed image.
float cropWindowX = Edge.LEFT.getCoordinate() - displayedImageRect.left;
float cropWindowY = Edge.TOP.getCoordinate() - displayedImageRect.top;
float cropWindowWidth = Edge.getWidth();
float cropWindowHeight = Edge.getHeight();
// Scale the crop window position to the actual size of the Bitmap.
float actualCropX = cropWindowX * scaleFactorWidth;
float actualCropY = cropWindowY * scaleFactorHeight;
float actualCropWidth = cropWindowWidth * scaleFactorWidth;
float actualCropHeight = cropWindowHeight * scaleFactorHeight;
// Crop the subset from the original Bitmap.
return Bitmap.createBitmap(visibleBitmap,
(int) actualCropX, (int) actualCropY, (int) actualCropWidth, (int) actualCropHeight);
}
/**
* 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.
*/
private void resetMatrix() {
mRotation = 0;
mSuppMatrix.reset();
setImageViewMatrix(getDrawMatrix());
checkMatrixBounds();
}
private void setImageViewMatrix(Matrix matrix) {
ImageView imageView = getImageView();
if (null != imageView) {
checkImageViewScaleType();
imageView.setImageMatrix(matrix);
// Call MatrixChangedListener if needed
if (null != mMatrixChangeListener) {
RectF displayRect = getDisplayRect(matrix);
if (null != displayRect) {
mMatrixChangeListener.onMatrixChanged(displayRect);
}
}
}
}
/**
* Calculate Matrix for FIT_CENTER
*
* @param d - Drawable being displayed
*/
private void updateBaseMatrix(Drawable d) {
ImageView imageView = getImageView();
if (null == imageView || null == d) {
return;
}
final float viewWidth = getImageViewWidth(imageView);
final float viewHeight = getImageViewHeight(imageView);
final int drawableWidth = d.getIntrinsicWidth();
final int drawableHeight = d.getIntrinsicHeight();
mBaseMatrix.reset();
final float widthScale = viewWidth / drawableWidth;
final float heightScale = viewHeight / drawableHeight;
if (mScaleType == ScaleType.CENTER) {
mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F,
(viewHeight - drawableHeight) / 2F);
} else if (mScaleType == ScaleType.CENTER_CROP) {
float scale = Math.max(widthScale, heightScale);
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else if (mScaleType == ScaleType.CENTER_INSIDE) {
float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
mBaseMatrix.postScale(scale, scale);
mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
(viewHeight - drawableHeight * scale) / 2F);
} else {
RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
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 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);
}
/**
* 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);
}
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();
mSuppMatrix.postScale(deltaScale, deltaScale, mFocalX, mFocalY);
checkAndDisplayMatrix();
// We haven't hit our target scale yet, so post ourselves again
if (t < 1f) {
Compat.postOnAnimation(imageView, this);
}
}
private float interpolate() {
float t = 1f * (System.currentTimeMillis() - mStartTime) / ZOOM_DURATION;
t = Math.min(1f, t);
t = sInterpolator.getInterpolation(t);
return t;
}
}
private class AnimatedRotateRunnable implements Runnable {
private final float mFocalX, mFocalY;
private final long mStartTime;
private final float mRotationStart, mRotationEnd;
private float mRotationProgress;
public AnimatedRotateRunnable(final float currentRotation, final float targetRotation,
final float focalX, final float focalY) {
mStartTime = System.currentTimeMillis();
mRotationStart = currentRotation;
mRotationEnd = targetRotation;
mFocalX = focalX;
mFocalY = focalY;
}
@Override
public void run() {
ImageView imageView = getImageView();
if (imageView == null) {
return;
}
final float t = interpolate();
final float totalRotation = (mRotationEnd - mRotationStart) * t;
final float rotationDelta = totalRotation - mRotationProgress;
mRotationProgress = totalRotation;
mSuppMatrix.postRotate(rotationDelta, mFocalX, mFocalY);
checkAndDisplayMatrix();
// We haven't hit our target scale yet, so post ourselves again
if (t < 1f) {
Compat.postOnAnimation(imageView, this);
}
}
private float interpolate() {
float t = 1f * (System.currentTimeMillis() - mStartTime) / DEFAULT_ROTATE_DURATION;
t = Math.min(1f, t);
t = sInterpolator.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 (false && viewWidth < rect.width()) {
minX = 0;
maxX = Math.round(rect.width() - viewWidth);
} else {
minX = maxX = startX;
}
final int startY = Math.round(-rect.top);
if (false && 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);
}
}
}
}
\ No newline at end of file
package com.maile.jingcai.commponent;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.maile.jingcai.R;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
/**
* Created by chenjingmian on 16/4/21.
*/
public class PicModeSelectView extends RelativeLayout {
private final int DURATION_ANIM = 200;
@InjectView(R.id.cover_layer)
View mCoverLayer;
@InjectView(R.id.btn_layout)
LinearLayout mBtnLayout;
private long mResultId;
private String mPath;
private AlphaAnimation mAlphaInAnim;
private AlphaAnimation mAlphaOutAnim;
private TranslateAnimation mTranInAnim;
private TranslateAnimation mTranOutAnim;
private ClickCallback mCameraBtnCallback;
private ClickCallback mGalleryBtnCallback;
public PicModeSelectView(Context context) {
super(context);
init(context);
}
public PicModeSelectView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PicModeSelectView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.pic_mode_select_view, this);
ButterKnife.inject(this, view);
mAlphaInAnim = new AlphaAnimation(0, 1);
mAlphaInAnim.setDuration(DURATION_ANIM);
mAlphaInAnim.setFillAfter(true);
mAlphaOutAnim = new AlphaAnimation(1, 0);
mAlphaOutAnim.setDuration(DURATION_ANIM);
mAlphaOutAnim.setFillAfter(true);
mAlphaOutAnim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
setVisibility(INVISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mTranInAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0);
mTranInAnim.setDuration(DURATION_ANIM);
mTranInAnim.setFillAfter(true);
mTranOutAnim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1);
mTranOutAnim.setDuration(DURATION_ANIM);
mTranOutAnim.setFillAfter(true);
}
public void setClickCallback(ClickCallback cameraCallback, ClickCallback galleryCallback) {
this.mCameraBtnCallback = cameraCallback;
this.mGalleryBtnCallback = galleryCallback;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
ButterKnife.reset(this);
mAlphaInAnim = null;
mAlphaOutAnim = null;
mTranInAnim = null;
mTranOutAnim = null;
}
public void show(long resultId, String path) {
show(true);
mResultId = resultId;
mPath = path;
}
public void show(boolean isVisible) {
if (isVisible) {
setVisibility(VISIBLE);
}
showCoverLayer(isVisible);
showBtnLayout(isVisible);
}
private void showCoverLayer(boolean isVisible) {
if (isVisible) {
mCoverLayer.startAnimation(mAlphaInAnim);
} else {
mCoverLayer.startAnimation(mAlphaOutAnim);
}
}
private void showBtnLayout(boolean isVisible) {
if (isVisible) {
mBtnLayout.startAnimation(mTranInAnim);
} else {
mBtnLayout.startAnimation(mTranOutAnim);
}
}
@OnClick(R.id.camera)
void OnCameraCLick() {
if (mCameraBtnCallback != null) {
mCameraBtnCallback.onClick();
} else {
// ImageCropActivity.newInstance(getContext(), ImageCropActivity.ACTION_PICK_PHOTO,
// mResultId, mPath, -1);
}
setVisibility(INVISIBLE);
}
//add by tangwen
//拉起相册:图片库
@OnClick(R.id.gallery)
void OnGalleryCLick() {
if (mGalleryBtnCallback != null) {
mGalleryBtnCallback.onClick();
} else {
// ImageCropActivity.newInstance(getContext(), ImageCropActivity.ACTION_PICK_PHOTO,
// mResultId, mPath, -1);
}
setVisibility(INVISIBLE);
}
@OnClick(R.id.cover_layer)
void OnCoverCLick() {
show(false);
}
@OnClick(R.id.cancel)
void OnCancelCLick() {
show(false);
}
public boolean onBackPressed() {
if (getVisibility() == VISIBLE) {
show(false);
return true;
} else {
return false;
}
}
public interface ClickCallback {
void onClick();
}
}
/*******************************************************************************
* 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.maile.jingcai.commponent;
import android.content.Context;
import android.widget.Scroller;
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);
}
public boolean isFinished() {
return mScroller.isFinished();
}
@Override
public int getCurrX() {
return mScroller.getCurrX();
}
@Override
public int getCurrY() {
return mScroller.getCurrY();
}
}
\ No newline at end of file
/*******************************************************************************
* Copyright 2011, 2012 Chris Banes.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.maile.jingcai.commponent;
import android.content.Context;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
public abstract class ScrollerProxy {
public static ScrollerProxy getScroller(Context context) {
if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
return new PreGingerScroller(context);
} else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
return new GingerScroller(context);
} else {
return new IcsScroller(context);
}
}
public abstract boolean computeScrollOffset();
public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY,
int maxY, int overX, int overY);
public abstract void forceFinished(boolean finished);
public abstract boolean isFinished();
public abstract int getCurrX();
public abstract int getCurrY();
}
package com.maile.jingcai.commponent;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.maile.jingcai.R;
import com.maile.jingcai.util.DrawUtil;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* Created by chenjingmian on 16/5/9.
*/
public class ToastTopBar extends LinearLayout {
private final int HANDLER_MAG_HIDE_ERRORBAR = 1;
private final int DURATION_ANIM = 300;
@InjectView(R.id.toast_img)
ImageView mToastImg;
@InjectView(R.id.toast_tv)
TextView mToastText;
private ValueAnimator mErrorAnim;
private int mErrorHideTop;
private int mErrorCurrentTop;
private boolean mErrorVisible;
public ToastTopBar(Context context) {
super(context);
init(context);
}
public ToastTopBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ToastTopBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
View view = LayoutInflater.from(context).inflate(R.layout.toast_top_bar, this);
ButterKnife.inject(view, this);
mErrorHideTop = -DrawUtil.dip2px(60);
mErrorCurrentTop = mErrorHideTop;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
ButterKnife.reset(this);
}
public void clear() {
myHandler.removeMessages(HANDLER_MAG_HIDE_ERRORBAR);
myHandler = null;
mErrorAnim = null;
}
public void showErrorBar(String error) {
mToastText.setText(error);
startErrorAnim(true);
}
public void showErrorBar(int error, boolean isShowImage) {
if (!isShowImage) {
mToastImg.setVisibility(View.GONE);
}
mToastText.setText(error);
startErrorAnim(true);
}
public void showErrorBar(int error) {
mToastText.setText(error);
startErrorAnim(true);
}
private void startErrorAnim(boolean isVisible) {
mErrorVisible = isVisible;
int start = mErrorCurrentTop;
int end = isVisible ? 0 : mErrorHideTop;
myHandler.removeMessages(HANDLER_MAG_HIDE_ERRORBAR);
if (start == end) {
if (isVisible) {
Message message = myHandler.obtainMessage(HANDLER_MAG_HIDE_ERRORBAR);
myHandler.sendMessageDelayed(message, 1000);
}
return;
}
if (mErrorAnim == null) {
mErrorAnim = ValueAnimator.ofInt(start, end);
mErrorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mErrorCurrentTop = (int) animation.getAnimatedValue();
((RelativeLayout.LayoutParams) getLayoutParams()).topMargin = mErrorCurrentTop;
getParent().requestLayout();
}
});
mErrorAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mErrorCurrentTop = mErrorVisible ? 0 : mErrorHideTop;
((RelativeLayout.LayoutParams) getLayoutParams()).topMargin = mErrorCurrentTop;
getParent().requestLayout();
if (mErrorVisible) {
Message message = myHandler.obtainMessage(HANDLER_MAG_HIDE_ERRORBAR);
myHandler.sendMessageDelayed(message, 1000);
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
} else {
mErrorAnim.setIntValues(start, end);
}
mErrorAnim.setDuration((long) (Math.abs((end - start) * 1.0f / mErrorHideTop) * DURATION_ANIM));
mErrorAnim.start();
}
Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLER_MAG_HIDE_ERRORBAR:
startErrorAnim(false);
break;
}
super.handleMessage(msg);
}
};
}
package com.maile.jingcai.commponent;
/*******************************************************************************
* 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;
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
......@@ -28,10 +28,7 @@ public class RspCheckInterceptor implements Interceptor {
Log.i("tangwen", Constant.BASE_URL + "[/]: " + jsonObject.toString());
int status = jsonObject.getInt("code");//status
if (status != 0 && status != 200){ //请求失败
String msg = jsonObject.getString("msg");
if(status == 500 || status == 404){
msg = "服务器异常";
}
String msg = codeResponse(status);
throw new IOException(msg);
}
} catch (JSONException e) {
......@@ -47,17 +44,31 @@ public class RspCheckInterceptor implements Interceptor {
}
public void codeResponse(int code){
public String codeResponse(int code){
switch (code){
case 1005: // 自动登录验证错误
break;
case 403:
case 404:
return "服务端异常(资源未找到)";
case 500:
return "服务端异常";
case 1002:
break;
case 998: // 自动登录已过期
break;
case 1023: // 错误的uid
break;
return "短信验证码验证失败";
case 997:
return "参数缺失";
case 1003:
return "手机号格式错误";
case 1009:
return "您已退出,请重新登陆";
case 1020:
return "证码超时";
case 1024:
return "错误的TOKEN";
case 1023:
return "错误的用户id";
case 10410:
return "请先登录";
}
return "";
}
}
package com.maile.jingcai.util;
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Base64;
import com.maile.jingcai.base.Constant;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Created by Administrator on 2015/10/19.
*/
public class CameraUtil {
private static char[] base64EncodeChars = new char[]{'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
public static final int TAKE_A_PICTURE = 10;
public static final int SELECT_A_PICTURE = 20;
public static final int SET_PICTURE = 30;
public static final int SELECT_A_PICTURE_AFTER_KIKAT = 40;
public static final int SET_ALBUM_PICTURE_KITKAT = 50;
public static final String TMP_IMAGE_FILE_NAME = "tmp_user_header.jpeg";
public static final String TEMP_PHOTO_FILE_NAME = "temp_photo.jpg";//缓存图片名
/**
* 裁剪图片方法实现 拍照
*
* @param uri
*/
public static Intent cameraCropImageUri(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/jpeg");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 640);
intent.putExtra("outputY", 640);
intent.putExtra("scale", true);
// if (mIsKitKat) {
// intent.putExtra("return-data", true);
// intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
// } else {
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
// }
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true);
return intent;
}
public static Intent selectImageUriAfterKikat() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
return intent;
}
/**
* 裁剪图片方法实现 相册选(禁止掉GIF)
*/
public static Intent cropImageUri() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 640);
intent.putExtra("outputY", 640);
intent.putExtra("scale", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(Constant.ACCOUNT_DIR, TMP_IMAGE_FILE_NAME)));
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
return intent;
}
/**
* <br>功能简述: 4.4改动版裁剪图片方法实现 相册
* <br>功能详细描述:
* <br>注意:
*
* @param uri
*/
public static Intent cropImageUriAfterKikat(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/jpeg");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 640);
intent.putExtra("outputY", 640);
intent.putExtra("scale", true);
// intent.putExtra("return-data", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(Constant.ACCOUNT_DIR, TMP_IMAGE_FILE_NAME)));
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true);
return intent;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection,
selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri
.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri
.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri
.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri,
String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static byte[] bitmap2byte(Bitmap bitmap) {
if (bitmap != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
return baos.toByteArray();
} else {
return null;
}
}
public static String imgToBase64(String imgPath, Bitmap bitmap) {
if (imgPath != null && imgPath.length() > 0) {
bitmap = readBitmap(imgPath);
}
if (bitmap == null) {
//bitmap not found!!
}
ByteArrayOutputStream out = null;
try {
out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
byte[] imgBytes = out.toByteArray();
return Base64.encodeToString(imgBytes, Base64.DEFAULT);
} catch (Exception e) {
// TODO Auto-generated catch block
return null;
} finally {
try {
out.flush();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static Bitmap readBitmap(String imgPath) {
try {
return BitmapFactory.decodeFile(imgPath);
} catch (Exception e) {
return null;
}
}
public static Bitmap decodeUriAsBitmap(Uri uri, Context context) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
return bitmap;
}
public static String EncodeByteToString(byte[] data) {
StringBuffer sb = new StringBuffer();
int len = data.length;
int i = 0;
int b1, b2, b3;
while (i < len) {
b1 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
sb.append("==");
break;
}
b2 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4)
| ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
sb.append("=");
break;
}
b3 = data[i++] & 0xff;
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4)
| ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[((b2 & 0x0f) << 2)
| ((b3 & 0xc0) >>> 6)]);
sb.append(base64EncodeChars[b3 & 0x3f]);
}
return sb.toString();
}
}
package com.maile.jingcai.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import com.maile.jingcai.base.Constant;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipInputStream;
/**
* @author zoubo
* 文件工具类
*/
public class FileUtil {
private final static String ITEM_SPACE = "#";
/**
* 指定路径文件是否存在
*
* @param filePath
*/
public static boolean isFileExist(String filePath) {
boolean result = false;
try {
File file = new File(filePath);
result = file.exists();
file = null;
} catch (Exception e) {
// TODO: handle exception
}
return result;
}
public static void readInputStream(String filename, InputStream inputStream) {
// 1.建立通道对象
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 2.定义存储空间
byte[] buffer = new byte[1024];
// 3.开始读文件
int len = -1;
try {
if (inputStream != null) {
while ((len = inputStream.read(buffer)) != -1) {
// 将Buffer中的数据写到outputStream对象中
outputStream.write(buffer, 0, len);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 创建文件夹
*/
public static void createNewFile(String path) {
File destDir = new File(path);
if (!destDir.exists()) {
destDir.mkdirs();
}
}
public static void delete(File file) {
if (file.isFile()) {
file.delete();
return;
}
if (file.isDirectory()) {
File[] childFiles = file.listFiles();
if (childFiles == null || childFiles.length == 0) {
file.delete();
return;
}
for (int i = 0; i < childFiles.length; i++) {
delete(childFiles[i]);
}
file.delete();
}
}
/**
* sd卡是否可读写
*/
public static boolean isSDCardAvaiable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
public static boolean saveByteToSDFile(byte[] byteData, String filePathName) {
boolean result = false;
FileOutputStream fileOutputStream = null;
try {
File e = createNewFile(filePathName, false);
fileOutputStream = new FileOutputStream(e);
fileOutputStream.write(byteData);
fileOutputStream.flush();
result = true;
} catch (FileNotFoundException var19) {
var19.printStackTrace();
} catch (SecurityException var20) {
var20.printStackTrace();
} catch (IOException var21) {
var21.printStackTrace();
} catch (Exception var22) {
var22.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException var18) {
var18.printStackTrace();
}
}
}
return result;
}
public static File createNewFile(String path, boolean append) {
File newFile = new File(path);
File e;
if (!append) {
if (newFile.exists()) {
newFile.delete();
} else {
e = new File(path + ".png");
if (e != null && e.exists()) {
e.delete();
}
}
}
if (!newFile.exists()) {
try {
e = newFile.getParentFile();
if (e != null && !e.exists()) {
e.mkdirs();
}
newFile.createNewFile();
} catch (Exception var4) {
var4.printStackTrace();
}
}
return newFile;
}
public static final boolean saveBitmap(Bitmap bmp, String path, Bitmap.CompressFormat format, Context context
) {
Uri uri = ImageUtils.getImageUri(path);
if (uri != null) {
OutputStream outputStream = null;
try {
outputStream = context.getContentResolver().openOutputStream(uri);
if (outputStream != null) {
bmp.compress(format, 100, outputStream);
}
} catch (IOException ex) {
ex.printStackTrace();
return false;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
// do nothing
}
}
}
} else {
return false;
}
return true;
}
public static boolean saveBitmap(Bitmap bitmap, String path) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = false;
opts.inSampleSize = 1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
while (baos.toByteArray().length > 500 * 1024) {
baos.reset();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
quality -= 10;
}
try {
baos.writeTo(new FileOutputStream(path));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
public static final boolean saveBitmap(Bitmap bmp, String bmpName, Bitmap.CompressFormat format) {
if (bmp == null) {
Log.i("BitmapUtility", "save bitmap to file bmp is null");
return false;
} else {
FileOutputStream stream = null;
try {
File e = new File(bmpName);
boolean bCreate;
boolean bOk;
if (e.exists()) {
bCreate = e.delete();
if (!bCreate) {
Log.i("BitmapUtility", "delete src file fail");
return false;
}
} else {
File bCreate1 = e.getParentFile();
if (bCreate1 == null) {
Log.i("BitmapUtility", "get bmpName parent file fail");
return false;
}
if (!bCreate1.exists()) {
bOk = bCreate1.mkdirs();
if (!bOk) {
Log.i("BitmapUtility", "make dir fail");
return false;
}
}
}
bCreate = e.createNewFile();
if (!bCreate) {
Log.i("BitmapUtility", "create file fail");
return false;
}
stream = new FileOutputStream(e);
bOk = bmp.compress(format, 100, stream);
if (bOk) {
return true;
}
Log.i("BitmapUtility", "bitmap compress file fail");
return false;
} catch (Exception var20) {
Log.i("BitmapUtility", var20.toString());
} finally {
if (stream != null) {
try {
stream.close();
} catch (Exception var19) {
Log.i("BitmapUtility", "close stream " + var19.toString());
}
}
}
return false;
}
}
/**
* 根据给定路径参数删除单个文件的方法 私有方法,供内部其它方法调用
*
* @param filePath 要删除的文件路径
* @return 成功返回true, 失败返回false
*/
public static boolean deleteFile(String filePath) {
// 定义返回结果
boolean result = false;
// //判断路径参数是否为空
// if(filePath == null || "".equals(filePath)) {
// //如果路径参数为空
// System.out.println("文件路径不能为空~!");
// } else {
// //如果路径参数不为空
// File file = new File(filePath);
// //判断给定路径下要删除的文件是否存在
// if( !file.exists() ) {
// //如果文件不存在
// System.out.println("指定路径下要删除的文件不存在~!");
// } else {
// //如果文件存在,就调用方法删除
// result = file.delete();
// }
// }
if (filePath != null && !"".equals(filePath.trim())) {
File file = new File(filePath);
if (file.exists()) {
result = file.delete();
}
}
return result;
}
// 获取当前目录下所有的图片文件
public static final ArrayList<String> getImageFileName(String fileAbsolutePath) {
ArrayList<String> photoBitmapUrl = new ArrayList<>();
File file = new File(fileAbsolutePath);
File[] subFile = file.listFiles();
for (int iFileLength = 0; iFileLength < subFile.length; iFileLength++) {
// 判断是否为文件夹
if (!subFile[iFileLength].isDirectory()) {
String filename = subFile[iFileLength].getAbsolutePath();
// 判断是否为MP4结尾
if (filename.trim().toLowerCase().endsWith(".jpg")) {
photoBitmapUrl.add(filename);
}
}
}
return photoBitmapUrl;
}
public static String readFileContent(String fileName) {
String content = ""; //文件内容字符串
//打开文件
File file = new File(fileName);
//如果path是传递过来的参数,可以做一个非目录的判断
if (file.isDirectory()) {
Log.d("zou", " sendError The File doesn't not exist.");
} else {
try {
InputStream instream = new FileInputStream(file);
if (instream != null) {
InputStreamReader inputreader = new InputStreamReader(instream);
BufferedReader buffreader = new BufferedReader(inputreader);
String line;
//分行读取
while ((line = buffreader.readLine()) != null) {
content += line + "\n";
}
instream.close();
}
} catch (FileNotFoundException e) {
Log.d("zou", "sendError The File doesn't not exist.");
} catch (IOException e) {
Log.d("zou", e.getMessage());
}
}
return content;
}
public static String getFileName(String filePath) {
String[] names = filePath.split("/");
if (names != null && names.length > 0) {
return names[names.length - 1];
}
return null;
}
/**
* 解压缩一个zip到指定目录
*
* @param zipFile 要解压的压缩文件
* @param folderPath 解压缩的目标目录
* @throws IOException 当解压缩过程出错时抛出
*/
public static void upZipFile(File zipFile, String folderPath, boolean isDeleteZip) throws ZipException, IOException {
File desDir = new File(folderPath);
if (!desDir.exists()) {
desDir.mkdirs();
}
ZipInputStream zipIn = null;
FileOutputStream fileOut = null;
ZipEntry zipEntry = null;
int readedBytes = 0;
byte[] buf = new byte[2048];
try {
zipIn = new ZipInputStream(new FileInputStream(zipFile));
while ((zipEntry = zipIn.getNextEntry()) != null) {
String entryName = zipEntry.getName();
if (zipEntry.isDirectory()) {
entryName = entryName.substring(0, entryName.length() - 1);
File folder = new File(folderPath + File.separator+ entryName);
folder.mkdirs();
} else {
String fileName=folderPath + File.separator + entryName;
File file = new File(fileName);
file.createNewFile();
fileOut = new FileOutputStream(file);
while ((readedBytes = zipIn.read(buf)) > 0) {
fileOut.write(buf, 0, readedBytes);
}
fileOut.close();
}
zipIn.closeEntry();
}
zipIn.close();
} catch (IOException e) {
e.printStackTrace();
}
// ZipFile zf = new ZipFile(zipFile);
// for (Enumeration<?> entries = zf.entries(); entries.hasMoreElements(); ) {
// ZipEntry entry = ((ZipEntry) entries.nextElement());
// InputStream in = zf.getInputStream(entry);
// String str = folderPath + File.separator + entry.getName();
// str = new String(str.getBytes("8859_1"), "GB2312");
// File desFile = new File(str);
// if (!desFile.exists()) {
// File fileParentDir = desFile.getParentFile();
// if (!fileParentDir.exists()) {
// fileParentDir.mkdirs();
// }
// desFile.createNewFile();
// }
// OutputStream out = new FileOutputStream(desFile);
// byte buffer[] = new byte[1024];
// int realLength;
// while ((realLength = in.read(buffer)) > 0) {
// out.write(buffer, 0, realLength);
// }
// in.close();
// out.close();
// }
if (isDeleteZip) {
zipFile.delete();
}
}
//创建文件夹及文件
public static void CreateText(String fileName) throws IOException {
File file = new File(Constant.ACCOUNT_DIR);
if (!file.exists()) {
try {
//按照指定的路径创建文件夹
file.mkdirs();
} catch (Exception e) {
// TODO: handle exception
}
}
File dir = new File(fileName);
if (!dir.exists()) {
try {
//在指定的文件夹中创建文件
dir.createNewFile();
} catch (Exception e) {
}
}
}
/**
* 读取Txt文件并写入新内容到原来的内容后面
* */
public static void writeFileSdcard(String fileName, String str) {
FileWriter fw = null;
BufferedWriter bw = null;
String datetime = "";
try {
CreateText(fileName);
SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd" + " "
+ "HH:mm:ss");
datetime = tempDate.format(new java.util.Date()).toString();
fw = new FileWriter(fileName, true);//
// 创建FileWriter对象,用来写入字符流
bw = new BufferedWriter(fw); // 将缓冲对文件的输出
String myreadline = datetime + "[]" + str;
bw.write(myreadline + "\n"); // 写入文件
bw.newLine();
bw.flush(); // 刷新该流的缓冲
bw.close();
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
bw.close();
fw.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
}
}
}
}
package com.maile.jingcai.util;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.view.View;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
* 图片工具类
*/
public class ImageUtils {
public static Uri getImageUri(String path) {
return Uri.fromFile(new File(path));
}
private static final int IMAGE_MAX_SIZE = 1024;
public static Bitmap getBitmap(Uri uri, Context context) {
InputStream in = null;
Bitmap returnedBitmap = null;
try {
in = context.getContentResolver().openInputStream(uri);
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
int scale = 1;
if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
scale = (int) Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
in = context.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(in, null, o2);
in.close();
//First check
ExifInterface ei = new ExifInterface(uri.getPath());
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
returnedBitmap = rotateImage(bitmap, 90);
//Free up the memory
bitmap.recycle();
bitmap = null;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
returnedBitmap = rotateImage(bitmap, 180);
//Free up the memory
bitmap.recycle();
bitmap = null;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
returnedBitmap = rotateImage(bitmap, 270);
//Free up the memory
bitmap.recycle();
bitmap = null;
break;
default:
returnedBitmap = bitmap;
}
return returnedBitmap;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 旋转图片
*/
private static Bitmap rotateImage(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}
public static Drawable getGradientDrawable(String startColor, String endColor,
GradientDrawable.Orientation orientation) {
if (Build.VERSION.SDK_INT >= 16) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColors(new int[]{Color.parseColor(startColor),
Color.parseColor(endColor)});
gradientDrawable.setOrientation(orientation);
return gradientDrawable;
} else {
ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor(startColor));
return colorDrawable;
}
}
public static Drawable getRadiusGradientDrawable(String startColor, String endColor,
GradientDrawable.Orientation orientation, float radius) {
if (Build.VERSION.SDK_INT >= 16) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColors(new int[]{Color.parseColor(startColor),
Color.parseColor(endColor)});
gradientDrawable.setOrientation(orientation);
gradientDrawable.setCornerRadius(radius);
return gradientDrawable;
} else {
ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor(startColor));
return colorDrawable;
}
}
public static Drawable getRadiusDrawable(String color, float radius) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.parseColor(color));
gradientDrawable.setCornerRadius(radius);
return gradientDrawable;
}
public static Drawable getRadiusDrawable(int color, float radius) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(color);
gradientDrawable.setCornerRadius(radius);
return gradientDrawable;
}
/**
* 根据原位图生成一个新的位图,并将原位图所占空间释放
*
* @param srcBmp 原位图
* @return 新位图
*/
public static Bitmap copy(Bitmap srcBmp) {
Bitmap destBmp = null;
try {
//创建一个临时文件
File file = new File("/mnt/sdcard/temp/tmp.txt");
file.getParentFile().mkdirs();
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
int width = srcBmp.getWidth();
int height = srcBmp.getHeight();
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, width * height * 4);
//将位图信息写进buffer
srcBmp.copyPixelsToBuffer(map);
//释放原位图占用的空间
// srcBmp.recycle();
//创建一个新的位图
destBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
map.position(0);
//从临时缓冲中拷贝位图信息
destBmp.copyPixelsFromBuffer(map);
channel.close();
randomAccessFile.close();
} catch (Exception ex) {
destBmp = null;
}
return destBmp;
}
public static Bitmap zoomImage(Bitmap bgimage, double newWidth,
double newHeight) {
// 获取这个图片的宽和高
float width = bgimage.getWidth();
float height = bgimage.getHeight();
if (width < newWidth && height < newHeight) {
return bgimage;
}
// 创建操作图片用的matrix对象
Matrix matrix = new Matrix();
// 计算宽高缩放率
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 缩放图片动作
matrix.postScale(scaleWidth, scaleHeight);
Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
(int) height, matrix, true);
return bitmap;
}
public static Bitmap centerSquareScaleBitmap(Bitmap bitmap, int edgeLength) {
if (null == bitmap || edgeLength <= 0) {
return null;
}
Bitmap result = bitmap;
int widthOrg = bitmap.getWidth();
int heightOrg = bitmap.getHeight();
if (widthOrg > edgeLength && heightOrg > edgeLength) {
// //压缩到一个最小长度是edgeLength的bitmap
int longerEdge = (int) (edgeLength * Math.max(widthOrg, heightOrg) / Math.min(widthOrg, heightOrg));
int scaledWidth = widthOrg > heightOrg ? longerEdge : edgeLength;
int scaledHeight = widthOrg > heightOrg ? edgeLength : longerEdge;
Bitmap scaledBitmap;
try {
scaledBitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true);
} catch (Exception e) {
return null;
}
//从图中截取正中间的正方形部分。
int xTopLeft = (scaledWidth - edgeLength) / 3;
int yTopLeft = (scaledHeight - edgeLength) / 3;
try {
result = Bitmap.createBitmap(scaledBitmap, xTopLeft, yTopLeft, edgeLength, edgeLength);
scaledBitmap.recycle();
} catch (Exception e) {
return null;
}
}
return result;
}
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 50, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
// int options = 80;
// while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
// baos.reset();//重置baos即清空baos
// image.compress(Bitmap.CompressFormat.PNG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
// options -= 10;//每次都减少10
// }
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return bitmap;
}
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
int i;
int j;
if (bmp.getHeight() > bmp.getWidth()) {
i = bmp.getWidth();
j = bmp.getWidth();
} else {
i = bmp.getHeight();
j = bmp.getHeight();
}
Bitmap localBitmap = Bitmap.createBitmap(i, j, Bitmap.Config.RGB_565);
Canvas localCanvas = new Canvas(localBitmap);
while (true) {
localCanvas.drawBitmap(bmp, new Rect(0, 0, i, j), new Rect(0, 0, i, j), null);
if (needRecycle)
bmp.recycle();
ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
localBitmap.compress(Bitmap.CompressFormat.JPEG, 100,
localByteArrayOutputStream);
localBitmap.recycle();
byte[] arrayOfByte = localByteArrayOutputStream.toByteArray();
try {
localByteArrayOutputStream.close();
return arrayOfByte;
} catch (Exception e) {
//F.out(e);
}
i = bmp.getHeight();
j = bmp.getHeight();
}
}
//保存到手机
public static void saveToSD(Context context, Bitmap shareBitmap, boolean isShowToast, String filePath) {
try {
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
FileOutputStream fos = new FileOutputStream(file);
boolean b = shareBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
try {
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
if (b) {
if (isShowToast) {
// PublicUtils.showToast(context, "已保存到" + file.getAbsolutePath());
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
//保存图片到系统相册
public static void saveImageToGallery(Context context, Bitmap bmp, boolean isShowToast, String filePath, String fileName) {
// 首先保存图片
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
boolean b = bmp.compress(Bitmap.CompressFormat.JPEG, 80, fos);
try {
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (b) {
if (isShowToast) {
// PublicUtils.showToast(context, "已保存到本地相册,请打开相册查看哦");
}
}
// 其次把文件插入到系统图库
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 最后通知图库更新
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.getAbsolutePath())));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// 原始图片的宽高
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
int heightScale = height / reqHeight;
int witdhScale = width / reqWidth;
inSampleSize = Math.min(heightScale, witdhScale);
}
return inSampleSize;
}
public static Bitmap drawableToBitmap(Bitmap bitmap, Drawable drawable) {
int h = DrawUtil.sHeightPixels - DrawUtil.dip2px(137);
int w = DrawUtil.sWidthPixels - DrawUtil.dip2px(77);
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565;
bitmap = Bitmap.createBitmap(w, h, config);
//注意,下面三行代码要用到,否在在View或者surfaceview里的canvas.drawBitmap会看不到图
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
public static Bitmap loadBitmapFromView(View view) {
int w = view.getWidth();
int h = view.getHeight();
Bitmap screenshot;
screenshot = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
Canvas c = new Canvas(screenshot);
view.draw(c);
return screenshot;
}
/**
* 原图缩小3倍,提高模糊效率
*
* @param view
* @return
*/
public static Bitmap getSrcBitmap(View view) {
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap cacheBitmap = view.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bmp = ImageUtils.zoomImage(cacheBitmap, cacheBitmap.getWidth() / 3,
cacheBitmap.getHeight() / 3);
// 销毁缓存信息
view.setDrawingCacheEnabled(false);
return bmp;
}
public static Bitmap convertViewToBitmap(View view) {
int w = DrawUtil.dip2px(50);
int h = DrawUtil.dip2px(50);
view.layout(0, 0, w, h);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
/**
* @param res
* @param resId
* @param reqWidth
* @param reqHeight
* @return
* @description 从Resources中加载图片
*/
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
try {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 设置成了true,不占用内存,只获取bitmap宽高
BitmapFactory.decodeResource(res, resId, options); // 读取图片长款
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 调用上面定义的方法计算inSampleSize值
// 使用获取到的inSampleSize值再次解析图片
options.inJustDecodeBounds = false;
Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图
Bitmap dst = Bitmap.createScaledBitmap(src, reqWidth, reqHeight, true); // 进一步得到目标大小的缩略图
if (src != dst) { // 如果没有缩放,那么不回收
src.recycle(); // 释放Bitmap的native像素数组
}
return dst;
} catch (Exception exception) {
return null;
}
}
//根据view创造图片
public static Bitmap getViewBitmapTwo(View addViewContent) {
if (addViewContent != null) {
addViewContent.setDrawingCacheEnabled(true);
addViewContent.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
addViewContent.layout(0, 0,
addViewContent.getMeasuredWidth(),
addViewContent.getMeasuredHeight());
addViewContent.buildDrawingCache();
Bitmap cacheBitmap = addViewContent.getDrawingCache();
Bitmap bitmap = null;
if (cacheBitmap != null) {
bitmap = Bitmap.createBitmap(cacheBitmap);
}
addViewContent.setDrawingCacheEnabled(false);
return bitmap;
} else {
return null;
}
}
private static int mImageColor = 0xfff9f1df;
private static int mColorData[] = {0xfff9f1df, 0xffdce8f1, 0xffddece5, 0xfff1e1e0, 0xffe8e2ef};
public static int getImageColor(int position) {
int color = mImageColor;
int choose = position % 5;
if (choose == 0) {
color = mColorData[4];
} else if (choose == 1) {
color = mColorData[0];
} else if (choose == 2) {
color = mColorData[1];
} else if (choose == 3) {
color = mColorData[2];
} else if (choose == 4) {
color = mColorData[3];
}
return color;
}
}
/*
* Copyright 2013, Edmodo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
* You may obtain a copy of the License in the LICENSE file, or 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.maile.jingcai.util;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.view.View;
/**
* Utility class that deals with operations with an ImageView.
*/
public class ImageViewUtil {
/**
* Gets the rectangular position of a Bitmap if it were placed inside a View
* with scale type set to {@link android.widget.ImageView# ScaleType #CENTER_INSIDE}.
*
* @param bitmap the Bitmap
* @param view the parent View of the Bitmap
* @return the rectangular position of the Bitmap
*/
public static Rect getBitmapRectCenterInside(Bitmap bitmap, View view) {
final int bitmapWidth = bitmap.getWidth();
final int bitmapHeight = bitmap.getHeight();
final int viewWidth = view.getWidth();
final int viewHeight = view.getHeight();
return getBitmapRectCenterInsideHelper(bitmapWidth, bitmapHeight, viewWidth, viewHeight);
}
/**
* Gets the rectangular position of a Bitmap if it were placed inside a View
* with scale type set to {@link android.widget.ImageView# ScaleType #CENTER_INSIDE}.
*
* @param bitmapWidth the Bitmap's width
* @param bitmapHeight the Bitmap's height
* @param viewWidth the parent View's width
* @param viewHeight the parent View's height
* @return the rectangular position of the Bitmap
*/
public static Rect getBitmapRectCenterInside(int bitmapWidth,
int bitmapHeight,
int viewWidth,
int viewHeight) {
return getBitmapRectCenterInsideHelper(bitmapWidth, bitmapHeight, viewWidth, viewHeight);
}
/**
* Helper that does the work of the above functions. Gets the rectangular
* position of a Bitmap if it were placed inside a View with scale type set
* to {@link android.widget.ImageView# ScaleType #CENTER_INSIDE}.
*
* @param bitmapWidth the Bitmap's width
* @param bitmapHeight the Bitmap's height
* @param viewWidth the parent View's width
* @param viewHeight the parent View's height
* @return the rectangular position of the Bitmap
*/
private static Rect getBitmapRectCenterInsideHelper(int bitmapWidth,
int bitmapHeight,
int viewWidth,
int viewHeight) {
double resultWidth;
double resultHeight;
int resultX;
int resultY;
double viewToBitmapWidthRatio = Double.POSITIVE_INFINITY;
double viewToBitmapHeightRatio = Double.POSITIVE_INFINITY;
// Checks if either width or height needs to be fixed
if (viewWidth < bitmapWidth) {
viewToBitmapWidthRatio = (double) viewWidth / (double) bitmapWidth;
}
if (viewHeight < bitmapHeight) {
viewToBitmapHeightRatio = (double) viewHeight / (double) bitmapHeight;
}
// If either needs to be fixed, choose smallest ratio and calculate from
// there
if (viewToBitmapWidthRatio != Double.POSITIVE_INFINITY || viewToBitmapHeightRatio != Double.POSITIVE_INFINITY) {
if (viewToBitmapWidthRatio <= viewToBitmapHeightRatio) {
resultWidth = viewWidth;
resultHeight = (bitmapHeight * resultWidth / bitmapWidth);
} else {
resultHeight = viewHeight;
resultWidth = (bitmapWidth * resultHeight / bitmapHeight);
}
}
// Otherwise, the picture is within frame layout bounds. Desired width
// is simply picture size
else {
resultHeight = bitmapHeight;
resultWidth = bitmapWidth;
}
// Calculate the position of the bitmap inside the ImageView.
if (resultWidth == viewWidth) {
resultX = 0;
resultY = (int) Math.round((viewHeight - resultHeight) / 2);
} else if (resultHeight == viewHeight) {
resultX = (int) Math.round((viewWidth - resultWidth) / 2);
resultY = 0;
} else {
resultX = (int) Math.round((viewWidth - resultWidth) / 2);
resultY = (int) Math.round((viewHeight - resultHeight) / 2);
}
final Rect result = new Rect(resultX,
resultY,
resultX + (int) Math.ceil(resultWidth),
resultY + (int) Math.ceil(resultHeight));
return result;
}
}
/*
* Copyright 2013, Edmodo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
* You may obtain a copy of the License in the LICENSE file, or 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.maile.jingcai.util;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.TypedValue;
/**
* Utility class for handling all of the Paint used to draw the CropOverlayView.
*/
public class PaintUtil {
// Private Constants ///////////////////////////////////////////////////////
private static final int DEFAULT_CORNER_COLOR = Color.WHITE;
private static final String SEMI_TRANSPARENT = "#4DFFFFFF";
private static final String DEFAULT_BACKGROUND_COLOR_ID = "#B029303F";//"#B0000000";
private static final float DEFAULT_LINE_THICKNESS_DP = 1;
private static final float DEFAULT_CORNER_THICKNESS_DP = 5;
private static final float DEFAULT_GUIDELINE_THICKNESS_PX = 1;
// Public Methods //////////////////////////////////////////////////////////
/**
* Creates the Paint object for drawing the crop window border.
*
* @param context the Context
* @return new Paint object
*/
public static Paint newBorderPaint(Context context) {
// Set the line thickness for the crop window border.
final float lineThicknessPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LINE_THICKNESS_DP, context.getResources().getDisplayMetrics());
final Paint borderPaint = new Paint();
borderPaint.setAntiAlias(true);
borderPaint.setColor(Color.parseColor(SEMI_TRANSPARENT));
borderPaint.setStrokeWidth(lineThicknessPx);
borderPaint.setStyle(Paint.Style.STROKE);
return borderPaint;
}
/**
* Creates the Paint object for drawing the crop window guidelines.
*
* @return the new Paint object
*/
public static Paint newGuidelinePaint() {
final Paint paint = new Paint();
paint.setColor(Color.parseColor(SEMI_TRANSPARENT));
paint.setStrokeWidth(DEFAULT_GUIDELINE_THICKNESS_PX);
return paint;
}
/**
* Creates the Paint object for drawing the translucent overlay outside the
* crop window.
*
* @param context the Context
* @return the new Paint object
*/
public static Paint newBackgroundPaint(Context context) {
final Paint paint = new Paint();
paint.setColor(Color.parseColor(DEFAULT_BACKGROUND_COLOR_ID));
return paint;
}
/**
* Creates the Paint object for drawing the corners of the border
*
* @param context the Context
* @return the new Paint object
*/
public static Paint newCornerPaint(Context context) {
// Set the line thickness for the crop window border.
final float lineThicknessPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_THICKNESS_DP, context.getResources().getDisplayMetrics());
final Paint cornerPaint = new Paint();
cornerPaint.setColor(DEFAULT_CORNER_COLOR);
cornerPaint.setStrokeWidth(lineThicknessPx);
cornerPaint.setStyle(Paint.Style.STROKE);
return cornerPaint;
}
/**
* Returns the value of the corner thickness
*
* @return Float equivalent to the corner thickness
*/
public static float getCornerThickness() {
return DEFAULT_CORNER_THICKNESS_DP;
}
/**
* Returns the value of the line thickness of the border
*
* @return Float equivalent to the line thickness
*/
public static float getLineThickness() {
return DEFAULT_LINE_THICKNESS_DP;
}
}
package com.maile.jingcai.util;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.maile.jingcai.R;
import com.maile.jingcai.base.BaseApplication;
/**
......@@ -24,4 +29,13 @@ public class PublicUtils {
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
public static final void showToast(Context context, String textDesc) {
Toast.makeText(context, textDesc, Toast.LENGTH_SHORT).show();
}
public static final void showToast(Context context, int text) {
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
}
package com.maile.jingcai.view.activity;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.maile.jingcai.R;
import com.maile.jingcai.base.BaseFragment;
import com.maile.jingcai.base.Constant;
import com.maile.jingcai.commponent.CropOverlayView;
import com.maile.jingcai.commponent.IGetImageBounds;
import com.maile.jingcai.commponent.PhotoView;
import com.maile.jingcai.util.DrawUtil;
import com.maile.jingcai.util.FileUtil;
import com.maile.jingcai.util.ImageUtils;
import com.maile.jingcai.util.PublicUtils;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import me.nereo.multi_image_selector.MultiImageSelector;
/**
* Created by tangwen on 16/11/15.
*/
public class ImageCropHeadActivity extends Activity{
private Context mContext;
private PhotoView mPhotoView;//显示图
private CropOverlayView mCropOverlayView;//截图显示范围
public static final String TEMP_PHOTO_FILE_NAME = "temp_photo.jpg";//缓存图片名
private File mFileTemp;//缓存文件
private String mImagePath;//缓存图片路径
protected static final int REQUEST_STORAGE_READ_ACCESS_PERMISSION = 101;//权限
private ArrayList<String> mSelectPath;//从图片库中取出的图片的uri集合
private static final int REQUEST_IMAGE = 2;//请求码
private Uri mImageUri = null;//图片uri
private Uri mSaveUri = null;//保存uri
private Bitmap mBitmap;
private TextView mSaveBtn;
private String saveStr = "保存";
private final Bitmap.CompressFormat mOutputFormat = Bitmap.CompressFormat.JPEG;
private Bitmap mNewBitmap;
private String sendToEditBitMapStr = "HEAD_IMAGE_BUNDLE";
private static final int IMAGE_HEAD = 3;
private ImageView mBackCloseIv;
private String CLICK_BACK_IMAGE="CLICK_BACK_IMAGE";
private RelativeLayout mMRorateRl;
private float mLastAngle = 0;
int mCountRotate = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_crop);
mContext = this;
initView();
initListener();
createTempFile();
pickImage();
}
/**
* 拾取图片库
*/
private void pickImage() {
boolean showCamera = true;
int maxNum = 9;
MultiImageSelector selector = MultiImageSelector.create(mContext);
selector.showCamera(showCamera);
selector.count(maxNum);
selector.single();
selector.origin(mSelectPath);
//请求图片库,并且在onActivityResult中进行返回
selector.start(ImageCropHeadActivity.this, REQUEST_IMAGE);
}
private void requestPermission(final String permission, String rationale, final int requestCode) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
new AlertDialog.Builder(this)
.setTitle(R.string.mis_permission_dialog_title)
.setMessage(rationale)
.setPositiveButton(R.string.mis_permission_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(ImageCropHeadActivity.this, new String[]{permission}, requestCode);
}
})
.setNegativeButton(R.string.mis_permission_dialog_cancel, null)
.create().show();
} else {
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}
}
private void createTempFile() {
String state = Environment.getExternalStorageState();
//存入sd卡
if (Environment.MEDIA_MOUNTED.equals(state)) {
FileUtil.createNewFile(Constant.ACCOUNT_CROP_DIR);
mFileTemp = new File(Constant.ACCOUNT_CROP_DIR, TEMP_PHOTO_FILE_NAME);
} else {
mFileTemp = new File(getFilesDir(), TEMP_PHOTO_FILE_NAME);
}
//截图后的图片的保存地址--》读出每张图的uri--》设置给photoView
mImagePath = mFileTemp.getPath();
}
/**
* 初始化截图页面的显示
*/
private void initListener() {
//设置图片的截图范围
mPhotoView.setImageBoundsListener(new IGetImageBounds() {
@Override
public Rect getImageBounds() {
try {
return mCropOverlayView.getImageBounds();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
});
}
/**
* 初始化视图
*/
private void initView() {
mPhotoView = (PhotoView) findViewById(R.id.iv_photo);
mCropOverlayView = (CropOverlayView) findViewById(R.id.crop_overlay);
mBackCloseIv = (ImageView) findViewById(R.id.btn_back_close);
mSaveBtn = (TextView) findViewById(R.id.btn_done);
mSaveBtn.setText(saveStr);
mSaveBtn.setClickable(true);
//点击保存,截取图像,使用Intent包装数据,finish本身
mSaveBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveUploadCroppedImage();//保存
}
});
mBackCloseIv.setClickable(true);
mBackCloseIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra(CLICK_BACK_IMAGE, true);
ImageCropHeadActivity.this.setResult(IMAGE_HEAD, intent);//返回数据
finish();
}
});
//点击旋转
mMRorateRl = (RelativeLayout) findViewById(R.id.btn_rotate);
mMRorateRl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLastAngle += 90;
mCountRotate++;
mPhotoView.setRotationBy(mLastAngle, true);
if (mCountRotate == 4) {
mCountRotate = 0;
mLastAngle = 0;
}
}
});
}
/**
* 保存截图,并传递截图 path
*/
private void saveUploadCroppedImage() {
boolean saved = saveOutput();
if (saved) {
//如果保存成功--》使用intent传递数据到EditUserInfoActivity
/* Bundle bundle = new Bundle();
bundle.putParcelable(sendToEditBitMapStr, mNewBitmap);*/
Intent intent = new Intent();
intent.putExtra(sendToEditBitMapStr, mImagePath);
ImageCropHeadActivity.this.setResult(IMAGE_HEAD, intent);
finish();
} else {
PublicUtils.showToast(this, "Unable to save Image into your device.");
finish();
}
}
private boolean saveOutput() {
Bitmap croppedImage = mPhotoView.getCroppedImage();
int width = DrawUtil.sWidthPixels * 2 / 3;
int height = width;
mNewBitmap = ImageUtils.zoomImage(croppedImage, width, height);//返回的截图图片
if (mSaveUri != null) {
OutputStream outputStream = null;
try {
outputStream = mContext.getContentResolver().openOutputStream(mSaveUri);
if (outputStream != null) {
mNewBitmap.compress(mOutputFormat, 90, outputStream);
}
} catch (IOException ex) {
ex.printStackTrace();
return false;
} finally {
closeSilently(outputStream);
}
} else {
Log.e("tangwen", "not defined image url");
return false;
}
croppedImage.recycle();
mNewBitmap.recycle();
return true;
}
public void closeSilently(Closeable c) {
if (c == null) return;
try {
c.close();
} catch (Throwable t) {
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE) {
if (resultCode == RESULT_OK) {
try {
mSelectPath = data.getStringArrayListExtra(MultiImageSelector.EXTRA_RESULT);//集合
InputStream inputStream = getContentResolver().openInputStream(ImageUtils.getImageUri(mSelectPath.get(0)));//输入流
FileOutputStream fileOutputStream = new FileOutputStream(mFileTemp);//输出流
copyStream(inputStream, fileOutputStream);
fileOutputStream.close();
inputStream.close();
mImagePath = mFileTemp.getPath();//sd卡中图片的路径
mImageUri = ImageUtils.getImageUri(mImagePath);//从文件中读出uri
mSaveUri = mImageUri;
showImageCrop();//显示裁剪页面
} catch (Exception e) {
e.printStackTrace();
return;
}
} else {
finish();
}
} else {
finish();
}
}
/**
* 展示图片裁剪
*/
private void showImageCrop() {
mBitmap = ImageUtils.getBitmap(mImageUri, mContext);
if (mBitmap == null) {
PublicUtils.showToast("照片不合法");
finish();
}
Drawable drawable = new BitmapDrawable(getResources(), mBitmap);
float minScale = mPhotoView.setMinimumScaleToFit(drawable);
mPhotoView.setMaximumScale(minScale * 3);
mPhotoView.setMediumScale(minScale * 2);
mPhotoView.setScale(minScale);
mPhotoView.setImageDrawable(drawable);
}
private static void copyStream(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}
}
......@@ -171,9 +171,16 @@ public class LoginActivity extends Activity implements ILoginView {
@Override
public void onNext(WrapperRspEntity<String> userWrapperRspEntity) {
// Log.i("tangwen", "onNext: " + userWrapperRspEntity.getData().toString()); //注意空指针异常
onStartMainActivity();
if(userWrapperRspEntity.getMsg()!=null){
Log.i("tangwen", "onNext: " + userWrapperRspEntity.getData().toString()); //注意空指针异常
PreferencesManager preferencesManager = PreferencesManager.getSharedPreference(getApplication(),
IPreferencesIds.DEFAULT_SHAREPREFERENCES_FILE,
Context.MODE_PRIVATE);
preferencesManager.putString(IPreferencesIds.TOKEN,userWrapperRspEntity.getData());
onStartMainActivity();
}else{
onError(new NullPointerException());
}
}
});
}
......
package com.maile.jingcai.view.activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
......@@ -11,33 +15,58 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.webkit.WebView;
import com.flyco.tablayout.CommonTabLayout;
import com.flyco.tablayout.listener.CustomTabEntity;
import com.flyco.tablayout.listener.OnTabSelectListener;
import com.maile.jingcai.R;
import com.maile.jingcai.base.Constant;
import com.maile.jingcai.commponent.PicModeSelectView;
import com.maile.jingcai.commponent.ToastTopBar;
import com.maile.jingcai.module.entity.TabEntity;
import com.maile.jingcai.util.CameraUtil;
import com.maile.jingcai.util.NetUtils;
import com.maile.jingcai.util.PublicUtils;
import com.maile.jingcai.util.preferences.IPreferencesIds;
import com.maile.jingcai.util.preferences.PreferencesManager;
import com.maile.jingcai.view.ViewFindUtils;
import com.maile.jingcai.view.fragment.SimpleCardFragment;
import com.maile.jingcai.view.iview.IWebView;
import com.umeng.analytics.MobclickAgent;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
/**
* Created by chengfeng-piaopiao on 2017/11/8.
*/
public class MainActivity extends FragmentActivity {
public class MainActivity extends FragmentActivity implements IWebView {
public static final int EDIT_USER_INFO_SUCCESS_CODE = 200; // 修改成功
private static final int SEX_TYPE_MALE = 1;
private static final int SEX_TYPE_FEMALE = 2;
private static final int IMAGE_HEAD = 3;
private static final int UPDATE_SIGN_CODE = 4;
private String USER_NAME = "USER_NAME";
private String USER_PROFILE = "USER_PROFILE";
private String USER_SEX = "USER_SEX";
private String USER_HEAD = "USER_HEAD";
private String mBitmapStr;
private String CLICK_BACK_IMAGE = "CLICK_BACK_IMAGE";
private static final String UPDATE_SIGN = "UPDATE_SIGN";
@InjectView(R.id.pic_mode_select_view)
PicModeSelectView mPicSelectView;
@InjectView(R.id.toast_bar)
ToastTopBar mToastBar;
private Context mContext = this;
private ArrayList<Fragment> mFragments = new ArrayList<>();
......@@ -54,6 +83,9 @@ public class MainActivity extends FragmentActivity {
private ViewPager mViewPager;
private CommonTabLayout mTabLayout_2;
private long exitTime;
private WebView mWebView;
private String mWebURL;
private String[] urls = {"http://h5.test.7peng.cn/","http://192.168.1.250:81/shop","http://h5.test.7peng.cn/profile.html"};
......@@ -78,7 +110,7 @@ public class MainActivity extends FragmentActivity {
Log.i("tangwen", "urls " + urls.toString());
for (int i = 0 ; i < mTitles.length; i ++){
mFragments.add(SimpleCardFragment.getInstance(mTitles[i],urls[i]));
mFragments.add(SimpleCardFragment.getInstance(mTitles[i],urls[i],this));
}
for (int i = 0; i < mTitles.length; i++) {
......@@ -93,29 +125,6 @@ public class MainActivity extends FragmentActivity {
/** with ViewPager */
mTabLayout_2 = ViewFindUtils.find(mDecorView, R.id.tl_2);
tl_2();
// //两位数
// mTabLayout_2.showMsg(0, 55);
// mTabLayout_2.setMsgMargin(0, -5, 5);
//
// //三位数
// mTabLayout_2.showMsg(1, 100);
// mTabLayout_2.setMsgMargin(1, -5, 5);
//
// //设置未读消息红点
// mTabLayout_2.showDot(2);
// MsgView rtv_2_2 = mTabLayout_2.getMsgView(2);
// if (rtv_2_2 != null) {
// UnreadMsgUtils.setSize(rtv_2_2, dp2px(7.5f));
// }
//
// //设置未读消息背景
// mTabLayout_2.showMsg(3, 5);
// mTabLayout_2.setMsgMargin(3, 0, 5);
// MsgView rtv_2_3 = mTabLayout_2.getMsgView(3);
// if (rtv_2_3 != null) {
// rtv_2_3.setBackgroundColor(Color.parseColor("#6D8FB0"));
// }
}
Random mRandom = new Random();
......@@ -155,8 +164,42 @@ public class MainActivity extends FragmentActivity {
});
mViewPager.setCurrentItem(0);
mPicSelectView.setClickCallback(new PicModeSelectView.ClickCallback() {
@Override
public void onClick() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Constant.ACCOUNT_DIR,
CameraUtil.TMP_IMAGE_FILE_NAME)));
startActivityForResult(intent, CameraUtil.TAKE_A_PICTURE);//回调图片,显示头像
}
}, new PicModeSelectView.ClickCallback() {//1:拍照 2:相册
@Override
public void onClick() {//点击"从相册中选择回调到此处!!"--》相对于takePhoto()
//1:拉起multi图片库
Intent intent;
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//19版本
// /*intent = CameraUtil.selectImageUriAfterKikat();
// startActivityForResult(intent, CameraUtil.SELECT_A_PICTURE_AFTER_KIKAT);*/
//
// String savePath = Constant.SHARE_DIR + System.currentTimeMillis() + ".png";
// Intent intentHead = new Intent(MainActivity.this, ImageCropHeadActivity.class);
// startActivityForResult(intentHead, IMAGE_HEAD);
//
// } else {
// intent = CameraUtil.cropImageUri();
// startActivityForResult(intent, CameraUtil.SELECT_A_PICTURE);
// }
}
});
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
......@@ -202,4 +245,107 @@ public class MainActivity extends FragmentActivity {
}
return super.onKeyDown(keyCode, event);
}
private String sendToEditBitMapStr = "HEAD_IMAGE_BUNDLE";
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case IMAGE_HEAD:
//回调设置头像
if (null != data) {
if (data.getBooleanExtra(CLICK_BACK_IMAGE, false) == true) {
mToastBar.showErrorBar(R.string.user_info_upload_head_fail);
return;
}
/* Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.getParcelable(sendToEditBitMapStr);*/
//重新设置头像
/*mHeaderView.setImageBitmap(bitmap);*/
mBitmapStr = data.getStringExtra(sendToEditBitMapStr);
if (null != mBitmapStr) {
/* mImageUri = ImageUtils.getImageUri(mBitmapStr);//从文件中读出uri
mBitmap = ImageUtils.getBitmap(mImageUri, EditUserInfoActivity.this);
mHeaderView.setImageBitmap(mBitmap);*/
// updateHeadImage();
}
}
break;
case CameraUtil.TAKE_A_PICTURE:
if (resultCode == RESULT_OK) {
Intent intent = CameraUtil.cameraCropImageUri(Uri.fromFile(new File(Constant.ACCOUNT_DIR,
CameraUtil.TMP_IMAGE_FILE_NAME)));
startActivityForResult(intent, CameraUtil.SET_PICTURE);
} else {
mToastBar.showErrorBar(R.string.user_info_upload_head_fail);
}
break;
case CameraUtil.SET_PICTURE:
if (resultCode == RESULT_OK && null != data) {
// updateHeadImage();
} else {
mToastBar.showErrorBar(R.string.user_info_upload_head_fail);
}
break;
case CameraUtil.SELECT_A_PICTURE:
if (resultCode == RESULT_OK && null != data) {
// updateHeadImage();
} else if (resultCode == RESULT_CANCELED) {
mToastBar.showErrorBar(R.string.user_info_upload_head_fail);
}
break;
case CameraUtil.SELECT_A_PICTURE_AFTER_KIKAT://相册
if (resultCode == RESULT_OK && null != data) {
String albumPicturePath = CameraUtil.getPath(this, data.getData());
Intent intent = CameraUtil.cropImageUriAfterKikat(Uri.fromFile(new File(albumPicturePath)));
startActivityForResult(intent, CameraUtil.SET_ALBUM_PICTURE_KITKAT);
} else if (resultCode == RESULT_CANCELED) {
mToastBar.showErrorBar(R.string.user_info_upload_head_fail);
}
break;
case CameraUtil.SET_ALBUM_PICTURE_KITKAT: { //相册选择
//updateHeadImage();
}
break;
default:
break;
}
}
@Override
public void editUserImage(WebView webView, String webURL) {
this.mWebView = webView;
this.mWebURL = webURL;
/**
* 直接拉起相册库--》去除dialog
*/
if (!NetUtils.isNetworkOK(this)) { //网络未连接
mToastBar.showErrorBar(R.string.network_not_ok);
} else {
//mPicSelectView.show(true);拉起activity
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//19版本
/*intent = CameraUtil.selectImageUriAfterKikat();
startActivityForResult(intent, CameraUtil.SELECT_A_PICTURE_AFTER_KIKAT);*/
String savePath = Constant.SHARE_DIR + System.currentTimeMillis() + ".png";
Intent intentHead = new Intent(MainActivity.this, ImageCropHeadActivity.class);
startActivityForResult(intentHead, IMAGE_HEAD);
} else {
intent = CameraUtil.cropImageUri();
startActivityForResult(intent, CameraUtil.SELECT_A_PICTURE);
}
}
}
}
......@@ -34,6 +34,7 @@ import com.maile.jingcai.util.preferences.IPreferencesIds;
import com.maile.jingcai.util.preferences.PreferencesManager;
import com.maile.jingcai.view.activity.LoginActivity;
import com.maile.jingcai.view.activity.MainActivity;
import com.maile.jingcai.view.iview.IWebView;
import com.umeng.analytics.MobclickAgent;
import java.lang.reflect.InvocationTargetException;
......@@ -60,12 +61,16 @@ public class SimpleCardFragment extends BaseFragment {
private String mTitle;
private String mUrl;
private IWebView mIWebView;
private String currentURL;
public static SimpleCardFragment getInstance(String title, String mUrl) {
public static SimpleCardFragment getInstance(String title, String mUrl,IWebView mIWebView) {
SimpleCardFragment sf = new SimpleCardFragment();
sf.mTitle = title;
sf.mUrl = mUrl;
sf.mIWebView = mIWebView;
return sf;
}
......@@ -195,6 +200,7 @@ public class SimpleCardFragment extends BaseFragment {
@Override
public void onPageFinished(WebView view, String url) {
currentURL = url;
if (mLoading != null) {
mLoading.setVisibility(View.INVISIBLE);
}
......@@ -206,34 +212,7 @@ public class SimpleCardFragment extends BaseFragment {
Log.i("ggg", "onPageFinished: " + "ggg");
// new Handler().postDelayed(new Runnable() {
// public void run() {
// //mWebView.loadUrl("javascript:console.log('ggg'); (function(){localStorage.setItem(\"__token__\", '"+token+"');})();");
// mWebView.loadUrl("javascript:console.log('type:'+ typeof(window.h5AutoLogin));h5AutoLogin('" + token + "')");
// }
// }, 2000);
// mWebView.loadUrl("javascript:console.log('type:'+ typeof(window.h5AutoLogin));h5AutoLogin('" + token + "')");
//mWebView.loadUrl("javascript:console.log('ggg');h5AutoLogin('"+token+"')");
// RetrofitManager.getInstance().createReq(LoginApiService.class).h5AutoLogin(token).subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(new Observer<WrapperRspEntity<String>>() {
// @Override
// public void onCompleted() {
// }
//
// @Override
// public void onError(Throwable e) {
//
// }
//
// @Override
// public void onNext(WrapperRspEntity<String> userWrapperRspEntity) {
//
// }
// });
}
......@@ -273,12 +252,25 @@ public class SimpleCardFragment extends BaseFragment {
@JavascriptInterface
public void loginMain(){
PreferencesManager preferencesManager = PreferencesManager.getSharedPreference(getActivity(),
IPreferencesIds.DEFAULT_SHAREPREFERENCES_FILE,
Context.MODE_PRIVATE);
preferencesManager.putString(IPreferencesIds.TOKEN,"");
Intent intent = new Intent(mContext, LoginActivity.class);
mContext.startActivity(intent);
if (mContext != null) {
((Activity) mContext).finish();
}
}
/**
* H5更新头像
* @return 是否修改成功
*/
@JavascriptInterface
public void editUserHeadImage(){
mIWebView.editUserImage(mWebView,currentURL);
}
}
@Override
......
package com.maile.jingcai.view.iview;
import android.webkit.WebView;
/**
* Created by chengfeng-piaopiao on 2017/11/22.
*/
public interface IWebView {
/**
* H5修改用户头像
* @param webView 当前页面的webView实例
* @param webURL 当前H5页面的URL
* @return 头像是否修改成功
*/
void editUserImage(WebView webView,String webURL);
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<color android:color="#e9e9e9"/>
</item>
<item android:state_pressed="true">
<color android:color="#e9e9e9"/>
</item>
<item android:state_selected="true">
<color android:color="#e9e9e9"/>
</item>
<item>
<color android:color="#ffffff"/>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#191A1C"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_image_crop_title"
android:layout_width="match_parent"
android:layout_height="60dp">
<ImageView
android:id="@+id/btn_back_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/back_close" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="图片裁剪"
android:textColor="#99FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/btn_done"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center"
android:paddingRight="15dp"
android:text="下一步"
android:textColor="#FFBA42"
android:textSize="15sp"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/rl_image_crop_title"
tools:context=".MainActivity">
<RelativeLayout
android:id="@+id/btn_rotate"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/rotate" />
</RelativeLayout>
<com.maile.jingcai.commponent.PhotoView
android:id="@+id/iv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/btn_rotate"
android:background="#282829"
android:scaleType="center" />
<com.maile.jingcai.commponent.CropOverlayView
android:id="@+id/crop_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/btn_rotate"
app:cornerRadius="0dp"
app:guideLines="true"
app:marginSide="0dp" />
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -36,5 +36,17 @@
tl:tl_underline_color="#DDDDDD"
tl:tl_underline_height="1dp"/>
<com.maile.jingcai.commponent.PicModeSelectView
android:id="@+id/pic_mode_select_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
</com.maile.jingcai.commponent.PicModeSelectView>
<com.maile.jingcai.commponent.ToastTopBar
android:id="@+id/toast_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-60dp"/>
</RelativeLayout>
......@@ -25,5 +25,6 @@
layout="@layout/layout_loading"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<View
android:id="@+id/cover_layer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80000000"/>
<LinearLayout
android:id="@+id/btn_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#f6f6f6"
android:layout_alignParentBottom="true"
>
<TextView
android:id="@+id/camera"
android:layout_width="match_parent"
android:layout_height="56dp"
android:textSize="20sp"
android:textColor="#e548484d"
android:text="@string/dialog_select_btn_camera"
android:background="@drawable/dialog_pic_mode_select_selector"
android:gravity="center"
android:visibility="gone"
/>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#f6f6f6"
></View>
<TextView
android:id="@+id/gallery"
android:layout_width="match_parent"
android:layout_height="56dp"
android:textSize="20sp"
android:textColor="#e548484d"
android:text="@string/dialog_select_btn_gallery"
android:background="@drawable/dialog_pic_mode_select_selector"
android:gravity="center"
/>
<TextView
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="56dp"
android:textSize="20sp"
android:textColor="#9948484d"
android:text="@string/dialog_select_btn_cancel"
android:background="@drawable/dialog_pic_mode_select_selector"
android:gravity="center"
android:layout_marginTop="8dp"
/>
</LinearLayout>
</RelativeLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:background="#99000000"
android:gravity="center">
<ImageView
android:id="@+id/toast_img"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_marginLeft="21dp"
android:layout_marginRight="8dp"
android:src="@drawable/login_error_img"
/>
<TextView
android:id="@+id/toast_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="#ffffff"
android:textSize="20sp"
/>
</LinearLayout>
......@@ -19,4 +19,9 @@
<string name="error_upload_user_info_not_ok">用户信息上传失败</string>
<string name="error_login_error">登录失败</string>
<string name="dialog_select_btn_camera">拍照</string>
<string name="dialog_select_btn_gallery">从相册选择</string>
<string name="dialog_select_btn_cancel">取消</string>
<string name="user_info_upload_head_success">上传头像成功</string>
<string name="user_info_upload_head_fail">取消头像设置</string>
</resources>
......@@ -18,4 +18,101 @@
<item name="android:progressDrawable">@drawable/progressbar_mini</item>
</style>
<!-- Crop overlay view -->
<declare-styleable name="CropOverlayView">
<attr name="guideLines" format="boolean"/>
<attr name="marginTop" format="dimension"/>
<attr name="marginSide" format="dimension"/>
<attr name="minWidth" format="dimension"/>
<attr name="maxWidth" format="dimension"/>
<attr name="cornerRadius" format="dimension"/>
<attr name="overlayColor" format="color"/>
</declare-styleable>
<declare-styleable name="AutoScalingLayout">
<attr name="designWidth" format="dimension"/>
<attr name="designHeight" format="dimension"/>
<attr name="autoScaleEnable" format="boolean"/>
<attr name="autoScaleType" format="string"/>
</declare-styleable>
<declare-styleable name="RoundedImageView">
<attr name="riv_corner_radius" format="dimension"/>
<attr name="riv_corner_radius_top_left" format="dimension"/>
<attr name="riv_corner_radius_top_right" format="dimension"/>
<attr name="riv_corner_radius_bottom_left" format="dimension"/>
<attr name="riv_corner_radius_bottom_right" format="dimension"/>
<attr name="riv_border_width" format="dimension"/>
<attr name="riv_border_color" format="color"/>
<attr name="riv_mutate_background" format="boolean"/>
<attr name="riv_oval" format="boolean"/>
<attr name="android:scaleType"/>
<attr name="riv_tile_mode">
<enum name="clamp" value="0"/>
<enum name="repeat" value="1"/>
<enum name="mirror" value="2"/>
</attr>
<attr name="riv_tile_mode_x">
<enum name="clamp" value="0"/>
<enum name="repeat" value="1"/>
<enum name="mirror" value="2"/>
</attr>
<attr name="riv_tile_mode_y">
<enum name="clamp" value="0"/>
<enum name="repeat" value="1"/>
<enum name="mirror" value="2"/>
</attr>
</declare-styleable>
<declare-styleable name="ViewPagerIndicator">
<!-- Style of the icon indicator's views. -->
<attr name="vpiIconPageIndicatorStyle" format="reference"/>
</declare-styleable>
<declare-styleable name="MagicTextView">
<attr name="innerShadowColor" format="color"/>
<attr name="innerShadowRadius" format="float"/>
<attr name="innerShadowDx" format="float"/>
<attr name="innerShadowDy" format="float"/>
<attr name="outerShadowColor" format="color"/>
<attr name="outerShadowRadius" format="float"/>
<attr name="outerShadowDx" format="float"/>
<attr name="outerShadowDy" format="float"/>
<attr name="typeface" format="string"/>
<attr name="foreground" format="reference|color"/>
<attr name="strokeWidth" format="float"/>
<attr name="strokeMiter" format="float"/>
<attr name="strokeColor" format="color"/>
<attr name="strokeJoinStyle">
<enum name="miter" value="0"/>
<enum name="bevel" value="1"/>
<enum name="round" value="2"/>
</attr>
</declare-styleable>
<declare-styleable name="JazzyViewPager">
<attr name="style">
<enum name="standard" value="0"/>
<enum name="tablet" value="1"/>
<enum name="cubein" value="2"/>
<enum name="cubeout" value="3"/>
<enum name="flipvertical" value="4"/>
<enum name="fliphorizontal" value="5"/>
<enum name="stack" value="6"/>
<enum name="zoomin" value="7"/>
<enum name="zoomout" value="8"/>
<enum name="rotateup" value="9"/>
<enum name="rotatedown" value="10"/>
<enum name="accordion" value="11"/>
</attr>
<attr name="fadeEnabled" format="boolean"/>
<attr name="outlineEnabled" format="boolean"/>
<attr name="outlineColor" format="color|reference"/>
</declare-styleable>
</resources>
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 12
targetSdkVersion 23
versionCode 1
versionName "1.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
resourcePrefix "mis_"
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.0'
compile 'com.squareup.picasso:picasso:2.4.0'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in F:/Nereo/Program/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
package me.nereo.multi_image_selector;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.nereo.multi_image_selector">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:allowBackup="true">
<activity
android:configChanges="orientation|screenSize"
android:name="me.nereo.multi_image_selector.MultiImageSelectorActivity" />
</application>
</manifest>
package me.nereo.multi_image_selector;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import java.util.ArrayList;
/**
* 图片选择器
* Created by nereo on 16/3/17.
*/
public class MultiImageSelector {
public static final String EXTRA_RESULT = MultiImageSelectorActivity.EXTRA_RESULT;
private boolean mShowCamera = true;
private int mMaxCount = 9;
private int mMode = MultiImageSelectorActivity.MODE_MULTI;
private ArrayList<String> mOriginData;
private static MultiImageSelector sSelector;
@Deprecated
private MultiImageSelector(Context context){
}
private MultiImageSelector(){}
@Deprecated
public static MultiImageSelector create(Context context){
if(sSelector == null){
sSelector = new MultiImageSelector(context);
}
return sSelector;
}
public static MultiImageSelector create(){
if(sSelector == null){
sSelector = new MultiImageSelector();
}
return sSelector;
}
public MultiImageSelector showCamera(boolean show){
mShowCamera = show;
return sSelector;
}
public MultiImageSelector count(int count){
mMaxCount = count;
return sSelector;
}
public MultiImageSelector single(){
mMode = MultiImageSelectorActivity.MODE_SINGLE;
return sSelector;
}
public MultiImageSelector multi(){
mMode = MultiImageSelectorActivity.MODE_MULTI;
return sSelector;
}
public MultiImageSelector origin(ArrayList<String> images){
mOriginData = images;
return sSelector;
}
public void start(Activity activity, int requestCode){
final Context context = activity;
if(hasPermission(context)) {
activity.startActivityForResult(createIntent(context), requestCode);
}else{
Toast.makeText(context, R.string.mis_error_no_permission, Toast.LENGTH_SHORT).show();
}
}
public void start(Fragment fragment, int requestCode){
final Context context = fragment.getContext();
if(hasPermission(context)) {
fragment.startActivityForResult(createIntent(context), requestCode);
}else{
Toast.makeText(context, R.string.mis_error_no_permission, Toast.LENGTH_SHORT).show();
}
}
private boolean hasPermission(Context context){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){
// Permission was added in API Level 16
return ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
}
return true;
}
private Intent createIntent(Context context){
Intent intent = new Intent(context, MultiImageSelectorActivity.class);
intent.putExtra(MultiImageSelectorActivity.EXTRA_SHOW_CAMERA, mShowCamera);
intent.putExtra(MultiImageSelectorActivity.EXTRA_SELECT_COUNT, mMaxCount);
if(mOriginData != null){
intent.putStringArrayListExtra(MultiImageSelectorActivity.EXTRA_DEFAULT_SELECTED_LIST, mOriginData);
}
intent.putExtra(MultiImageSelectorActivity.EXTRA_SELECT_MODE, mMode);
return intent;
}
}
package me.nereo.multi_image_selector;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import java.io.File;
import java.util.ArrayList;
/**
* Multi image selector
* Created by Nereo on 2015/4/7.
* Updated by nereo on 2016/1/19.
* Updated by nereo on 2016/5/18.
*/
public class MultiImageSelectorActivity extends AppCompatActivity
implements MultiImageSelectorFragment.Callback {
// Single choice
public static final int MODE_SINGLE = 0;
// Multi choice
public static final int MODE_MULTI = 1;
/**
* Max image size,int,{@link #DEFAULT_IMAGE_SIZE} by default
*/
public static final String EXTRA_SELECT_COUNT = "max_select_count";
/**
* Select mode,{@link #MODE_MULTI} by default
*/
public static final String EXTRA_SELECT_MODE = "select_count_mode";
/**
* Whether show camera,true by default
*/
public static final String EXTRA_SHOW_CAMERA = "show_camera";
/**
* Result data set,ArrayList&lt;String&gt;
*/
public static final String EXTRA_RESULT = "select_result";
/**
* Original data set
*/
public static final String EXTRA_DEFAULT_SELECTED_LIST = "default_list";
// Default image size
private static final int DEFAULT_IMAGE_SIZE = 9;
private ArrayList<String> resultList = new ArrayList<>();
private Button mSubmitButton;
private int mDefaultCount = DEFAULT_IMAGE_SIZE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MIS_NO_ACTIONBAR);
setContentView(R.layout.mis_activity_default);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(Color.BLACK);
}
findViewById(R.id.btn_back).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setResult(RESULT_CANCELED, null);
finish();
}
});
final Intent intent = getIntent();
mDefaultCount = intent.getIntExtra(EXTRA_SELECT_COUNT, DEFAULT_IMAGE_SIZE);
final int mode = intent.getIntExtra(EXTRA_SELECT_MODE, MODE_MULTI);
final boolean isShow = intent.getBooleanExtra(EXTRA_SHOW_CAMERA, true);
if (mode == MODE_MULTI && intent.hasExtra(EXTRA_DEFAULT_SELECTED_LIST)) {
resultList = intent.getStringArrayListExtra(EXTRA_DEFAULT_SELECTED_LIST);
}
mSubmitButton = (Button) findViewById(R.id.commit);
if (mode == MODE_MULTI) {
updateDoneText(resultList);
mSubmitButton.setVisibility(View.VISIBLE);
mSubmitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (resultList != null && resultList.size() > 0) {
// Notify success
Intent data = new Intent();
data.putStringArrayListExtra(EXTRA_RESULT, resultList);
setResult(RESULT_OK, data);
} else {
setResult(RESULT_CANCELED);
}
finish();
}
});
} else {
mSubmitButton.setVisibility(View.GONE);
}
if (savedInstanceState == null) {
Bundle bundle = new Bundle();
bundle.putInt(MultiImageSelectorFragment.EXTRA_SELECT_COUNT, mDefaultCount);
bundle.putInt(MultiImageSelectorFragment.EXTRA_SELECT_MODE, mode);
bundle.putBoolean(MultiImageSelectorFragment.EXTRA_SHOW_CAMERA, isShow);
bundle.putStringArrayList(MultiImageSelectorFragment.EXTRA_DEFAULT_SELECTED_LIST, resultList);
getSupportFragmentManager().beginTransaction()
.add(R.id.image_grid, Fragment.instantiate(this, MultiImageSelectorFragment.class.getName(), bundle))
.commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
setResult(RESULT_CANCELED);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Update done button by select image data
*
* @param resultList selected image data
*/
private void updateDoneText(ArrayList<String> resultList) {
int size = 0;
if (resultList == null || resultList.size() <= 0) {
mSubmitButton.setText(R.string.mis_action_done);
mSubmitButton.setEnabled(false);
} else {
size = resultList.size();
mSubmitButton.setEnabled(true);
}
mSubmitButton.setText(getString(R.string.mis_action_button_string,
getString(R.string.mis_action_done), size, mDefaultCount));
}
@Override
public void onSingleImageSelected(String path) {
Intent data = new Intent();
resultList.add(path);
data.putStringArrayListExtra(EXTRA_RESULT, resultList);
setResult(RESULT_OK, data);
finish();
}
@Override
public void onImageSelected(String path) {
if (!resultList.contains(path)) {
resultList.add(path);
}
updateDoneText(resultList);
}
@Override
public void onImageUnselected(String path) {
if (resultList.contains(path)) {
resultList.remove(path);
}
updateDoneText(resultList);
}
@Override
public void onCameraShot(File imageFile) {
if (imageFile != null) {
// notify system the image has change
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageFile)));
Intent data = new Intent();
resultList.add(imageFile.getAbsolutePath());
data.putStringArrayListExtra(EXTRA_RESULT, resultList);
setResult(RESULT_OK, data);
finish();
}
}
}
package me.nereo.multi_image_selector;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.ListPopupWindow;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import me.nereo.multi_image_selector.adapter.FolderAdapter;
import me.nereo.multi_image_selector.adapter.ImageGridAdapter;
import me.nereo.multi_image_selector.bean.Folder;
import me.nereo.multi_image_selector.bean.Image;
import me.nereo.multi_image_selector.utils.FileUtils;
import me.nereo.multi_image_selector.utils.ScreenUtils;
/**
* Multi image selector Fragment
* Created by Nereo on 2015/4/7.
* Updated by nereo on 2016/5/18.
*/
public class MultiImageSelectorFragment extends Fragment {
public static final String TAG = "MultiImageSelectorFragment";
private static final int REQUEST_STORAGE_WRITE_ACCESS_PERMISSION = 110;
private static final int REQUEST_CAMERA = 100;
private static final String KEY_TEMP_FILE = "key_temp_file";
// Single choice
public static final int MODE_SINGLE = 0;
// Multi choice
public static final int MODE_MULTI = 1;
/** Max image size,int,*/
public static final String EXTRA_SELECT_COUNT = "max_select_count";
/** Select mode,{@link #MODE_MULTI} by default */
public static final String EXTRA_SELECT_MODE = "select_count_mode";
/** Whether show camera,true by default */
public static final String EXTRA_SHOW_CAMERA = "show_camera";
/** Original data set */
public static final String EXTRA_DEFAULT_SELECTED_LIST = "default_list";
// loaders
private static final int LOADER_ALL = 0;
private static final int LOADER_CATEGORY = 1;
// image result data set
private ArrayList<String> resultList = new ArrayList<>();
// folder result data set
private ArrayList<Folder> mResultFolder = new ArrayList<>();
private GridView mGridView;
private Callback mCallback;
private ImageGridAdapter mImageAdapter;
private FolderAdapter mFolderAdapter;
private ListPopupWindow mFolderPopupWindow;
private TextView mCategoryText;
private View mPopupAnchorView;
private boolean hasFolderGened = false;
private File mTmpFile;
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (Callback) getActivity();
}catch (ClassCastException e){
throw new ClassCastException("The Activity must implement MultiImageSelectorFragment.Callback interface...");
}
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.mis_fragment_multi_image, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final int mode = selectMode();
if(mode == MODE_MULTI) {
ArrayList<String> tmp = getArguments().getStringArrayList(EXTRA_DEFAULT_SELECTED_LIST);
if(tmp != null && tmp.size()>0) {
resultList = tmp;
}
}
mImageAdapter = new ImageGridAdapter(getActivity(), showCamera(), 3);
mImageAdapter.showSelectIndicator(mode == MODE_MULTI);
mPopupAnchorView = view.findViewById(R.id.footer);
mCategoryText = (TextView) view.findViewById(R.id.category_btn);
mCategoryText.setText(R.string.mis_folder_all);
mCategoryText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mFolderPopupWindow == null){
createPopupFolderList();
}
if (mFolderPopupWindow.isShowing()) {
mFolderPopupWindow.dismiss();
} else {
mFolderPopupWindow.show();
int index = mFolderAdapter.getSelectIndex();
index = index == 0 ? index : index - 1;
mFolderPopupWindow.getListView().setSelection(index);
}
}
});
mGridView = (GridView) view.findViewById(R.id.grid);
mGridView.setAdapter(mImageAdapter);
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (mImageAdapter.isShowCamera()) {
if (i == 0) {
showCameraAction();
} else {
Image image = (Image) adapterView.getAdapter().getItem(i);
selectImageFromGrid(image, mode);
}
} else {
Image image = (Image) adapterView.getAdapter().getItem(i);
selectImageFromGrid(image, mode);
}
}
});
mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_FLING) {
Picasso.with(view.getContext()).pauseTag(TAG);
} else {
Picasso.with(view.getContext()).resumeTag(TAG);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
mFolderAdapter = new FolderAdapter(getActivity());
}
/**
* Create popup ListView
*/
private void createPopupFolderList() {
Point point = ScreenUtils.getScreenSize(getActivity());
int width = point.x;
int height = (int) (point.y * (6f/8.0f));
mFolderPopupWindow = new ListPopupWindow(getActivity());
mFolderPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
mFolderPopupWindow.setAdapter(mFolderAdapter);
mFolderPopupWindow.setContentWidth(width);
mFolderPopupWindow.setWidth(width);
mFolderPopupWindow.setHeight(height);
mFolderPopupWindow.setAnchorView(mPopupAnchorView);
mFolderPopupWindow.setModal(true);
mFolderPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
mFolderAdapter.setSelectIndex(i);
final int index = i;
final AdapterView v = adapterView;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mFolderPopupWindow.dismiss();
if (index == 0) {
getActivity().getSupportLoaderManager().restartLoader(LOADER_ALL, null, mLoaderCallback);
mCategoryText.setText(R.string.mis_folder_all);
if (showCamera()) {
mImageAdapter.setShowCamera(true);
} else {
mImageAdapter.setShowCamera(false);
}
} else {
Folder folder = (Folder) v.getAdapter().getItem(index);
if (null != folder) {
mImageAdapter.setData(folder.images);
mCategoryText.setText(folder.name);
if (resultList != null && resultList.size() > 0) {
mImageAdapter.setDefaultSelected(resultList);
}
}
mImageAdapter.setShowCamera(false);
}
mGridView.smoothScrollToPosition(0);
}
}, 100);
}
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(KEY_TEMP_FILE, mTmpFile);
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
mTmpFile = (File) savedInstanceState.getSerializable(KEY_TEMP_FILE);
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// load image data
getActivity().getSupportLoaderManager().initLoader(LOADER_ALL, null, mLoaderCallback);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CAMERA){
if(resultCode == Activity.RESULT_OK) {
if (mTmpFile != null) {
if (mCallback != null) {
mCallback.onCameraShot(mTmpFile);
}
}
}else{
// delete tmp file
while (mTmpFile != null && mTmpFile.exists()){
boolean success = mTmpFile.delete();
if(success){
mTmpFile = null;
}
}
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
if(mFolderPopupWindow != null){
if(mFolderPopupWindow.isShowing()){
mFolderPopupWindow.dismiss();
}
}
super.onConfigurationChanged(newConfig);
}
/**
* Open camera
*/
private void showCameraAction() {
if(ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED){
requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
getString(R.string.mis_permission_rationale_write_storage),
REQUEST_STORAGE_WRITE_ACCESS_PERMISSION);
}else {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
try {
mTmpFile = FileUtils.createTmpFile(getActivity());
} catch (IOException e) {
e.printStackTrace();
}
if (mTmpFile != null && mTmpFile.exists()) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
startActivityForResult(intent, REQUEST_CAMERA);
} else {
Toast.makeText(getActivity(), R.string.mis_error_image_not_exist, Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getActivity(), R.string.mis_msg_no_camera, Toast.LENGTH_SHORT).show();
}
}
}
private void requestPermission(final String permission, String rationale, final int requestCode){
if(shouldShowRequestPermissionRationale(permission)){
new AlertDialog.Builder(getContext())
.setTitle(R.string.mis_permission_dialog_title)
.setMessage(rationale)
.setPositiveButton(R.string.mis_permission_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(new String[]{permission}, requestCode);
}
})
.setNegativeButton(R.string.mis_permission_dialog_cancel, null)
.create().show();
}else{
requestPermissions(new String[]{permission}, requestCode);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(requestCode == REQUEST_STORAGE_WRITE_ACCESS_PERMISSION){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
showCameraAction();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
/**
* notify callback
* @param image image data
*/
private void selectImageFromGrid(Image image, int mode) {
if(image != null) {
if(mode == MODE_MULTI) {
if (resultList.contains(image.path)) {
resultList.remove(image.path);
if (mCallback != null) {
mCallback.onImageUnselected(image.path);
}
} else {
if(selectImageCount() == resultList.size()){
Toast.makeText(getActivity(), R.string.mis_msg_amount_limit, Toast.LENGTH_SHORT).show();
return;
}
resultList.add(image.path);
if (mCallback != null) {
mCallback.onImageSelected(image.path);
}
}
mImageAdapter.select(image);
}else if(mode == MODE_SINGLE){
if(mCallback != null){
mCallback.onSingleImageSelected(image.path);
}
}
}
}
private LoaderManager.LoaderCallbacks<Cursor> mLoaderCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
private final String[] IMAGE_PROJECTION = {
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.MIME_TYPE,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media._ID };
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = null;
if(id == LOADER_ALL) {
cursorLoader = new CursorLoader(getActivity(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION,
IMAGE_PROJECTION[4]+">0 AND "+IMAGE_PROJECTION[3]+"=? OR "+IMAGE_PROJECTION[3]+"=? ",
new String[]{"image/jpeg", "image/png"}, IMAGE_PROJECTION[2] + " DESC");
}else if(id == LOADER_CATEGORY){
cursorLoader = new CursorLoader(getActivity(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION,
IMAGE_PROJECTION[4]+">0 AND "+IMAGE_PROJECTION[0]+" like '%"+args.getString("path")+"%'",
null, IMAGE_PROJECTION[2] + " DESC");
}
return cursorLoader;
}
private boolean fileExist(String path){
if(!TextUtils.isEmpty(path)){
return new File(path).exists();
}
return false;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (data != null) {
if (data.getCount() > 0) {
List<Image> images = new ArrayList<>();
data.moveToFirst();
do{
String path = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]));
String name = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]));
long dateTime = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]));
if(!fileExist(path)){continue;}
Image image = null;
if (!TextUtils.isEmpty(name)) {
image = new Image(path, name, dateTime);
images.add(image);
}
if( !hasFolderGened ) {
// get all folder data
File folderFile = new File(path).getParentFile();
if(folderFile != null && folderFile.exists()){
String fp = folderFile.getAbsolutePath();
Folder f = getFolderByPath(fp);
if(f == null){
Folder folder = new Folder();
folder.name = folderFile.getName();
folder.path = fp;
folder.cover = image;
List<Image> imageList = new ArrayList<>();
imageList.add(image);
folder.images = imageList;
mResultFolder.add(folder);
}else {
f.images.add(image);
}
}
}
}while(data.moveToNext());
mImageAdapter.setData(images);
if(resultList != null && resultList.size()>0){
mImageAdapter.setDefaultSelected(resultList);
}
if(!hasFolderGened) {
mFolderAdapter.setData(mResultFolder);
hasFolderGened = true;
}
}
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
};
private Folder getFolderByPath(String path){
if(mResultFolder != null){
for (Folder folder : mResultFolder) {
if(TextUtils.equals(folder.path, path)){
return folder;
}
}
}
return null;
}
private boolean showCamera(){
return getArguments() == null || getArguments().getBoolean(EXTRA_SHOW_CAMERA, true);
}
private int selectMode(){
return getArguments() == null ? MODE_MULTI : getArguments().getInt(EXTRA_SELECT_MODE);
}
private int selectImageCount(){
return getArguments() == null ? 9 : getArguments().getInt(EXTRA_SELECT_COUNT);
}
/**
* Callback for host activity
*/
public interface Callback{
void onSingleImageSelected(String path);
void onImageSelected(String path);
void onImageUnselected(String path);
void onCameraShot(File imageFile);
}
}
package me.nereo.multi_image_selector.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import me.nereo.multi_image_selector.R;
import me.nereo.multi_image_selector.bean.Folder;
/**
* 文件夹Adapter
* Created by Nereo on 2015/4/7.
* Updated by nereo on 2016/1/19.
*/
public class FolderAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
private List<Folder> mFolders = new ArrayList<>();
int mImageSize;
int lastSelected = 0;
public FolderAdapter(Context context){
mContext = context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mImageSize = mContext.getResources().getDimensionPixelOffset(R.dimen.mis_folder_cover_size);
}
/**
* 设置数据集
* @param folders
*/
public void setData(List<Folder> folders) {
if(folders != null && folders.size()>0){
mFolders = folders;
}else{
mFolders.clear();
}
notifyDataSetChanged();
}
@Override
public int getCount() {
return mFolders.size()+1;
}
@Override
public Folder getItem(int i) {
if(i == 0) return null;
return mFolders.get(i-1);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if(view == null){
view = mInflater.inflate(R.layout.mis_list_item_folder, viewGroup, false);
holder = new ViewHolder(view);
}else{
holder = (ViewHolder) view.getTag();
}
if (holder != null) {
if(i == 0){
holder.name.setText(R.string.mis_folder_all);
holder.path.setText("/sdcard");
holder.size.setText(String.format("%d%s",
getTotalImageSize(), mContext.getResources().getString(R.string.mis_photo_unit)));
if(mFolders.size()>0){
Folder f = mFolders.get(0);
if (f != null) {
Picasso.with(mContext)
.load(new File(f.cover.path))
.error(R.drawable.mis_default_error)
.resizeDimen(R.dimen.mis_folder_cover_size, R.dimen.mis_folder_cover_size)
.centerCrop()
.into(holder.cover);
}else{
holder.cover.setImageResource(R.drawable.mis_default_error);
}
}
}else {
holder.bindData(getItem(i));
}
if(lastSelected == i){
holder.indicator.setVisibility(View.VISIBLE);
}else{
holder.indicator.setVisibility(View.INVISIBLE);
}
}
return view;
}
private int getTotalImageSize(){
int result = 0;
if(mFolders != null && mFolders.size()>0){
for (Folder f: mFolders){
result += f.images.size();
}
}
return result;
}
public void setSelectIndex(int i) {
if(lastSelected == i) return;
lastSelected = i;
notifyDataSetChanged();
}
public int getSelectIndex(){
return lastSelected;
}
class ViewHolder{
ImageView cover;
TextView name;
TextView path;
TextView size;
ImageView indicator;
ViewHolder(View view){
cover = (ImageView)view.findViewById(R.id.cover);
name = (TextView) view.findViewById(R.id.name);
path = (TextView) view.findViewById(R.id.path);
size = (TextView) view.findViewById(R.id.size);
indicator = (ImageView) view.findViewById(R.id.indicator);
view.setTag(this);
}
void bindData(Folder data) {
if(data == null){
return;
}
name.setText(data.name);
path.setText(data.path);
if (data.images != null) {
size.setText(String.format("%d%s", data.images.size(), mContext.getResources().getString(R.string.mis_photo_unit)));
}else{
size.setText("*"+mContext.getResources().getString(R.string.mis_photo_unit));
}
if (data.cover != null) {
// 显示图片
Picasso.with(mContext)
.load(new File(data.cover.path))
.placeholder(R.drawable.mis_default_error)
.resizeDimen(R.dimen.mis_folder_cover_size, R.dimen.mis_folder_cover_size)
.centerCrop()
.into(cover);
}else{
cover.setImageResource(R.drawable.mis_default_error);
}
}
}
}
package me.nereo.multi_image_selector.adapter;
import android.content.Context;
import android.graphics.Point;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import me.nereo.multi_image_selector.MultiImageSelectorFragment;
import me.nereo.multi_image_selector.R;
import me.nereo.multi_image_selector.bean.Image;
/**
* 图片Adapter
* Created by Nereo on 2015/4/7.
* Updated by nereo on 2016/1/19.
*/
public class ImageGridAdapter extends BaseAdapter {
private static final int TYPE_CAMERA = 0;
private static final int TYPE_NORMAL = 1;
private Context mContext;
private LayoutInflater mInflater;
private boolean showCamera = true;
private boolean showSelectIndicator = true;
private List<Image> mImages = new ArrayList<>();
private List<Image> mSelectedImages = new ArrayList<>();
final int mGridWidth;
public ImageGridAdapter(Context context, boolean showCamera, int column) {
mContext = context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.showCamera = showCamera;
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int width;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
Point size = new Point();
wm.getDefaultDisplay().getSize(size);
width = size.x;
} else {
width = wm.getDefaultDisplay().getWidth();
}
mGridWidth = width / column;
}
/**
* 显示选择指示器
*
* @param b
*/
public void showSelectIndicator(boolean b) {
showSelectIndicator = b;
}
public void setShowCamera(boolean b) {
if (showCamera == b) return;
showCamera = b;
notifyDataSetChanged();
}
public boolean isShowCamera() {
return showCamera;
}
/**
* 选择某个图片,改变选择状态
*
* @param image
*/
public void select(Image image) {
if (mSelectedImages.contains(image)) {
mSelectedImages.remove(image);
} else {
mSelectedImages.add(image);
}
notifyDataSetChanged();
}
/**
* 通过图片路径设置默认选择
*
* @param resultList
*/
public void setDefaultSelected(ArrayList<String> resultList) {
for (String path : resultList) {
Image image = getImageByPath(path);
if (image != null) {
mSelectedImages.add(image);
}
}
if (mSelectedImages.size() > 0) {
notifyDataSetChanged();
}
}
private Image getImageByPath(String path) {
if (mImages != null && mImages.size() > 0) {
for (Image image : mImages) {
if (image.path.equalsIgnoreCase(path)) {
return image;
}
}
}
return null;
}
/**
* 设置数据集
*
* @param images
*/
public void setData(List<Image> images) {
mSelectedImages.clear();
if (images != null && images.size() > 0) {
mImages = images;
} else {
mImages.clear();
}
notifyDataSetChanged();
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
if (showCamera) {
return position == 0 ? TYPE_CAMERA : TYPE_NORMAL;
}
return TYPE_NORMAL;
}
@Override
public int getCount() {
return showCamera ? mImages.size() + 1 : mImages.size();
}
@Override
public Image getItem(int i) {
if (showCamera) {
if (i == 0) {
return null;
}
return mImages.get(i - 1);
} else {
return mImages.get(i);
}
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (isShowCamera()) {
if (i == 0) {
view = mInflater.inflate(R.layout.mis_list_item_camera, viewGroup, false);
return view;
}
}
ViewHolder holder;
if (view == null) {
view = mInflater.inflate(R.layout.mis_list_item_image, viewGroup, false);
holder = new ViewHolder(view);
} else {
holder = (ViewHolder) view.getTag();
}
if (holder != null) {
holder.bindData(getItem(i));
}
return view;
}
class ViewHolder {
ImageView image;
ImageView indicator;
View mask;
ViewHolder(View view) {
image = (ImageView) view.findViewById(R.id.image);
indicator = (ImageView) view.findViewById(R.id.checkmark);
mask = view.findViewById(R.id.mask);
view.setTag(this);
}
void bindData(final Image data) {
if (data == null) return;
// 处理单选和多选状态
if (showSelectIndicator) {
indicator.setVisibility(View.VISIBLE);
if (mSelectedImages.contains(data)) {
// 设置选中状态
indicator.setImageResource(R.drawable.mis_btn_selected);
mask.setVisibility(View.VISIBLE);
} else {
// 未选择
indicator.setImageResource(R.drawable.mis_btn_unselected);
mask.setVisibility(View.GONE);
}
} else {
indicator.setVisibility(View.GONE);
}
File imageFile = new File(data.path);
if (imageFile.exists()) {
// 显示图片
Picasso.with(mContext)
.load(imageFile)
.placeholder(R.drawable.mis_default_error)
.tag(MultiImageSelectorFragment.TAG)
.resize(mGridWidth, mGridWidth)
.centerCrop()
.into(image);
} else {
image.setImageResource(R.drawable.mis_default_error);
}
}
}
}
package me.nereo.multi_image_selector.bean;
import android.text.TextUtils;
import java.util.List;
/**
* 文件夹
* Created by Nereo on 2015/4/7.
*/
public class Folder {
public String name;
public String path;
public Image cover;
public List<Image> images;
@Override
public boolean equals(Object o) {
try {
Folder other = (Folder) o;
return TextUtils.equals(other.path, path);
}catch (ClassCastException e){
e.printStackTrace();
}
return super.equals(o);
}
}
package me.nereo.multi_image_selector.bean;
import android.text.TextUtils;
/**
* 图片实体
* Created by Nereo on 2015/4/7.
*/
public class Image {
public String path;
public String name;
public long time;
public Image(String path, String name, long time){
this.path = path;
this.name = name;
this.time = time;
}
@Override
public boolean equals(Object o) {
try {
Image other = (Image) o;
return TextUtils.equals(this.path, other.path);
}catch (ClassCastException e){
e.printStackTrace();
}
return super.equals(o);
}
}
package me.nereo.multi_image_selector.utils;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.text.TextUtils;
import java.io.File;
import java.io.IOException;
import static android.os.Environment.MEDIA_MOUNTED;
/**
* 文件操作类
* Created by Nereo on 2015/4/8.
*/
public class FileUtils {
private static final String JPEG_FILE_PREFIX = "IMG_";
private static final String JPEG_FILE_SUFFIX = ".jpg";
public static File createTmpFile(Context context) throws IOException{
File dir = null;
if(TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)) {
dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
if (!dir.exists()) {
dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM + "/Camera");
if (!dir.exists()) {
dir = getCacheDirectory(context, true);
}
}
}else{
dir = getCacheDirectory(context, true);
}
return File.createTempFile(JPEG_FILE_PREFIX, JPEG_FILE_SUFFIX, dir);
}
private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
/**
* Returns application cache directory. Cache directory will be created on SD card
* <i>("/Android/data/[app_package_name]/cache")</i> if card is mounted and app has appropriate permission. Else -
* Android defines cache directory on device's file system.
*
* @param context Application context
* @return Cache {@link File directory}.<br />
* <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
* {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null).
*/
public static File getCacheDirectory(Context context) {
return getCacheDirectory(context, true);
}
/**
* Returns application cache directory. Cache directory will be created on SD card
* <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or
* on device's file system depending incoming parameters.
*
* @param context Application context
* @param preferExternal Whether prefer external location for cache
* @return Cache {@link File directory}.<br />
* <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
* {@link android.content.Context#getCacheDir() Context.getCacheDir()} returns null).
*/
public static File getCacheDirectory(Context context, boolean preferExternal) {
File appCacheDir = null;
String externalStorageState;
try {
externalStorageState = Environment.getExternalStorageState();
} catch (NullPointerException e) { // (sh)it happens (Issue #660)
externalStorageState = "";
} catch (IncompatibleClassChangeError e) { // (sh)it happens too (Issue #989)
externalStorageState = "";
}
if (preferExternal && MEDIA_MOUNTED.equals(externalStorageState) && hasExternalStoragePermission(context)) {
appCacheDir = getExternalCacheDir(context);
}
if (appCacheDir == null) {
appCacheDir = context.getCacheDir();
}
if (appCacheDir == null) {
String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/";
appCacheDir = new File(cacheDirPath);
}
return appCacheDir;
}
/**
* Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be
* created on SD card <i>("/Android/data/[app_package_name]/cache/uil-images")</i> if card is mounted and app has
* appropriate permission. Else - Android defines cache directory on device's file system.
*
* @param context Application context
* @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images")
* @return Cache {@link File directory}
*/
public static File getIndividualCacheDirectory(Context context, String cacheDir) {
File appCacheDir = getCacheDirectory(context);
File individualCacheDir = new File(appCacheDir, cacheDir);
if (!individualCacheDir.exists()) {
if (!individualCacheDir.mkdir()) {
individualCacheDir = appCacheDir;
}
}
return individualCacheDir;
}
private static File getExternalCacheDir(Context context) {
File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data");
File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache");
if (!appCacheDir.exists()) {
if (!appCacheDir.mkdirs()) {
return null;
}
try {
new File(appCacheDir, ".nomedia").createNewFile();
} catch (IOException e) {
}
}
return appCacheDir;
}
private static boolean hasExternalStoragePermission(Context context) {
int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
return perm == PackageManager.PERMISSION_GRANTED;
}
}
package me.nereo.multi_image_selector.utils;
import android.content.Context;
import android.graphics.Point;
import android.os.Build;
import android.view.Display;
import android.view.WindowManager;
/**
* 屏幕工具
* Created by nereo on 15/11/19.
* Updated by nereo on 2016/1/19.
*/
public class ScreenUtils {
public static Point getScreenSize(Context context){
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point out = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(out);
}else{
int width = display.getWidth();
int height = display.getHeight();
out.set(width, height);
}
return out;
}
}
package me.nereo.multi_image_selector.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* Created by nereo on 15/11/10.
*/
public class SquareFrameLayout extends FrameLayout{
public SquareFrameLayout(Context context) {
super(context);
}
public SquareFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
}
}
package me.nereo.multi_image_selector.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
/** An image view which always remains square with respect to its width. */
class SquaredImageView extends ImageView {
public SquaredImageView(Context context) {
super(context);
}
public SquaredImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#CDCECE" android:state_enabled="false" />
<item android:color="#FFFFFF" android:state_enabled="true" />
<item android:color="#CDCECE" android:state_pressed="false" />
<item android:color="#FFFFFF" android:state_pressed="true" />
<item android:color="#CDCECE" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#757575" android:state_pressed="true" />
<item android:color="#757575" android:state_selected="true" />
<item android:color="#757575" android:state_checked="true" />
<item android:color="#bababa" android:state_pressed="false" />
<item android:color="#bababa" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#44BF1A" />
</shape>
</item>
<item android:state_enabled="true">
<shape android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#44BF1A" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#337523" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="#337523" />
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true">
<shape>
<solid android:color="#D948484d"/>
</shape>
</item>
<item android:state_pressed="false">
<shape>
<solid android:color="#48484d"/>
</shape>
</item>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:horizontalSpacing="@dimen/mis_space_size"
android:verticalSpacing="@dimen/mis_space_size"
android:paddingBottom="?android:attr/actionBarSize"
android:clipToPadding="false"
android:numColumns="auto_fit"
android:columnWidth="@dimen/mis_image_size"/>
<RelativeLayout
android:clickable="true"
android:id="@+id/footer"
android:background="#cc000000"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize">
<Button
android:id="@+id/category_btn"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:layout_centerVertical="true"
android:textColor="@color/mis_folder_text_color"
tools:text="所有图片"
android:textSize="16sp"
android:gravity="center_vertical"
android:drawableRight="@drawable/mis_text_indicator"
android:drawablePadding="5dp"
android:background="@null"
android:singleLine="true"
android:ellipsize="end"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</RelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#191a1c"
android:orientation="vertical">
<include
layout="@layout/mis_cmp_customer_actionbar"
android:layout_width="match_parent"
android:layout_height="60dp" />
<FrameLayout
android:id="@+id/image_grid"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<?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="60dp"
android:background="#191a1c"
android:orientation="vertical">
<ImageView
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:src="@drawable/mis_btn_back" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="图片"
android:textColor="#bababa"
android:textSize="18sp" />
<Button
android:id="@+id/commit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="@drawable/mis_action_btn"
android:minHeight="1dp"
android:minWidth="1dp"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="5dp"
android:text="完成"
android:textColor="@color/mis_default_text_color"
android:textSize="14sp" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#191a1c">
<GridView
android:id="@+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:horizontalSpacing="@dimen/mis_space_size"
android:numColumns="3"
android:paddingBottom="49dp"
android:verticalSpacing="@dimen/mis_space_size" />
<RelativeLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="49dp"
android:layout_alignParentBottom="true"
android:background="#cc000000"
android:clickable="true">
<Button
android:id="@+id/category_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:background="@null"
android:drawableRight="@drawable/mis_text_indicator"
android:ellipsize="end"
android:gravity="center"
android:includeFontPadding="false"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:singleLine="true"
android:textColor="@color/mis_folder_text_color"
android:textSize="18sp"
tools:text="所有图片" />
</RelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<me.nereo.multi_image_selector.view.SquareFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/mis_camera_background_selector">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="15dp"
android:drawableTop="@drawable/mis_tip_take_photo"
android:gravity="center_horizontal"
android:includeFontPadding="false"
android:text="@string/mis_tip_take_photo"
android:textColor="#aaaaaa"
android:textSize="12sp" />
</me.nereo.multi_image_selector.view.SquareFrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp">
<ImageView
android:id="@+id/cover"
android:layout_width="@dimen/mis_folder_cover_size"
android:layout_height="@dimen/mis_folder_cover_size"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:scaleType="centerInside"
android:src="@drawable/mis_default_error" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:layout_toLeftOf="@+id/indicator"
android:layout_toRightOf="@+id/cover"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="16sp"
tools:text="img" />
<TextView
android:id="@+id/path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:singleLine="true"
android:textColor="#AFAFAF"
android:textSize="12sp"
android:visibility="gone"
tools:text="/sdcard/a/" />
<TextView
android:id="@+id/size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#AFAFAF"
android:textSize="12sp"
tools:text="1张" />
</LinearLayout>
<ImageView
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="20dp"
android:src="@drawable/mis_default_check" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<me.nereo.multi_image_selector.view.SquareFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<me.nereo.multi_image_selector.view.SquaredImageView
android:id="@+id/image"
android:scaleType="centerInside"
android:src="@drawable/mis_default_error"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:visibility="gone"
android:id="@+id/mask"
android:background="#88000000"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/checkmark"
android:layout_gravity="top|right"
android:layout_marginTop="5.5dp"
android:layout_marginRight="5.5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/mis_btn_unselected"/>
</me.nereo.multi_image_selector.view.SquareFrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="mis_image_size">96dp</dimen>
<dimen name="mis_space_size">2dp</dimen>
<dimen name="mis_folder_cover_size">72dp</dimen>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="mis_image_size">100dp</dimen>
<dimen name="mis_space_size">2dp</dimen>
<dimen name="mis_folder_cover_size">72dp</dimen>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="mis_image_size">120dp</dimen>
<dimen name="mis_space_size">3dp</dimen>
<dimen name="mis_folder_cover_size">82dp</dimen>
</resources>
\ No newline at end of file
<resources>
<string name="mis_folder_all">所有照片</string>
<string name="mis_preview">预览</string>
<string name="mis_msg_no_camera">没有系统相机</string>
<string name="mis_msg_amount_limit">已经达到最高选择数量</string>
<string name="mis_action_done">完成</string>
<string name="mis_photo_unit"></string>
<string name="mis_tip_take_photo">拍摄照片</string>
<string name="mis_error_image_not_exist">图片错误</string>
<string name="mis_error_no_permission">无权限</string>
<string name="mis_permission_dialog_title">权限拒绝</string>
<string name="mis_permission_dialog_ok"></string>
<string name="mis_permission_dialog_cancel">拒绝</string>
<string name="mis_permission_rationale">浏览图片需要您提供浏览存储的权限</string>
<string name="mis_permission_rationale_write_storage">保存拍照图片需要您提供写存储权限</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="mis_actionbar_color">#21282C</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="mis_image_size">120dp</dimen>
<dimen name="mis_space_size">4dp</dimen>
<dimen name="mis_folder_cover_size">72dp</dimen>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<public name="mis_asv" type="drawable" />
</resources>
\ No newline at end of file
<resources>
<string name="mis_folder_all">All Images</string>
<string name="mis_preview">Preview</string>
<string name="mis_msg_no_camera">No system camera found</string>
<string name="mis_msg_amount_limit">Select images amount is limit</string>
<string name="mis_action_done">Done</string>
<string name="mis_action_button_string">%1$s(%2$d/%3$d)</string>
<string name="mis_photo_unit">Shot</string>
<string name="mis_tip_take_photo">Take photo</string>
<string name="mis_error_image_not_exist">Image error</string>
<string name="mis_error_no_permission">Has no permission</string>
<string name="mis_permission_dialog_title">Permission Deny</string>
<string name="mis_permission_dialog_ok">OK</string>
<string name="mis_permission_dialog_cancel">CANCEL</string>
<string name="mis_permission_rationale">Storage read permission is needed to pick files.</string>
<string name="mis_permission_rationale_write_storage">Storage write permission is needed to save the image.</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MIS_NO_ACTIONBAR" parent="Theme.AppCompat.Light.NoActionBar"></style>
</resources>
\ No newline at end of file
include ':app'
include ':app' ,':multi-image-selector'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment