1.SharedPreference:
public class SharedPrefsUtil {
public static void putValue(Context context, String key, int value) {
Editor sp = PreferenceManager.getDefaultSharedPreferences(context).edit();
sp.putInt(key, value);
sp.commit();
}
public static void putValue(Context context, String key, boolean value) {
Editor sp = PreferenceManager.getDefaultSharedPreferences(context).edit();
sp.putBoolean(key, value);
sp.commit();
}
public static void putValue(Context context, String key, String value) {
Editor sp = PreferenceManager.getDefaultSharedPreferences(context).edit();
sp.putString(key, value);
sp.commit();
}
public static int getValue(Context context, String key, int defValue) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
int value = sp.getInt(key, defValue);
return value;
}
public static boolean getValue(Context context, String key, boolean defValue) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
boolean value = sp.getBoolean(key, defValue);
return value;
}
public static String getValue(Context context, String key, String defValue) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String value = sp.getString(key, defValue);
return value;
}
}
2.MathUtils:平面几何用到的工具方法
public final class MathUtils {
// ===========================================================
// Constants
// ===========================================================
public static final Random RANDOM = new Random(System.nanoTime());
// ===========================================================
// Fields
// ===========================================================
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public static final float atan2(final float dY, final float dX) {
return (float) Math.atan2(dY, dX);
}
public static final float radToDeg(final float pRad) {
return MathConstants.RAD_TO_DEG * pRad;
}
public static final float degToRad(final float pDegree) {
return MathConstants.DEG_TO_RAD * pDegree;
}
public static final int signum(final int n) {
if (n == 0) {
return 0;
} else if (n > 0) {
return 1;
} else {
return -1;
}
}
public static final int randomSign() {
if (RANDOM.nextBoolean()) {
return 1;
} else {
return -1;
}
}
public static final float random(final float pMin, final float pMax) {
return pMin + RANDOM.nextFloat() * (pMax - pMin);
}
/**
* @param pMin inclusive!
* @param pMax inclusive!
* @return
*/
public static final int random(final int pMin, final int pMax) {
return pMin + RANDOM.nextInt(pMax - pMin + 1);
}
public static final boolean randomBoolean() {
return MathUtils.random(0, 1) == 1;
}
public static final boolean isPowerOfTwo(final int n) {
return ((n != 0) && (n & (n - 1)) == 0);
}
public static final int nextPowerOfTwo(final float f) {
return MathUtils.nextPowerOfTwo((int) ((float) Math.ceil(f)));
}
public static final int nextPowerOfTwo(final int n) {
int k = n;
if (k == 0) {
return 1;
}
k--;
for (int i = 1; i < 32; i <<= 1) {
k = k | k >> i;
}
return k + 1;
}
public static final int sum(final int[] pValues) {
int sum = 0;
for (int i = pValues.length - 1; i >= 0; i--) {
sum += pValues[i];
}
return sum;
}
public static final void arraySumInternal(final int[] pValues) {
final int valueCount = pValues.length;
for (int i = 1; i < valueCount; i++) {
pValues[i] = pValues[i - 1] + pValues[i];
}
}
public static final void arraySumInternal(final long[] pValues) {
final int valueCount = pValues.length;
for (int i = 1; i < valueCount; i++) {
pValues[i] = pValues[i - 1] + pValues[i];
}
}
public static final void arraySumInternal(final long[] pValues, final long pFactor) {
pValues[0] = pValues[0] * pFactor;
final int valueCount = pValues.length;
for (int i = 1; i < valueCount; i++) {
pValues[i] = pValues[i - 1] + pValues[i] * pFactor;
}
}
public static final void arraySumInto(final long[] pValues, final long[] pTargetValues, final long pFactor) {
pTargetValues[0] = pValues[0] * pFactor;
final int valueCount = pValues.length;
for (int i = 1; i < valueCount; i++) {
pTargetValues[i] = pTargetValues[i - 1] + pValues[i] * pFactor;
}
}
public static final float arraySum(final float[] pValues) {
float sum = 0;
final int valueCount = pValues.length;
for (int i = 0; i < valueCount; i++) {
sum += pValues[i];
}
return sum;
}
public static final float arrayAverage(final float[] pValues) {
return MathUtils.arraySum(pValues) / pValues.length;
}
public static float[] rotateAroundCenter(final float[] pVertices, final float pRotation,
final float pRotationCenterX, final float pRotationCenterY) {
if (pRotation != 0) {
final float rotationRad = MathUtils.degToRad(pRotation);
final float sinRotationRad = (float) Math.sin(rotationRad);
final float cosRotationInRad = (float) Math.cos(rotationRad);
for (int i = pVertices.length - 2; i >= 0; i -= 2) {
final float pX = pVertices[i];
final float pY = pVertices[i + 1];
pVertices[i] = pRotationCenterX
+ (cosRotationInRad * (pX - pRotationCenterX) - sinRotationRad * (pY - pRotationCenterY));
pVertices[i + 1] = pRotationCenterY
+ (sinRotationRad * (pX - pRotationCenterX) + cosRotationInRad * (pY - pRotationCenterY));
}
}
return pVertices;
}
public static float[] scaleAroundCenter(final float[] pVertices, final float pScaleX, final float pScaleY,
final float pScaleCenterX, final float pScaleCenterY) {
if (pScaleX != 1 || pScaleY != 1) {
for (int i = pVertices.length - 2; i >= 0; i -= 2) {
pVertices[i] = pScaleCenterX + (pVertices[i] - pScaleCenterX) * pScaleX;
pVertices[i + 1] = pScaleCenterY + (pVertices[i + 1] - pScaleCenterY) * pScaleY;
}
}
return pVertices;
}
public static float[] rotateAndScaleAroundCenter(final float[] pVertices, final float pRotation,
final float pRotationCenterX, final float pRotationCenterY, final float pScaleX, final float pScaleY,
final float pScaleCenterX, final float pScaleCenterY) {
MathUtils.rotateAroundCenter(pVertices, pRotation, pRotationCenterX, pRotationCenterY);
return MathUtils.scaleAroundCenter(pVertices, pScaleX, pScaleY, pScaleCenterX, pScaleCenterY);
}
public static float[] revertScaleAroundCenter(final float[] pVertices, final float pScaleX, final float pScaleY,
final float pScaleCenterX, final float pScaleCenterY) {
return MathUtils.scaleAroundCenter(pVertices, 1 / pScaleX, 1 / pScaleY, pScaleCenterX, pScaleCenterY);
}
public static float[] revertRotateAroundCenter(final float[] pVertices, final float pRotation,
final float pRotationCenterX, final float pRotationCenterY) {
return MathUtils.rotateAroundCenter(pVertices, -pRotation, pRotationCenterX, pRotationCenterY);
}
public static float[] revertRotateAndScaleAroundCenter(final float[] pVertices, final float pRotation,
final float pRotationCenterX, final float pRotationCenterY, final float pScaleX, final float pScaleY,
final float pScaleCenterX, final float pScaleCenterY) {
MathUtils.revertScaleAroundCenter(pVertices, pScaleX, pScaleY, pScaleCenterX, pScaleCenterY);
return MathUtils.revertRotateAroundCenter(pVertices, pRotation, pRotationCenterX, pRotationCenterY);
}
public static final boolean isInBounds(final int pMinValue, final int pMaxValue, final int pValue) {
return pValue >= pMinValue && pValue <= pMaxValue;
}
public static final boolean isInBounds(final float pMinValue, final float pMaxValue, final float pValue) {
return pValue >= pMinValue && pValue <= pMaxValue;
}
/**
* @param pMinValue inclusive!
* @param pMaxValue inclusive!
* @param pValue
* @return
*/
public static final int bringToBounds(final int pMinValue, final int pMaxValue, final int pValue) {
return Math.max(pMinValue, Math.min(pMaxValue, pValue));
}
/**
* @param pMinValue inclusive!
* @param pMaxValue inclusive!
* @param pValue
* @return
*/
public static final float bringToBounds(final float pMinValue, final float pMaxValue, final float pValue) {
return Math.max(pMinValue, Math.min(pMaxValue, pValue));
}
/**
* @return the euclidean distance between the points (pX1, pY1) and (pX2, pY2).
*/
public static final float distance(final float pX1, final float pY1, final float pX2, final float pY2) {
final float dX = pX2 - pX1;
final float dY = pY2 - pY1;
return (float) Math.sqrt((dX * dX) + (dY * dY));
}
/**
* @return the euclidean distance between the origin (0, 0) and (pX, pY).
*/
public static final float length(final float pX, final float pY) {
return (float) Math.sqrt((pX * pX) + (pY * pY));
}
/**
* @param pX
* @param pY
* @param pMix [0...1]
* @return pX * (1 - pMix) + pY * pMix
*/
public static final float mix(final float pX, final float pY, final float pMix) {
return pX * (1 - pMix) + pY * pMix;
}
/**
* @param pX
* @param pY
* @param pMix [0...1]
* @return (int)Math.round(pX * (1 - pMix) + pY * pMix)
*/
public static final int mix(final int pX, final int pY, final float pMix) {
return Math.round(pX * (1 - pMix) + pY * pMix);
}
public static final boolean isEven(final int n) {
return n % 2 == 0;
}
public static final boolean isOdd(final int n) {
return n % 2 == 1;
}
public static float dot(final float pXA, final float pYA, final float pXB, final float pYB) {
return pXA * pXB + pYA * pYB;
}
public static float cross(final float pXA, final float pYA, final float pXB, final float pYB) {
return pXA * pYB - pXB * pYA;
}
// ===========================================================
// 额外添加
// ===========================================================
/**
* 求以PX1,PY1点为顶点,12点钟方向顶点连线及X2Y2顶点连线的夹角
* @param pX1
* @param pY1
* @param pX2
* @param pY2
* @return
*/
public static double getAngleForTwelve(float pX1, float pY1, float pX2, float pY2) {
if (pX1 == pX2 && pY1 == pY2) {
return 0;
}
double x4 = pX1;
double y4 = pY1 - 1;
double ma_x = pX2 - pX1;
double ma_y = pY2 - pY1;
double mb_x = x4 - pX1;
double mb_y = y4 - pY1;
if (mb_y == 0) {
mb_y = 1;
}
double v1 = (ma_x * mb_x) + (ma_y * mb_y);
double ma_val = Math.sqrt(ma_x * ma_x + ma_y * ma_y);
double mb_val = Math.sqrt(mb_x * mb_x + mb_y * mb_y);
double cosA = v1 / (ma_val * mb_val);
double angle = Math.acos(cosA) * 180.0f / Math.PI;
if ((ma_x < 0 && ma_y >= 0) || (ma_x < 0 && ma_y <= 0)) {
angle = 360.0f - angle;
}
return angle;
}
/**
* 求以PX1,PY1点为顶点,6点钟方向顶点连线及X2Y2顶点连线的夹角
* @param pX1
* @param pY1
* @param pX2
* @param pY2
* @return
*/
public static double getAngleForSix(float pX1, float pY1, float pX2, float pY2) {
if (pX1 == pX2 && pY1 == pY2) {
return 0;
}
double x4 = pX1;
double y4 = pY1 + 1;
double ma_x = pX2 - pX1;
double ma_y = pY2 - pY1;
double mb_x = x4 - pX1;
double mb_y = y4 - pY1;
if (mb_y == 0) {
mb_y = -1;
}
double v1 = (ma_x * mb_x) + (ma_y * mb_y);
double ma_val = Math.sqrt(ma_x * ma_x + ma_y * ma_y);
double mb_val = Math.sqrt(mb_x * mb_x + mb_y * mb_y);
double cosA = v1 / (ma_val * mb_val);
double angle = Math.acos(cosA) * 180.0f / Math.PI;
if ((ma_x > 0 && ma_y >= 0) || (ma_x > 0 && ma_y <= 0)) {
angle = 360.0f - angle;
}
return angle;
}
/**
* @param a 长轴长度的一半
* @param b 短轴长度的一半
* @param aX 中点坐标
* @param aY 中点坐标
* @param angle 椭圆上某点坐标和中点的连线 与 正长轴的夹角
* @return
*/
public static Coordinate getCoordinateForOval(float a, float b, float aX, float aY, float angle) {
float x = a * (float) Math.cos(Math.toRadians(angle));
float y = b * (float) Math.sin(Math.toRadians(angle));
Coordinate coordinate = new Coordinate(aX - x, aY - y);
return coordinate;
}
/**
* 计算圆形中圆周上某点的坐标
* @param aX 顶点坐标X
* @param aY 顶点坐标Y
* @param r 半径
* @param aAngle1 边(顶点与6点钟方向)与边(顶点与所求坐标)的角度
*/
public static Coordinate getCoordinateForCircleSix(float aX, float aY, float r, float aAngle1) {
aAngle1 = aAngle1 + 90;
float Y = (float) (Math.sin(Math.toRadians(aAngle1)) * r);
float X = (float) (Math.cos(Math.toRadians(aAngle1)) * r);
Coordinate coordinate = new Coordinate(aX + X, aY + Y);
return coordinate;
}
public static class Coordinate {
public float x = 0;
public float y = 0;
public Coordinate(float x, float y) {
this.x = x;
this.y = y;
}
}
/**
* 点到直线的最短距离的判断 点(x0,y0) 到由两点组成的线段(x1,y1) ,( x2,y2 )
* @param x1 线段
* @param y1 线段
* @param x2 线段
* @param y2 线段
* @param x0 点
* @param y0 点
* @return
*/
public static float pointToLine(float x0, float y0, float x1, float y1, float x2, float y2) {
float space = 0;
float a, b, c;
a = distance(x1, y1, x2, y2);// 线段的长度
b = distance(x1, y1, x0, y0);// (x1,y1)到点的距离
c = distance(x2, y2, x0, y0);// (x2,y2)到点的距离
if (c <= 0.000001 || b <= 0.000001) {
space = 0;
return space;
}
if (a <= 0.000001) {
space = b;
return space;
}
if (c * c >= a * a + b * b) {
space = b;
return space;
}
if (b * b >= a * a + c * c) {
space = c;
return space;
}
float p = (a + b + c) / 2;// 半周长
float s = (float) Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海伦公式求面积
space = 2 * s / a;// 返回点到线的距离(利用三角形面积公式求高)
return space;
}
/**
* 求x0是否在正方形内
* @param x0
* @param y0
* @param x1
* @param y1
* @return
*/
public static boolean isPointInSquare(float x0, float y0, float[] x1, float[] y1) {
if (x1.length != y1.length) {
return false;
}
boolean left = false;
boolean right = false;
boolean top = false;
boolean bottom = false;
for (int i = 0; i < y1.length; i++) {
if (pointInQuadrant(x0, y0, x1[i], y1[i]) == 7) {
return true;
}
if (pointInQuadrant(x0, y0, x1[i], y1[i]) == 3 || pointInQuadrant(x0, y0, x1[i], y1[i]) == 4
|| pointInQuadrant(x0, y0, x1[i], y1[i]) == -5) {
left = true;
} else if (pointInQuadrant(x0, y0, x1[i], y1[i]) == 1 || pointInQuadrant(x0, y0, x1[i], y1[i]) == 2
|| pointInQuadrant(x0, y0, x1[i], y1[i]) == 5) {
right = true;
}
if (pointInQuadrant(x0, y0, x1[i], y1[i]) == 1 || pointInQuadrant(x0, y0, x1[i], y1[i]) == 4
|| pointInQuadrant(x0, y0, x1[i], y1[i]) == -6) {
top = true;
} else if (pointInQuadrant(x0, y0, x1[i], y1[i]) == 3 || pointInQuadrant(x0, y0, x1[i], y1[i]) == 2
|| pointInQuadrant(x0, y0, x1[i], y1[i]) == 6) {
bottom = true;
}
}
if ((left && right) && (top && bottom)) {
return true;
}
return false;
}
/**
* X1在X0的第几象限
* @param x0
* @param y0
* @param x1
* @param y1
* @return -5左边 5右边 -6上边 6下面 7中点
*/
public static int pointInQuadrant(float x0, float y0, float x1, float y1) {
int code = 0;
if (x0 > x1) {
if (y0 > y1) {
code = 4;
} else if (y0 < y1) {
code = 3;
} else {
code = -5;
}
} else if (x0 < x1) {
if (y0 > y1) {
code = 1;
} else if (y0 < y1) {
code = 2;
} else {
code = 5;
}
} else {
if (y0 > y1) {
code = -6;
} else if (y0 < y1) {
code = 6;
} else {
code = 7;
}
}
return code;
}
/**
* 圆到正方形的距离
* @param x0 圆中点
* @param y0
* @param x 正方形左上顶点
* @param y
* @param width 正方形宽
* @param height
* @param rotation 正方形转动角度
* @return
*/
public static int circleToSquare(float x0, float y0, float x, float y, float width, float height, float rotation) {
float centreX = x + width / 2;
float centreY = y + height / 2;
float xx[] = new float[4];
float yy[] = new float[4];
float diagonal = (float) Math.sqrt(width * width + height * height) / 2;
Coordinate coordinate = null;
coordinate = getCoordinateForCircleSix(centreX, centreY, diagonal, 135 + rotation); // 左上顶点
float x1 = coordinate.x;
float y1 = coordinate.y;
xx[0] = x1;
yy[0] = y1;
coordinate = getCoordinateForCircleSix(centreX, centreY, diagonal, 225 + rotation); // 右上顶点
float x2 = coordinate.x;
float y2 = coordinate.y;
xx[1] = x2;
yy[1] = y2;
coordinate = getCoordinateForCircleSix(centreX, centreY, diagonal, 315 + rotation); // 右下顶点
float x3 = coordinate.x;
float y3 = coordinate.y;
xx[2] = x3;
yy[2] = y3;
coordinate = getCoordinateForCircleSix(centreX, centreY, diagonal, 45 + rotation); // 左下顶点
float x4 = coordinate.x;
float y4 = coordinate.y;
xx[3] = x4;
yy[3] = y4;
float space1 = pointToLine(x0, y0, x1, y1, x2, y2);
float space2 = pointToLine(x0, y0, x1, y1, x4, y4);
float space3 = pointToLine(x0, y0, x3, y3, x2, y2);
float space4 = pointToLine(x0, y0, x3, y3, x4, y4);
float space5 = space1 < space2 ? space1 : space2;
float space6 = space3 < space4 ? space3 : space4;
float space = space5 < space6 ? space5 : space6;
if (isPointInSquare(x0, y0, xx, yy)) {
return (int) space * -1;
}
return (int) space;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public interface MathConstants {
// ===========================================================
// Constants
// ===========================================================
public static final float PI = (float) Math.PI;
public static float PI_TWICE = PI * 2.0f;
public static float PI_HALF = PI * 0.5f;
public static final float DEG_TO_RAD = PI / 180.0f;
public static final float RAD_TO_DEG = 180.0f / PI;
// ===========================================================
// Methods
// ===========================================================
}
}
3.Line和Quadrilateral:判断四边形是否相交,线段与线段是否相交
关于线段相交和四边形相交的原理:计算几何算法概览
public class Line {
public float x1, y1;//P1,Q1
public float x2, y2;//P2,Q2
public Line(float x1, float y1, float x2, float y2) {
super();
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public void setLine(float x1, float y1, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
//获取斜率
public float getSlope() {
if (x2 == x1)
return Float.NaN;
return (y2 - y1) / (x2 - x1);
}
//设点为Q,线段为P1P2 ,判断点Q在该线段上的依据是:( Q - P1 ) × ( P2 - P1 ) = 0 且 Q 在以 P1,P2为对角顶点的矩形内。
public boolean isOnline(float px, float py) {
Line QP1 = new Line(px, py, x1, y1);
Line P2P1 = new Line(x2, y2, x1, y1);
float xmin = x1 > x2 ? x2 : x1;
float xmax = x1 > x2 ? x1 : x2;
float ymin = y1 > y2 ? y2 : y1;
float ymax = y1 > y2 ? y1 : y2;
if (QP1.cross(P2P1) != 0 || xmin > px || xmax < px || ymin > py || ymax < py) {
return false;
}
return true;
}
public boolean isYMaxPoint(float py) {
return py == Math.max(y1, y2);
}
public void reverse() {
float temp = x2;
x2 = x1;
x1 = temp;
temp = y2;
y2 = y1;
y1 = temp;
}
public float cross(Line line) {
float px1 = x2 - x1;
float py1 = y2 - y1;
float px2 = line.x2 - line.x1;
float py2 = line.y2 - line.y1;
return px1 * py2 - px2 * py1;
}
//连个线段是否相交
public boolean intersect(Line line) {
//快速排斥试验
float xmin, xmax, ymin, ymax, xmin2, xmax2, ymin2, ymax2;
xmin = x1 > x2 ? x2 : x1;
xmax = x1 > x2 ? x1 : x2;
ymin = y1 > y2 ? y2 : y1;
ymax = y1 > y2 ? y1 : y2;
xmin2 = line.x1 > line.x2 ? line.x2 : line.x1;
xmax2 = line.x1 > line.x2 ? line.x1 : line.x2;
ymin2 = line.y1 > line.y2 ? line.y2 : line.y1;
ymax2 = line.y1 > line.y2 ? line.y1 : line.y2;
if (xmax2 < xmin || xmin2 > xmax || ymax2 < ymin || ymin2 > ymax) {
return false;
}
//跨立试验:如果两线段相交,则两线段必然相互跨立对方
//判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0
//判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0
Line P1Q1 = new Line(x1, y1, line.x1, line.y1);
Line Q2Q1 = new Line(line.x2, line.y2, line.x1, line.y1);
Line P2Q1 = new Line(x2, y2, line.x1, line.y1);
float P1P2_Q1Q2 = P1Q1.cross(Q2Q1) * Q2Q1.cross(P2Q1);
if (P1P2_Q1Q2 < 0)
return false;
Line Q1P1 = new Line(line.x1, line.y1, x1, y1);
Line P2P1 = new Line(x2, y2, x1, y1);
Line Q2P1 = new Line(line.x2, line.y2, x1, y1);
float Q1Q2_P1P2 = Q1P1.cross(P2P1) * P2P1.cross(Q2P1);
if (Q1Q2_P1P2 < 0)
return false;
return true;
}
public boolean isInQuadrilateral() {
return false;
}
}
//四边形
public class Quadrilateral {
public Line[] lines;
public Quadrilateral(Line[] lines) {
super();
this.lines = lines;
}
/**
* @Title: isInner
* @Description: 判断点P是否在多边形中是计算几何中一个非常基本但是十分重要的算法。以点P为端点,向左方作射线L,由于多边形是有界的,所以射线L的左端一定在多边形外,
* 考虑沿着L从无穷远处开始自左向右移动,遇到和多边形的第一个交点的时候,进入到了多边形的内部,遇到第二个交点的时候,离开了多边形,
* ……所以很容易看出当L和多边形的交点数目C是奇数的时候,P在多边形内,是偶数的话P在多边形外。
* @param: @param px
* @param: @param py
* @param: @return
* @return: boolean
* @throws:
*/
public boolean isInner(float px, float py) {
Line ray = new Line(Float.MIN_VALUE, py, px, py);
int count = 0;
for (Line s : lines) {
if (s.isOnline(px, py)) {
return true;
} else if (s.getSlope() != 0) {//不是水平线段
if (ray.isOnline(s.x1, s.y1) || ray.isOnline(s.x2, s.y2)) {
if ((ray.isOnline(s.x1, s.y1) && s.isYMaxPoint(s.y1))
|| (ray.isOnline(s.x2, s.y2) && s.isYMaxPoint(s.y2)))
count++;
//端点在射线上单不是两端点中纵坐标较大的端点,不对count处理
} else if (ray.intersect(s)) {//射线与边相交
count++;
}
}
}
//相交点为奇数表示在四边形内部
return count % 2 == 1;
}
}
4.根据内容自适应字体的TextView
public class FontFitTextView extends TextView {
private static final String TAG = "FontFitTextView";
private static final boolean DEBUG = false;
//Attributes
private Paint testPaint;
private float minTextSize;
private float maxTextSize;
public FontFitTextView(Context context) {
super(context);
initialise();
}
public FontFitTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialise();
}
private void initialise() {
testPaint = new Paint();
testPaint.set(this.getPaint());
//max size defaults to the intially specified text size unless it is too small
maxTextSize = this.getTextSize();
if (maxTextSize < 11) {
maxTextSize = 30;
}
minTextSize = 10;
}
/* Re size the font so the specified text fits in the text box
* assuming the text box is the specified width.
*/
private void refitText(String text, int textWidth) {
if (textWidth > 0) {
int availableWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
int availableHeight = getHeight() - this.getPaddingTop() - this.getPaddingBottom();
float trySize = maxTextSize;
testPaint.setTextSize(trySize);
FontMetrics fm = testPaint.getFontMetrics();
int fontHeight = (int) Math.ceil(fm.descent - fm.top) + 2;
while ((trySize > minTextSize) && ((testPaint.measureText(text) > availableWidth)|| fontHeight > availableHeight)) {
trySize -= 1;
if (trySize <= minTextSize) {
trySize = minTextSize;
break;
}
testPaint.setTextSize(trySize);
fm = testPaint.getFontMetrics();
fontHeight = (int) Math.ceil(fm.descent - fm.top) + 2;
}
this.setTextSize(trySize);
}
}
//获取字体高度
public int getFontHeight(float fontSize) {
Paint paint = new Paint();
paint.setTextSize(fontSize);
FontMetrics fm = paint.getFontMetrics();
return (int) Math.ceil(fm.descent - fm.top) + 2;
}
@Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
refitText(text.toString(), this.getWidth());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw) {
refitText(this.getText().toString(), w);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (DEBUG) {
Paint pt = new Paint();
pt.setColor(0x80ff0000);
pt.setStrokeWidth(5.0f);
pt.setStyle(Paint.Style.STROKE);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), pt);
}
}
//Getters and Setters
public float getMinTextSize() {
return minTextSize;
}
public void setMinTextSize(int minTextSize) {
this.minTextSize = minTextSize;
}
public float getMaxTextSize() {
return maxTextSize;
}
public void setMaxTextSize(int minTextSize) {
this.maxTextSize = minTextSize;
}
}
5.平滑滚动的ListView
/**
* A ListView that can be asked to scroll (smoothly or otherwise) to a specific position. This class
* takes advantage of similar functionality that exists in {@link ListView} and enhances it.
*/
public class AutoScrollListView extends ListView {
/**
* Position the element at about 1/3 of the list height
*/
private static final float PREFERRED_SELECTION_OFFSET_FROM_TOP = 0.33f;
private int mRequestedScrollPosition = -1;
private boolean mSmoothScrollRequested;
public AutoScrollListView(Context context) {
super(context);
}
public AutoScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Brings the specified position to view by optionally performing a jump-scroll maneuver: first
* it jumps to some position near the one requested and then does a smooth scroll to the
* requested position. This creates an impression of full smooth scrolling without actually
* traversing the entire list. If smooth scrolling is not requested, instantly positions the
* requested item at a preferred offset.
*/
public void requestPositionToScreen(int position, boolean smoothScroll) {
mRequestedScrollPosition = position;
mSmoothScrollRequested = smoothScroll;
requestLayout();
}
@Override
protected void layoutChildren() {
super.layoutChildren();
if (mRequestedScrollPosition == -1) {
return;
}
final int position = mRequestedScrollPosition;
mRequestedScrollPosition = -1;
int firstPosition = getFirstVisiblePosition() + 1;
int lastPosition = getLastVisiblePosition();
if (position >= firstPosition && position <= lastPosition) {
return; // Already on screen
}
final int offset = (int) (getHeight() * PREFERRED_SELECTION_OFFSET_FROM_TOP);
if (!mSmoothScrollRequested) {
setSelectionFromTop(position, offset);
// Since we have changed the scrolling position, we need to redo child layout
// Calling "requestLayout" in the middle of a layout pass has no effect,
// so we call layoutChildren explicitly
super.layoutChildren();
} else {
// We will first position the list a couple of screens before or after
// the new selection and then scroll smoothly to it.
int twoScreens = (lastPosition - firstPosition) * 2;
int preliminaryPosition;
if (position < firstPosition) {
preliminaryPosition = position + twoScreens;
if (preliminaryPosition >= getCount()) {
preliminaryPosition = getCount() - 1;
}
if (preliminaryPosition < firstPosition) {
setSelection(preliminaryPosition);
super.layoutChildren();
}
} else {
preliminaryPosition = position - twoScreens;
if (preliminaryPosition < 0) {
preliminaryPosition = 0;
}
if (preliminaryPosition > lastPosition) {
setSelection(preliminaryPosition);
super.layoutChildren();
}
}
smoothScrollToPositionFromTop(position, offset);
}
}
}
6.线程工具类
public class ThreadUtils {
public static final ExecutorService fixedExec = Executors
.newFixedThreadPool(5, new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable,
"ThreadUtils_fixedExec");
return thread;
}
});
private static final ScheduledExecutorService scheduExec = Executors
.newScheduledThreadPool(3, new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable,
"ThreadUtils_scheduExec");
return thread;
}
});
/**
* @Title: splitTaksk
* @Description:将线程中的一个大任务拆分成几个小任务并行执行,注意:此方法会阻塞所调用的线程
* @param: @param threadPoolsize
* @param: @param runnable
* @return: void
* @throws:
*/
public static void executeDivideTasks(List runnables) {
Object lock = new Object();
Map resultMap = new HashMap();
if (runnables != null && !runnables.isEmpty()) {
for (int i = 0; i < runnables.size(); i++) {
fixedExec.submit(new InnerRunnalbe(runnables.get(i), runnables
.size(), lock, String.valueOf(i), resultMap));
}
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* @Title: executeTask
* @Description: 向线程池提交一个任务
* @param: @param runnables
* @return: void
* @throws:
*/
public static void executeTask(Runnable... runnables) {
for (Runnable runnable : runnables) {
fixedExec.submit(runnable);
}
}
/**
* @ClassName: InnerRunnalbe
* @Description: Runnable的代理类,内部执行线程,执行完所有任务后通知释放锁
* @author: yuedong bao
* @date: 2015-7-31 上午10:55:12
*/
private static class InnerRunnalbe implements Runnable {
private final Runnable task;
private final int taskSize;
private final Object lock;
private final Map reslutMap;
private final String taskName;
public InnerRunnalbe(Runnable task, int taskSize, Object lock,
String taskName, Map reslutMap) {
super();
this.task = task;
this.taskSize = taskSize;
this.lock = lock;
this.taskName = taskName;
this.reslutMap = reslutMap;
}
@Override
public void run() {
try {
task.run();
synchronized (reslutMap) {
reslutMap.put(taskName, true);
}
} catch (Exception e) {
e.printStackTrace();
synchronized (reslutMap) {
reslutMap.put(taskName, false);
}
} finally {
if (reslutMap.size() == taskSize) {
synchronized (lock) {
lock.notify();
}
}
}
}
}
/**
* 执行一次
* @Title: addDelayTask
* @param @param autoTask
* @param @param delay
* @return void
* @throws
*/
public static void addDelayTask(AutoTask autoTask, int delayMills) {
ScheduledFuture> scheduledFuture = scheduExec.schedule(autoTask,
delayMills, TimeUnit.MILLISECONDS);
autoTask.setScheduledFuture(scheduledFuture);
}
/**
* 循环
* @Title: addRateTask
* @param @param autoTask
* @param @param period
* @return void
* @throws
*/
public static void addRateTask(AutoTask autoTask, int period) {
ScheduledFuture> scheduledFuture = scheduExec.scheduleAtFixedRate(
autoTask, 0, period, TimeUnit.MILLISECONDS);
autoTask.setScheduledFuture(scheduledFuture);
}
/**
* 延迟多久执行
* @Title: addRateTask
* @param @param autoTask
* @param @param initialDelay
* @param @param period
* @return void
* @throws
*/
public static void addRateTask(AutoTask autoTask, int initialDelay,
int period) {
ScheduledFuture> scheduledFuture = scheduExec.scheduleAtFixedRate(
autoTask, initialDelay, period, TimeUnit.MILLISECONDS);
autoTask.setScheduledFuture(scheduledFuture);
}
public static abstract class AutoTask implements Runnable {
private ScheduledFuture> scheduledFuture;
public void setScheduledFuture(ScheduledFuture> scheduledFuture) {
this.scheduledFuture = scheduledFuture;
}
public abstract void onCancel();
/**
* Returns true if this task completed. Completion may be due to normal termination, an
* exception, or cancellation -- in all of these cases, this method will return true.
* @Title: isDone
* @param @return
* @return boolean
* @throws
*/
public boolean isDone() {
if (scheduledFuture != null) {
return scheduledFuture.isDone();
}
return true;
}
public boolean isCancelled() {
if (scheduledFuture != null) {
scheduledFuture.isCancelled();
}
return true;
}
/**
* 关闭任务
* @Title: stop
* @param @param mayInterruptIfRunning true 正在执行的中断,false等待完成
* @return void
* @throws
*/
public void stop(boolean mayInterruptIfRunning) {
if (scheduledFuture != null) {
scheduledFuture.cancel(mayInterruptIfRunning);
onCancel();
}
scheduledFuture = null;
}
}
}
==============================To be continued============================