圆形ImageView
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* 圆形ImageView,用于显示用户头像
*/
public class RoundImageView extends ImageView {
private static final String STATE_INSTANCE = "state_instance";
private static final String RADIUS = "radius";
private int sideColor = 0xFFFFFFFF;
/**
* 绘图的Paint
*/
private Paint mBitmapPaint;
/**
* 圆角的半径
*/
private int mRadius;
/**
* 3x3 矩阵,主要用于缩小放大
*/
private Matrix mMatrix;
/**
* 渲染图像,使用图像为绘制图形着色
*/
private BitmapShader mBitmapShader;
/**
* view的宽度
*/
private int mWidth;
public RoundImageView(Context context) {
this(context, null);
}
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mMatrix = new Matrix();
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
mWidth = Math.min(width, height);
mRadius = mWidth / 2;
}
/**
* 初始化BitmapShader
*/
private void setUpShader() {
Drawable drawable = getDrawable();
Bitmap bmp = drawableToBitamp(drawable);
if (drawable == null || bmp == null) {
return;
}
mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP, TileMode.CLAMP);
float scale = 1.0f;
int bSize = Math.min(bmp.getWidth(), bmp.getHeight());
scale = mWidth * 1.0f / bSize;
mMatrix.setScale(scale, scale);
mBitmapShader.setLocalMatrix(mMatrix);
mBitmapPaint.setShader(mBitmapShader);
}
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
setUpShader();
canvas.drawColor(sideColor, PorterDuff.Mode.SRC_OVER);
canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
}
/**
* drawable转bitmap
*
* @param drawable
* @return
*/
protected Bitmap drawableToBitamp(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
bundle.putInt(RADIUS, mRadius);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(((Bundle) state)
.getParcelable(STATE_INSTANCE));
this.mRadius = bundle.getInt(RADIUS);
} else {
super.onRestoreInstanceState(state);
}
}
public void setBackGroundColor(int color) {
this.sideColor = color;
invalidate();
}
public int getBackGroundColor(){
return sideColor;
}
}
可缩放的ImageView
import android.content.Context;
import android.content.DialogInterface.OnDismissListener;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Build.VERSION;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.ImageView;
/**
* 可缩放的ImageView,用于图片浏览
*/
public class ScaleImageView extends ImageView {
private Context mContext;
private float MAX_SCALE = 8f;
private Matrix mMatrix;
private final float[] mMatrixValues = new float[9];
private int mWidth;
private int mHeight;
private int mIntrinsicWidth;
private int mIntrinsicHeight;
private float mScale;
private float mMinScale = 0.1f;
private float mPrevDistance;
private boolean isScaling;
private int mPrevMoveX;
private int mPrevMoveY;
private int mLastX;
private int mLastY;
private GestureDetector mDetector;
private float mSlop;
private OnDismissListener mListener;
private float mDefaultScale = 0f;
public ScaleImageView(Context context, AttributeSet attr) {
super(context, attr);
this.mContext = context;
initialize();
}
public ScaleImageView(Context context) {
super(context);
this.mContext = context;
initialize();
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
this.initialize();
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
this.initialize();
}
private void initialize() {
this.setScaleType(ScaleType.MATRIX);
this.mMatrix = new Matrix();
Drawable d = getDrawable();
if (d != null) {
mIntrinsicWidth = d.getIntrinsicWidth();
mIntrinsicHeight = d.getIntrinsicHeight();
}
mDetector = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
maxZoomTo((int) e.getX(), (int) e.getY());
cutting();
return super.onDoubleTap(e);
}
});
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
public void updateScale() {
mWidth = getWidth();
mHeight = getHeight();
mMatrix.reset();
mScale = (float) mWidth / (float) mIntrinsicWidth;
if (mScale * mIntrinsicHeight > mHeight) {
mScale = (float) mHeight / (float) mIntrinsicHeight;
}
zoomTo(mScale, mWidth / 2, mHeight / 2);
cutting();
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
mWidth = r - l;
mHeight = b - t;
mMatrix.reset();
int r_norm = r - l;
mScale = (float) r_norm / (float) mIntrinsicWidth;
if (mScale * mIntrinsicHeight > mHeight) {
mScale = (float) mHeight / (float) mIntrinsicHeight;
}
zoomTo(mScale, mWidth / 2, mHeight / 2);
cutting();
return super.setFrame(l, t, r, b);
}
protected float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
protected float getScale() {
return getValue(mMatrix, Matrix.MSCALE_X);
}
public float getTranslateX() {
return getValue(mMatrix, Matrix.MTRANS_X);
}
protected float getTranslateY() {
return getValue(mMatrix, Matrix.MTRANS_Y);
}
protected void maxZoomTo(int x, int y) {
float scale = 0;
if (MAX_SCALE != getScale() && (Math.abs(getScale() - MAX_SCALE)) > 0.1f) {
scale = MAX_SCALE / getScale();
} else {
scale = mMinScale / getScale();
}
zoomTo(scale, x, y);
}
public void reset() {
mMatrix.reset();
mScale = mMinScale;
setImageMatrix(mMatrix);
}
public void zoomTo(float scale, int x, int y) {
if (getScale() * scale < mMinScale) {
return;
}
if (scale >= 1 && getScale() * scale > MAX_SCALE) {
return;
}
mMatrix.postScale(scale, scale);
mMatrix.postTranslate(-(mWidth * scale - mWidth) / 2, -(mHeight * scale - mHeight) / 2);
mMatrix.postTranslate(-(x - (mWidth / 2)) * scale, 0);
mMatrix.postTranslate(0, -(y - (mHeight / 2)) * scale);
setImageMatrix(mMatrix);
}
public void cutting() {
int width = (int) (mIntrinsicWidth * getScale());
int height = (int) (mIntrinsicHeight * getScale());
if (getTranslateX() < -(width - mWidth)) {
mMatrix.postTranslate(-(getTranslateX() + width - mWidth), 0);
}
if (getTranslateX() > 0) {
mMatrix.postTranslate(-getTranslateX(), 0);
}
if (getTranslateY() < -(height - mHeight)) {
mMatrix.postTranslate(0, -(getTranslateY() + height - mHeight));
}
if (getTranslateY() > 0) {
mMatrix.postTranslate(0, -getTranslateY());
}
if (width < mWidth) {
mMatrix.postTranslate((mWidth - width) / 2, 0);
}
if (height < mHeight) {
mMatrix.postTranslate(0, (mHeight - height) / 2);
}
setImageMatrix(mMatrix);
}
private float distance(float x0, float x1, float y0, float y1) {
float x = x0 - x1;
float y = y0 - y1;
return (float) Math.sqrt(x * x + y * y);
}
private float dispDistance() {
return (float) Math.sqrt(mWidth * mWidth + mHeight * mHeight);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (isGingerbread() || event.getAction() != MotionEvent.ACTION_MOVE) {
return super.dispatchTouchEvent(event);
}
if (mDefaultScale == 0f) {
mDefaultScale = mScale;
}
if (getScale() - 1.0f >= 0.01f && !checkEdge(event)) {
getParent().requestDisallowInterceptTouchEvent(true);
} else {
getParent().requestDisallowInterceptTouchEvent(false);
}
return super.dispatchTouchEvent(event);
}
@SuppressWarnings("deprecation")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mDetector.onTouchEvent(event)) {
return true;
}
int touchCount = event.getPointerCount();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_1_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
if (touchCount >= 2) {
float distance = distance(event.getX(0), event.getX(1), event.getY(0),
event.getY(1));
mPrevDistance = distance;
isScaling = true;
} else {
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
mLastX = mPrevMoveX;
mLastY = mPrevMoveY;
}
case MotionEvent.ACTION_MOVE:
if (touchCount >= 2 && isScaling) {
float dist = distance(event.getX(0), event.getX(1), event.getY(0),
event.getY(1));
float scale = (dist - mPrevDistance) / dispDistance();
mPrevDistance = dist;
scale += 1;
scale = scale * scale;
zoomTo(scale, mWidth / 2, mHeight / 2);
cutting();
} else if (!isScaling) {
int distanceX = mPrevMoveX - (int) event.getX();
int distanceY = mPrevMoveY - (int) event.getY();
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
mMatrix.postTranslate(-distanceX, -distanceY);
cutting();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_2_UP:
if (event.getPointerCount() <= 1) {
isScaling = false;
checkExecuteCallback(event);
} else {
if (mDefaultScale == 0f) {
mDefaultScale = mScale;
}
}
mPrevDistance = 0;
mPrevMoveX = 0;
mPrevMoveY = 0;
mLastX = 0;
mLastY = 0;
break;
}
return true;
}
/**
* 检查是否执行回调
*
* @param event
*/
private void checkExecuteCallback(MotionEvent event) {
int delta = (int) distance(mLastX, event.getX(), mLastY, event.getY());
if (delta < mSlop && mListener != null) {
mListener.onDismiss(null);
}
}
/**
* 检查是否滑动到放大的边缘
*
* @param event
* @return
*/
private boolean checkEdge(MotionEvent event) {
if (isGingerbread()) {
return super.dispatchTouchEvent(event);
}
mapDisplayRect();
if (Math.abs(mDisplayRect.left) <= mSlop
||
(Math.abs(mDisplayRect.left) > mSlop && getScale() - mDefaultScale <= 0.5f)
|| Math.abs(mDisplayRect.right - getWidth()) < mSlop
|| (Math.abs(mDisplayRect.right - getWidth()) >= mSlop && getScale()
- mDefaultScale <= 0.5f)) {
return true;
}
return false;
}
private final RectF mDisplayRect = new RectF();
/**
* 将图片的尺寸矩阵map成RectF
*
* @return
*/
private RectF mapDisplayRect() {
Drawable d = getDrawable();
if (null != d) {
mDisplayRect.set(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
getImageMatrix().mapRect(mDisplayRect);
return mDisplayRect;
}
return null;
}
public void setOndismissListener(OnDismissListener listener) {
mListener = listener;
}
private boolean isGingerbread() {
if (VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD) {
return true;
}
return false;
}
}
获取验证码倒计时按钮
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* 鉴于经常用到获取验证码倒计时按钮 在网上也没有找到理想的 自己写一个
* PS: 由于发现timer每次cancle()之后不能重新schedule方法,所以计时完毕只恐timer.
* 每次开始计时的时候重新设置timer, 没想到好办法初次下策
* 注意把该类的onCreate()onDestroy()和activity的onCreate()onDestroy()同步处理
*/
public class TimeButton extends Button implements OnClickListener {
private long lenght = 120 * 1000;
private String textafter = "重新获取";
private String textbefore = "获取验证码";
private final String TIME = "time";
private final String CTIME = "ctime";
private OnClickListener mOnclickListener;
private Timer t;
private TimerTask tt;
private long time;
Map map = new HashMap();
public TimeButton(Context context) {
this(context, null);
}
public TimeButton(Context context, AttributeSet attrs) {
super(context, attrs);
setOnClickListener(this);
}
@SuppressLint("HandlerLeak")
Handler han = new Handler() {
public void handleMessage(android.os.Message msg) {
TimeButton.this.setText(time / 1000 + textafter);
time -= 1000;
if (time < 0) {
TimeButton.this.setEnabled(true);
TimeButton.this.setText(textbefore);
clearTimer();
}
}
;
};
private void initTimer() {
time = lenght;
t = new Timer();
tt = new TimerTask() {
@Override
public void run() {
han.sendEmptyMessage(0x01);
}
};
}
private void clearTimer() {
if (tt != null) {
tt.cancel();
tt = null;
}
if (t != null)
t.cancel();
t = null;
}
@Override
public void setOnClickListener(OnClickListener l) {
if (l instanceof TimeButton) {
super.setOnClickListener(l);
} else {
this.mOnclickListener = l;
}
}
@Override
public void onClick(View v) {
if (mOnclickListener != null)
mOnclickListener.onClick(v);
initTimer();
this.setText(time / 1000 + textafter);
this.setEnabled(false);
t.schedule(tt, 0, 1000);
}
/**
* 和activity的onDestroy()方法同步
*/
public void onDestroy() {
if (map == null)
map = new HashMap();
map.put(TIME, time);
map.put(CTIME, System.currentTimeMillis());
clearTimer();
}
/**
* 和activity的onCreate()方法同步
*/
public void onCreate(Bundle bundle) {
if (map == null)
return;
if (map.size() <= 0)
return;
long time = System.currentTimeMillis() - map.get(CTIME) - map.get(TIME);
map.clear();
if (time > 0) {
return;
} else {
initTimer();
this.time = Math.abs(time);
t.schedule(tt, 0, 1000);
this.setText(time + textafter);
this.setEnabled(false);
}
}
/**
* 设置计时时候显示的文本
*/
public TimeButton setTextAfter(String text1) {
this.textafter = text1;
return this;
}
/**
* 设置点击之前的文本
*/
public TimeButton setTextBefore(String text0) {
this.textbefore = text0;
this.setText(textbefore);
return this;
}
/**
* 设置到计时长度
*/
public TimeButton setLenght(long lenght) {
this.lenght = lenght;
return this;
}
}
下拉刷新上拉加载
import android.content.Context;
import android.graphics.Color;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
/**
* 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.
*/
public class RefreshLayout<T extends AbsListView> extends SwipeRefreshLayout implements OnScrollListener {
/**
* 滑动到最下面时的上拉操作
*/
private int mTouchSlop;
/**
*
*/
protected T mAbsListView;
/**
* ListView滚动监听器,用于外部
*/
private OnScrollListener mListViewOnScrollListener;
private OnResultListener mScrollListener;
/**
* 上拉监听器, 到了最底部的上拉加载操作
*/
private OnLoadListener mOnLoadListener;
/**
* 按下时的y坐标
*/
protected int mYDown;
/**
* 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉
*/
protected int mLastY;
/**
* 是否在加载中 ( 上拉加载更多 )
*/
protected boolean isLoading = false;
private int mColor1;
private int mColor2;
/**
* ListView的加载中footer
*/
protected View mFooterView;
private int mScrollDirection = 0;
/**
* @param context
*/
public RefreshLayout(Context context) {
this(context, null);
}
public RefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (isInEditMode()) {
return;
}
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mColor1 = Color.parseColor("#FFB0C4DE");
mColor2 = Color.parseColor("#FF87CEFA");
}
@SuppressWarnings("deprecation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (isInEditMode()) {
return;
}
super.onLayout(changed, left, top, right, bottom);
if (mAbsListView == null) {
getRefreshView();
}
this.setColorScheme(mColor1, mColor2);
}
/**
* 获取ListView对象
*/
@SuppressWarnings("unchecked")
protected void getRefreshView() {
int childs = getChildCount();
if (childs <= 0) {
return;
}
View childView = null;
for (int i = 0; i < childs; i++) {
childView = getChildAt(i);
if (childView instanceof AbsListView) {
mAbsListView = (T) childView;
mAbsListView.setOnScrollListener(this);
}
}
}
@SuppressWarnings("unchecked")
public T findRefreshViewById(int id) {
mAbsListView = (T) this.findViewById(id);
mAbsListView.setOnScrollListener(this);
return mAbsListView;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
try {
return dealTouchEvent(event);
} catch (IllegalStateException exception) {
}
return true;
}
private boolean dealTouchEvent(MotionEvent event) {
final int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mYDown = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
mLastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
if (canLoad()) {
loadData();
}
if (mScrollListener != null) {
if (isPullUp()) {
mScrollDirection = 1;
} else {
mScrollDirection = 0;
}
}
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
/**
* 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.
*
* @return
*/
private boolean canLoad() {
return isBottom() && !isLoading && isPullUp() && mOnLoadListener != null;
}
/**
* 判断是否到了最底部
*/
private boolean isBottom() {
if (mAbsListView == null) {
getRefreshView();
}
if (mAbsListView != null && mAbsListView.getAdapter() != null) {
int childCount = mAbsListView.getAdapter().getCount();
return childCount > 1
&& mAbsListView.getLastVisiblePosition() == childCount - 1;
}
return false;
}
/**
* 是否是上拉操作
*
* @return
*/
private boolean isPullUp() {
return mLastY > 0 && (mYDown - mLastY) >= mTouchSlop * 3;
}
/**
* 如果到了最底部,而且是上拉操作.那么执行onLoad方法
*/
protected void loadData() {
setLoading(true);
mOnLoadListener.onLoad();
}
/**
* @param loading
*/
public void setLoading(boolean loading) {
isLoading = loading;
}
public AbsListView getListView() {
if (mAbsListView == null) {
getRefreshView();
}
return mAbsListView;
}
/**
* 使外部可以监听到listview的滚动
*
* @param listener
*/
public void addOnScrollListener(OnScrollListener listener) {
mListViewOnScrollListener = listener;
}
/**
* @param loadListener
*/
public void setOnLoadListener(OnLoadListener loadListener) {
mOnLoadListener = loadListener;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mListViewOnScrollListener != null) {
mListViewOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (mListViewOnScrollListener != null) {
mListViewOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
totalItemCount);
}
if (mScrollListener != null) {
mScrollListener.onResult(mScrollDirection);
}
if (canLoad()) {
loadData();
}
}
/**
* 加载更多的监听器
*/
public static interface OnLoadListener {
public void onLoad();
}
public void setOnScrollDirectionListener(OnResultListener listener) {
mScrollListener = listener;
}
public interface OnResultListener {
void onResult(int var1);
}
}