編輯:關於Android編程
1.
import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.net.Uri; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.ListAdapter; import android.widget.ListView; public class MeasureUtil { /** * 應用程序App區域寬高等尺寸獲取,最好在Activity的onWindowFocusChanged ()方法或者之後調運 */ public static Rect getAppAreaRect(Activity context) { Rect rect = new Rect(); context.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); return rect; } /** * 獲取狀態欄高度,最好在Activity的onWindowFocusChanged ()方法或者之後調運 */ public static int getStatusBarHeight(Activity context) { Rect rect = new Rect(); context.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); return rect.top; } /** * View布局區域寬高等尺寸獲取,最好在Activity的onWindowFocusChanged ()方法或者之後調運 */ public static Rect getContentViewRect(Activity context) { Rect rect = new Rect(); context.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect); return rect; } /** * 獲取狀態欄的高度 * * @param context 上下文 * @return 狀態欄高度 */ public static int getStatusBarHeight(Context context) { int result = 0; int resourceId = context.getResources().getIdentifier( "status_bar_height", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } public static int getToolbarHeight(Context context) { final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes( new int[]{R.attr.actionBarSize}); int toolbarHeight = (int) styledAttributes.getDimension(0, 0); styledAttributes.recycle(); return toolbarHeight; } /** * 可將當前view保存為圖片的工具 * * @param v * @return */ public static Bitmap createViewBitmap(View v) { Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); v.draw(canvas); return bitmap; } /** * 可將當前view保存為圖片的工具 * * @param view * @return */ public static Bitmap convertViewToBitmap(View view) { view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); return bitmap; } /** * 獲取app內部資源的uri,用於fresco設置本地圖片 * * @param resId * @param packageName * @return */ public static Uri getResourceUri(int resId, String packageName) { return Uri.parse("res://" + packageName + "/" + resId); } /** * 獲取屏幕尺寸 * * @param activity Activity * @return 屏幕尺寸像素值,下標為0的值為寬,下標為1的值為高 */ public static int[] getScreenSize(Activity activity) { DisplayMetrics metrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); return new int[]{metrics.widthPixels, metrics.heightPixels}; } public static int getScreenWidth(Activity activity) { DisplayMetrics metrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); return metrics.widthPixels; } public static int getScreenHeight(Activity activity) { DisplayMetrics metrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); return metrics.heightPixels; } /** * 根據手機的分辨率從 dp 的單位 轉成為 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根據手機的分辨率從 px(像素) 的單位 轉成為 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * 將px值轉換為sp值,保證文字大小不變 * * @param pxValue * @param context (DisplayMetrics類中屬性scaledDensity) * @return */ public static int px2sp(Context context, float pxValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); } /** * 將sp值轉換為px值,保證文字大小不變 * * @param spValue * @param context (DisplayMetrics類中屬性scaledDensity) * @return */ public static int sp2px(Context context, float spValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); } /** * 動態測量listview item的高度 * * @param listView */ public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return; } int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom(); for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); if (listItem instanceof ViewGroup) { listItem.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); } listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } /** * 動態測量listview item的高度 * * @param listView */ public static void setListViewHeightBasedOnChildren1(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.AT_MOST); int totalHeight = 0; View view = null; for (int i = 0; i < listAdapter.getCount(); i++) { view = listAdapter.getView(i, view, listView); if (i == 0) { view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT)); } view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED); totalHeight += view.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); listView.requestLayout(); } public static int[] getImageRealSize(Context context, int id) { BitmapFactory.Options options = new BitmapFactory.Options(); /** * 最關鍵在此,把options.inJustDecodeBounds = true; * 這裡再decodeFile(),返回的bitmap為空,但此時調用options.outHeight時,已經包含了圖片的高了 */ options.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), id, options); int size[] = new int[2]; size[0] = options.outWidth; size[1] = options.outHeight; return size; } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // 源圖片的高度和寬度 final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // 計算出實際寬高和目標寬高的比率 final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高 // 一定都會大於等於目標的寬和高。 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; } public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 第一次解析將inJustDecodeBounds設置為true,來獲取圖片大小 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // 調用上面定義的方法計算inSampleSize值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 使用獲取到的inSampleSize值再次解析圖片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } }
2.
import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.view.View; public class ThreePointLoadingView extends View { // 畫筆 private Paint mBallPaint; // 寬度 private int mWidth; // 高度 private int mHeight; // 圓之間的距離 private float mSpace; // 圓的半徑 private float mBallRadius; // 三個圓合起來的距離(包括間距) private float mTotalLength; // A圓心的x坐標 private float mABallX; // A圓心的y坐標 private float mABallY; // B圓心的x坐標 private float mBBallX; // B圓心的y坐標 private float mBBallY; // C圓心的x坐標 private float mCBallX; // C圓心的y坐標 private float mCBallY; // 圓心移動的距離 private float mMoveLength; // A圓心做二階貝塞爾曲線的起點、控制點、終點 private PointF mABallP0; private PointF mABallP1; private PointF mABallP2; // A圓心貝塞爾曲線運動時的坐標 private float mABallazierX; private float mABallazierY; // 值動畫 private ValueAnimator mAnimator; // 值動畫產生的x方向的偏移量 private float mOffsetX = 0; // 根據mOffsetX算得的y方向的偏移量 private float mOffsetY; // A圓的起始透明度 private int mABallAlpha = 255; // B圓的起始透明度 private int mBBallAlpha = (int) (255 * 0.8); // C圓的起始透明度 private int mCBallAlpha = (int) (255 * 0.6); public ThreePointLoadingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mBallPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); //設置顏色 mBallPaint.setColor(ContextCompat.getColor(getContext(), R.color.material_deep_orange_a200)); mBallPaint.setStyle(Paint.Style.FILL); mABallP0 = new PointF(); mABallP1 = new PointF(); mABallP2 = new PointF(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 考慮padding值 mWidth = measureSize(widthMeasureSpec, MeasureUtil.dip2px(getContext(), 180)) + getPaddingLeft() + getPaddingRight(); mHeight = measureSize(heightMeasureSpec, MeasureUtil.dip2px(getContext(), 180)) + getPaddingTop() + getPaddingBottom(); setMeasuredDimension(mWidth, mHeight); // 間距為寬度10分之一 mSpace = mWidth * 1.0f / 20; // 半徑為寬度50分之一 mBallRadius = mWidth * 1.0f / 50; // 總的長度為三個圓直徑加上之間的間距 mTotalLength = mBallRadius * 6 + mSpace * 2; // 兩個圓圓心的距離 mMoveLength = mSpace + mBallRadius * 2; // A圓心起始坐標,同時貝塞爾曲線的起始坐標也是這個 mABallazierX = mABallX = (mWidth - mTotalLength) / 2 + mBallRadius; mABallazierY = mABallY = mHeight / 2; // A圓心起始點,控制點,終點 mABallP0.set(mABallX, mABallY); mABallP1.set(mABallX + mMoveLength / 2, mABallY - mMoveLength / 2); mABallP2.set(mBBallX, mBBallY); // B圓心的起始坐標 mBBallX = (mWidth - mTotalLength) / 2 + mBallRadius * 3 + mSpace; mBBallY = mHeight / 2; // C圓心的起始坐標 mCBallX = (mWidth - mTotalLength) / 2 + mBallRadius * 5 + mSpace * 2; mCBallY = mHeight / 2; } @Override protected void onDraw(Canvas canvas) { // 根據x方向偏移量求出y方向偏移量 mOffsetY = (float) Math.sqrt(mMoveLength / 2 * mMoveLength / 2 - (mMoveLength / 2 - mOffsetX) * (mMoveLength / 2 - mOffsetX)); // 繪制B圓 mBallPaint.setAlpha(mBBallAlpha); canvas.drawCircle(mBBallX - mOffsetX, (float) (mBBallY + mOffsetY), mBallRadius, mBallPaint); // 繪制C圓 mBallPaint.setAlpha(mCBallAlpha); canvas.drawCircle(mCBallX - mOffsetX, (float) (mCBallY - mOffsetY), mBallRadius, mBallPaint); // 繪制A圓 mBallPaint.setAlpha(mABallAlpha); canvas.drawCircle(mABallazierX, mABallazierY, mBallRadius, mBallPaint); if (mAnimator == null) { // 啟動值動畫 startLoading(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); // 銷毀view時取消動畫,避免內存洩露 mAnimator.cancel(); } // 開啟值動畫 private void startLoading() { // 范圍在0到圓心移動的距離,這個是以B圓到A圓位置為基准的 mAnimator = ValueAnimator.ofFloat(0, mMoveLength); // 設置監聽 mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // B圓和C圓對應的X的偏移量 mOffsetX = (float) animation.getAnimatedValue(); float fraction = animation.getAnimatedFraction(); // B移動到A,透明度變化255*0.8->255 mBBallAlpha = (int) (255 * 0.8 + 255 * fraction * 0.2); // C移動到B,透明度變化255*0.6->255*0.8 mCBallAlpha = (int) (255 * 0.6 + 255 * fraction * 0.2); // A移動到C,透明度變化255->255*0.6 mABallAlpha = (int) (255 - 255 * fraction * 0.4); // A圓的分段二階貝塞爾曲線的處理 if (fraction < 0.5) { // fraction小於0.5時,為A到B過程的情況 // 乘以2是因為貝塞爾公式的t范圍在0到1 fraction *= 2; // 設置當前情況的起始點、控制點、終點 mABallP0.set(mABallX, mABallY); mABallP1.set(mABallX + mMoveLength / 2, mABallY - mMoveLength / 2); mABallP2.set(mBBallX, mBBallY); // 代入貝塞爾公式得到貝塞爾曲線過程的x,y坐標 mABallazierX = getBazierValue(fraction, mABallP0.x, mABallP1.x, mABallP2.x); mABallazierY = getBazierValue(fraction, mABallP0.y, mABallP1.y, mABallP2.y); } else { // fraction大於等於0.5時,為A到B過程之後,再從B到C過程的情況 // 減0.5是因為t要從0開始變化 fraction -= 0.5; // 乘以2是因為貝塞爾公式的t范圍在0到1 fraction *= 2; // 設置當前情況的起始點、控制點、終點 mABallP0.set(mBBallX, mBBallY); mABallP1.set(mBBallX + mMoveLength / 2, mBBallY + mMoveLength / 2); mABallP2.set(mCBallX, mCBallY); // 代入貝塞爾公式得到貝塞爾曲線過程的x,y坐標 mABallazierX = getBazierValue(fraction, mABallP0.x, mABallP1.x, mABallP2.x); mABallazierY = getBazierValue(fraction, mABallP0.y, mABallP1.y, mABallP2.y); } // 強制刷新 postInvalidate(); } }); // 動畫無限模式 mAnimator.setRepeatCount(ValueAnimator.INFINITE); // 時長1秒 mAnimator.setDuration(1000); // 延遲0.5秒執行 mAnimator.setStartDelay(500); // 開啟動畫 mAnimator.start(); } /** * 二階貝塞爾公式:B(t)=(1-t)^2*P0+2*t*(1-t)*P1+t^2*P2,(t∈[0,1]) */ private float getBazierValue(float fraction, float p0, float p1, float p2) { return (1 - fraction) * (1 - fraction) * p0 + 2 * fraction * (1 - fraction) * p1 + fraction * fraction * p2; } // 測量尺寸 private int measureSize(int measureSpec, int defaultSize) { final int mode = MeasureSpec.getMode(measureSpec); final int size = MeasureSpec.getSize(measureSpec); if (mode == MeasureSpec.EXACTLY) { return size; } else if (mode == MeasureSpec.AT_MOST) { return Math.min(size, defaultSize); } return size; } }
3.main.xml
4.Maintivity
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
5效果圖:
第一步:代碼混淆(注意引入的第三方jar)在新版本的ADT創建項目時,混碼的文件不再是proguard.cfg,而是project.properties和proguard
第1節 Activity的使用Activity幾乎是每個應用必有的組件,所以任何安卓應用的開發幾乎都是從Activity開始的。比如,你希望設計一個計算器應用,要呈現這個
我不知道大家有沒有這樣問題,項目做多了,就容易忽略最最基礎的知識,其實我也是在最近發現了自己也存在這樣的問題。因此打算做一些最基礎的知識的調研來重新學習和回顧這些容易被忽
異步任務 AsyncTask使用 android中實現異步機制主要有Thread加Handler和AsyncTask,今天主要記錄一下A