Commit 893c9986 by chengfengpiaopiao

图片选择器

parent 34c76b40
Showing with 3832 additions and 47 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.
*
* 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
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 "";
}
}
/*
* 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();
}
}
......@@ -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());
}
}
});
}
......
......@@ -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.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