Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 仿UC浏覽器三點加載效果

Android 仿UC浏覽器三點加載效果

編輯:關於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效果圖:

這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved