1. 程式人生 > >仿淘寶物流彈框

仿淘寶物流彈框

兩種實現效果:
第一種是背景是透明度的:
ViewPager+TabLayout +fragment是在一個dialog形式的Activity上的
Dialogactivity的佈局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="@drawable/transparent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:layout_marginTop="23dp"
        android:background="@drawable/transparent"
        android:gravity="center_vertical">

        <android.support.v4.view.ViewPager
            android:id="@+id/vp_address_dialog"
            android:layout_width="match_parent"
            android:layout_height="match_parent">


            <android.support.design.widget.TabLayout
                android:id="@+id/tb_address_dialog"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/transparent"
                app:tabGravity="center"
                app:tabIndicatorHeight="0dp" />

        </android.support.v4.view.ViewPager>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="20dp"
            android:background="@drawable/transparent"
            android:gravity="center"
            android:text="檢視全部"
            android:textColor="#fff"
            android:textSize="14sp" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/ll_close"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        android:layout_marginBottom="20dp"
        android:layout_marginTop="10dp"
        android:background="@color/transparent"
        android:gravity="center">

        <ImageView
            android:id="@+id/close"
            android:layout_width="51dp"
            android:layout_height="51dp"
            android:layout_gravity="center"
            android:background="@drawable/g_close" />
    </LinearLayout>
</LinearLayout>

//tou透明度DialogAddressActivity 
public class DialogAddressActivity extends FragmentActivity {

    @BindView(R.id.tb_address_dialog)
    TabLayout tbAddressDialog;
    @BindView(R.id.vp_address_dialog)
    ViewPager vpAddressDialog;
    ArrayList<Fragment> list;
    MyAdapter myAdapter;
    @BindView(R.id.ll_close)
    LinearLayout llClose;
    private int ONE_ALPHE = 10;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialog_address);
        ButterKnife.bind(this);
//        getWindow().setLayout(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT);
        //頁面,資料來源
        list = new ArrayList<>();
        list.add(new FirstAddressFragment());
        list.add(new FirstAddressFragment());
        myAdapter = new MyAdapter(getSupportFragmentManager());
        vpAddressDialog.setAdapter(myAdapter);
        //繫結
        tbAddressDialog.setupWithViewPager(vpAddressDialog);

        for (int i = 0; i < myAdapter.getCount(); i++) {
            TabLayout.Tab tab = tbAddressDialog.getTabAt(i);//獲得每一個tab
            tab.setCustomView(R.layout.tab_item_dialog_address);//給每一個tab設定view
            if (i == 0) {
                // 設定第一個tab的TextView是被選擇的樣式
                ImageView imageView = tab.getCustomView().findViewById(R.id.iv_indicator);
                imageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.viewpager2));
                imageView.setSelected(true);

            } else {
                //其他的灰色
                ImageView imageView = tab.getCustomView().findViewById(R.id.iv_indicator);
                imageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.viewpager3));
                imageView.setSelected(false);
            }


            tbAddressDialog.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                @Override
                public void onTabSelected(TabLayout.Tab tab) {
                    ImageView imageView = tab.getCustomView().findViewById(R.id.iv_indicator);
                    imageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.viewpager2));
                    imageView.setSelected(true);
                    vpAddressDialog.setCurrentItem(tab.getPosition());
                }

                @Override
                public void onTabUnselected(TabLayout.Tab tab) {
                    ImageView imageView = tab.getCustomView().findViewById(R.id.iv_indicator);
                    imageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.viewpager3));
                    imageView.setSelected(false);

                }

                @Override
                public void onTabReselected(TabLayout.Tab tab) {

                }
            });
        }
        llClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }


    class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return list.get(position);
        }

        @Override
        public int getCount() {
            return list.size();
        }
    }
}

  <activity
            android:name=".mime.service.activity.DialogAddressActivity"
            android:theme="@style/transcutestyle" />
 <style name="Dialog_Fullscreen" parent="Theme.AppCompat">
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>
    <!--dialog的activity全屏-->
    <style name="transcutestyle" parent="Dialog_Fullscreen">
        <item name="android:windowFrame">@android:color/transparent</item><!--邊框-->
        <item name="android:windowIsFloating">true</item><!--是否浮現在activity之上-->
        <item name="android:windowIsTranslucent">true</item><!--半透明-->
        <item name="android:windowNoTitle">true</item><!--無標題-->
        <item name="android:windowBackground">@android:color/transparent</item><!--背景透明-->
        <item name="android:backgroundDimAmount">0.3</item>
        <item name="android:windowAnimationStyle">@null</item>
    </style>

第二種是截圖高斯模糊的背景

 new BlurPopWin.Builder(this).setContent("該配合你演出的我,眼視而不見,在比一個最愛你的人即興表演")
                        //Radius越大耗時越長,被圖片處理影象越模糊
                        .setRadius(3).setTitle("已到達")
                        //設定居中還是底部顯示
                        .setshowAtLocationType(0)
                        .setShowCloseButton(true)
                        .setOutSideClickable(false)
                        .SetLogisticsDataList(logisticsDataList)
                        .onphoneclock(new BlurPopWin.OnPhoneClickListener() {
                            @Override
                            public void onphoneclock(String phoneNumber) {
//                                dialogCreateCall(phoneNumber);
                                //實現撥打電話的操作
                                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"
                                        + phoneNumber));
                                if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)
                                        != PackageManager.PERMISSION_GRANTED) {
                                    return;
                                }
                                startActivity(intent);
                            }
                        })
//                       .onClick(new BlurPopWin.PopupCallback() {
//                            @Override
//                            public void onClick(@NonNull BlurPopWin blurPopWin) {
//                                Toast.makeText(mContext, "中間被點了", Toast.LENGTH_SHORT).show();
//                                //跳轉詳情頁
//                                Intent intent = new Intent(mContext, AddressInfoActivity.class);
//                                mContext.startActivity(intent);
//
//
//                                blurPopWin.dismiss();
//                            }
//                        })
                        .show(view);

這是帶高斯模糊背景的Popwindow ,其中關於高斯模糊的演算法就不列出來了,demo中有

public class BlurPopWin {
    private RelativeLayout pop_root_layout;
    private CardView pop_layout;
    private TextView title;
    private TextView content;
    private ImageView close;
    private Builder builder;
    private PopupWindow popupWindow;
    private int radius;
    private float touchY;
    private Bitmap localBit;

    public static final String GRAVITY_BOTTOM = "BOTTOM";
    public static final String GRAVITY_CENTER = "CENTER";
    private LogisticsInformationView logistics_InformationView;

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public BlurPopWin(Builder builder) {
        this.builder = builder;
        builder.blurPopWin = initBlurPopWin(builder);
    }

    @UiThread
    public void show(View view) {
        builder.blurPopWin.popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
    }

    @UiThread
    public void dismiss() {
        if (builder != null && builder.blurPopWin != null)
            builder.blurPopWin.popupWindow.dismiss();
    }

    /*
    擷取螢幕
    * */
    @Nullable
    private Bitmap getIerceptionScreen() {
        // View是你需要截圖的View
        View view = builder.activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap b = view.getDrawingCache();

        // 獲取狀態列高度
        Rect frame = new Rect();
        builder.activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;

        // 獲取螢幕長和高
        int width = builder.activity.getWindowManager().getDefaultDisplay().getWidth();
        int height = builder.activity.getWindowManager().getDefaultDisplay()
                .getHeight();
        // 去掉標題欄
        // Bitmap b = Bitmap.createBitmap(b1, 0, 25, 320, 455);
        Bitmap bitmap = Bitmap.createBitmap(b, 0, statusBarHeight, width, height
                - statusBarHeight);
        view.destroyDrawingCache();
        bitmap = FastBlur.fastBlur(bitmap, radius);
        if (bitmap != null) {
            return bitmap;
        } else {
            return null;
        }
    }

    /*
    初始化
    * */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @UiThread
    private BlurPopWin initBlurPopWin(final Builder builder) {
        if (builder != null) {

            View rootView = builder.activity.getLayoutInflater().inflate(R.layout.pop_layout, null, false);
            popupWindow = new PopupWindow(rootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);
            pop_layout = (CardView) rootView.findViewById(R.id.pop_layout);
            pop_root_layout = (RelativeLayout) rootView.findViewById(R.id.pop_root_layout);
            title = (TextView) rootView.findViewById(R.id.title);
            content = (TextView) rootView.findViewById(R.id.content);
            close = (ImageView) rootView.findViewById(R.id.close);
            logistics_InformationView = rootView.findViewById(R.id.logistics_InformationView);

            if (builder.logisticsDataList != null) {
                logistics_InformationView.setLogisticsDataList(builder.logisticsDataList);

            }

//標題
            if (builder.title != null) {
                title.setText(builder.title);
            }

            if (builder.content != null) {
                content.setText(builder.content);
            }
//圓角
            if (builder.radius != 0) {
                radius = builder.radius;
            } else {
                radius = 5;
            }
//字號
            if (builder.titleTextSize != 0) {
                title.setTextSize(builder.titleTextSize);
            }

            if (builder.contentTextSize != 0) {
                content.setTextSize(builder.contentTextSize);
            }
//關閉
            if (builder.isShowClose) {
                close.setVisibility(View.VISIBLE);
                close.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        popupWindow.dismiss();
                    }
                });
            } else {
                close.setClickable(false);
                close.setVisibility(View.INVISIBLE);
            }
//顯示位置
            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            if (builder.showAtLocationType.equals(GRAVITY_CENTER)) {
                lp.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
            } else {
                lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
            }
            pop_layout.setLayoutParams(lp);
//截圖
            if (localBit == null) {
                localBit = getIerceptionScreen();
            }

            pop_root_layout.setBackground(new BitmapDrawable(localBit));

            pop_root_layout.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    switch (motionEvent.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            touchY = motionEvent.getY();
                            break;
                        case MotionEvent.ACTION_MOVE:
                            break;
                        case MotionEvent.ACTION_UP:

                            if (builder.isBackgroundClose) {
                                if (builder.showAtLocationType.equals(GRAVITY_CENTER)) {
                                    if (touchY < pop_layout.getTop() || touchY > pop_layout.getBottom()) {
                                        popupWindow.dismiss();
                                    }
                                } else if (builder.showAtLocationType.equals(GRAVITY_BOTTOM)) {
                                    if (touchY < pop_layout.getTop()) {
                                        popupWindow.dismiss();
                                    }
                                }
                            }
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            });
        } else {
            throw new NullPointerException("---> BlurPopWin ---> initBlurPopWin --->builder=null");
        }
//        點選整個cardview
        pop_layout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (builder.popupCallback != null) {
                    builder.popupCallback.onClick(BlurPopWin.this);
                }
            }
        });

        //點選電話

        logistics_InformationView.setOnPhoneClickListener(new LogisticsInformationView.OnPhoneClickListener() {
            @Override
            public void onPhoneClick(String phoneNumber) {

                if (builder.onPhoneClickListener != null) {
//                    Tools.showToast("點選電話了");
                    builder.onPhoneClickListener.onphoneclock(phoneNumber);

                }
            }
        });


        return this;
    }

    public static class Builder {

        private ArrayList logisticsDataList;
        protected BlurPopWin blurPopWin;
        protected int titleTextSize, contentTextSize;
        protected Activity activity;
        protected Context context;
        protected PopupCallback popupCallback;
        protected OnPhoneClickListener onPhoneClickListener;
        protected int radius;
        protected String title, content;
        protected boolean isCancelable;
        //預設不顯示XX
        protected boolean isShowClose = false;
        protected boolean isBackgroundClose = true;
        protected String showAtLocationType = GRAVITY_CENTER;

        public Builder(@NonNull Context context) {
            this.activity = (Activity) context;
            this.context = context;
            this.isCancelable = true;

        }

        private void initData() {

        }

        public Builder onphoneclock(OnPhoneClickListener onPhoneClickListener) {
            this.onPhoneClickListener = onPhoneClickListener;
            return this;
        }

        public Builder onClick(PopupCallback popupCallback) {
            this.popupCallback = popupCallback;
            return this;
        }

        //設定list資料
        public Builder SetLogisticsDataList(ArrayList logisticsDataList) {
            this.logisticsDataList = logisticsDataList;
            return this;

        }

        /*
        * 設定標題
        * */
        public Builder setTitle(@StringRes int titleRes) {
            setTitle(this.context.getString(titleRes));
            return this;
        }

        //標題
        public Builder setTitle(@NonNull String title) {
            this.title = title;
            return this;
        }

        //圓角
        public Builder setRadius(int radius) {
            this.radius = radius;
            return this;
        }

        //標題字型大小
        public Builder setTitleTextSize(int size) {
            this.titleTextSize = size;
            return this;
        }

        //內容字型大小
        public Builder setContentTextSize(int size) {
            this.contentTextSize = size;
            return this;
        }

        /*
        * 設定主文內容
        * */
        public Builder setContent(@StringRes int contentRes) {
            setContent(this.context.getString(contentRes));
            return this;
        }

        /*
        * 設定主文內容
        * */
        public Builder setContent(@NonNull String content) {
            this.content = content;
            return this;
        }

        /*
        * 預設居中,手動設定了才在最下面
        * */
        public Builder setshowAtLocationType(int type) {
            if (type == 0) {
                this.showAtLocationType = GRAVITY_CENTER;
            } else if (type == 1) {
                this.showAtLocationType = GRAVITY_BOTTOM;
            }

            return this;
        }

        //是否顯示close標誌
        public Builder setShowCloseButton(@NonNull boolean flag) {
            this.isShowClose = flag;
            return this;
        }

        public Builder setOutSideClickable(@NonNull boolean flag) {
            this.isBackgroundClose = flag;
            return this;
        }

        @UiThread
        public BlurPopWin build() {
            return new BlurPopWin(this);
        }

        @UiThread
        public BlurPopWin show(View view) {
            BlurPopWin blurPopWin = build();
            blurPopWin.show(view);

            return blurPopWin;
        }

    }

    public interface PopupCallback {

        void onClick(@NonNull BlurPopWin blurPopWin);
    }

    public interface OnPhoneClickListener {
        void onphoneclock(String phoneNumber);

    }
}

這兩個方法最重要的是關於物流的那個自定義的View



/**
 * Created by Administrator on 2017/9/8.
 */

public class LogisticsInformationView extends View {

    Context context;

    /**
     * 繪製工具:畫筆
     */

    Paint paint;
    Paint mPaintPhone;
    TextPaint textPaintPhone;

    /**
     * 繪製引數
     */

    int interval;//間隔:本文中指代物流資訊和物流時間的間隔

    float radius;//圓形半徑

    int left = 40;//距離左邊邊距
    int top = 20;//距離頂部邊距(相當於XML中的Margin或者Padding效果)

    int windowWidth;//獲取螢幕的寬高,避免定義資料過長超出螢幕
    int windowHeight;

    float width;

    String phoneNumber;//電話號碼
    int phoneNumberWidth;//11位電話號碼寬度是固定的
    int phoneNumberHeight;//11位電話號碼高度是固定的

    /**
     * 繪製介面引數
     */
    List<LogisticsData> logisticsDataList;

    List<Integer> heightList;//獲取每一條文字所佔的高度,這裡預設時間就佔一行

    int heightTotal = 0;//獲取總高度,用於繪製當前介面所佔的高

    /**
     * 使用Map記錄存在電話號碼的座標用於點選事件的儲存
     * 起始座標以及截止座標的記錄
     */
    HashMap<Float, String> phoneYNumber = new HashMap<Float, String>();
    HashMap<Float, Float> stopYX = new HashMap<Float, Float>();
    List<Float> stopYList = new ArrayList<>();//用於快速取出初始化的值

    private int startColor = R.color.text_color_start;
    private int endColor = R.color.text_color_end;
    private int mViewWidth = 0;
    LinearGradient mLinearGradient;

    public LogisticsInformationView(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public LogisticsInformationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LogisticsInformationView);
        width = typedArray.getDimension(R.styleable.LogisticsInformationView_width, 20);//獲取XML中設定的高度(圓形半徑)
        radius = typedArray.getDimension(R.styleable.LogisticsInformationView_radius, 10);
        //程式在執行時維護了一個 TypedArray的池,程式呼叫時,會向該池中請求一個例項
        //用完之後,呼叫 recycle() 方法來釋放該例項,從而使其可被其他模組複用。所以一定要呼叫

        typedArray.recycle();
        init();
    }

    public LogisticsInformationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

    /**
     * 初始化相關引數
     */
    private void init() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);//用於繪製時抗鋸齒
        paint.setColor(getResources().getColor(R.color.normalColor));

        mPaintPhone = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintPhone.setColor(getResources().getColor(R.color.colorPrimaryDark));
        mPaintPhone.setTextSize(30.0F);
//電話1111字的顏色
        textPaintPhone = new TextPaint();
        textPaintPhone.setColor(getResources().getColor(R.color.colorPrimaryDark));
        textPaintPhone.setTextSize(30.0F);
        textPaintPhone.setAntiAlias(true);

//        interval = dip2px(context, 16);//間距

        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);

        windowWidth = wm.getDefaultDisplay().getWidth();
        windowHeight = wm.getDefaultDisplay().getHeight();
//設定漸變色
        mViewWidth = getMeasuredWidth();//必須呼叫了mesure方法
        //漸變色
        mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0,
                new int[]{getResources().getColor(startColor), getResources().getColor(endColor)},
                null, Shader.TileMode.REPEAT);

    }


    /**
     * 傳遞相關物流資訊物件,這裡的物件可以更改為你的自定義的物件
     */
    public void setLogisticsDataList(List<LogisticsData> logisticsDataList) {
        this.logisticsDataList = logisticsDataList;

        heightList = new ArrayList<>();
        TextPaint textPaint = new TextPaint();
        textPaint.setTextSize(35.0F);

        //獲取模擬電話寬度資料
        StaticLayout phoneLayout = new StaticLayout("15555555555", textPaint, (int) (windowWidth * 0.8), ALIGN_NORMAL, 1.0F, 0.0F, true);
        phoneNumberWidth = (int) phoneLayout.getLineWidth(0);
        phoneNumberHeight = phoneLayout.getHeight();
        //計算每行字元所佔的高度
        for (int i = 0; i < logisticsDataList.size(); i++) {
            StaticLayout layout = new StaticLayout((logisticsDataList.get(i)).getContext() + "", textPaint,
                    (int) (windowWidth * 0.8), ALIGN_NORMAL, 1.0F, 0.0F, true);
            heightList.add(layout.getHeight());
            heightTotal = heightTotal + layout.getHeight() + interval + (i == 1 ? top : top * 2);//獲取總共高度
        }
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (logisticsDataList == null || logisticsDataList.size() == 0)
            return;

        List data = logisticsDataList;
        canvas.drawRect(left * 2, top, width + left * 2, heightTotal + top, paint);
        Paint mPaint = new Paint();
        TextPaint textPaint1 = new TextPaint();
        for (int i = 0; i < logisticsDataList.size(); i++) {
            if (i == 0) {
                mPaint.setAntiAlias(true);
                mPaint.setColor(getResources().getColor(R.color.checkColor));
                mPaint.setTextSize(30);
                TextPaint datePaint = new TextPaint();
                datePaint.setColor(getResources().getColor(R.color.checkColor));
                datePaint.setTextSize(20);
                datePaint.setAntiAlias(true);
                datePaint.measureText(((LogisticsData) data.get(i)).getDate());

                TextPaint texttimePaint = new TextPaint();
                texttimePaint.setColor(getResources().getColor(R.color.checkColor));
                texttimePaint.setTextSize(20);
                texttimePaint.setAntiAlias(true);
                texttimePaint.measureText(((LogisticsData) data.get(i)).getTime());
                canvas.drawText(((LogisticsData) data.get(i)).getDate() + "", 5, top + 32, datePaint);
                canvas.drawText(((LogisticsData) data.get(i)).getTime() + "", 5, top + 8, texttimePaint);

                TextPaint textPaint = new TextPaint();
                textPaint.setColor(getResources().getColor(R.color.checkColor));
                textPaint.setTextSize(30.0F);
                textPaint.setAntiAlias(true);


                mPaint.setShader(mLinearGradient);
                canvas.drawCircle(width / 2 + left * 2, top + 5, radius * 2 + 2, mPaint);

                textPaint1.setColor(getResources().getColor(R.color.white));
                textPaint1.setTextSize(26);
                textPaint1.setAntiAlias(true);
                textPaint1.measureText("收");
                canvas.drawText("收", left * 2 - 12, top + 14, textPaint1);
                String[] splitData = splitString(((LogisticsData) data.get(i)).getContext() + "");
                if (splitData != null) {
                    splitPhoneData(splitData, canvas, textPaint, 0, true);
                } else {
                    StaticLayout layout = new StaticLayout(((LogisticsData) data.get(i)).getContext() + "", textPaint,
                            (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);
                    canvas.save();
                    canvas.translate(left * 2 + radius * 2 + 10, 0);
                    layout.draw(canvas);
                    canvas.restore();
                }
            } else {
                int heightData = 0;
                for (int j = 0; j < i; j++) {
                    heightData = heightData + heightList.get(j) + interval + (j == 0 ? top : top * 2);
                }
                paint.setColor(getResources().getColor(R.color.normalColor));
                canvas.drawCircle(width / 2 + left * 2, heightData + 44, radius * 2 + 2, mPaint);
                canvas.drawText("運", +left * 2 - 10, heightData + 44 + 8, textPaint1);

                paint.setTextSize(30);
                TextPaint datePaint = new TextPaint();
                datePaint.setColor(getResources().getColor(R.color.normalColor));
                datePaint.setTextSize(20);
                datePaint.setAntiAlias(true);
                datePaint.measureText(((LogisticsData) data.get(i)).getDate());

                TextPaint texttimePaint = new TextPaint();
                texttimePaint.setColor(getResources().getColor(R.color.normalColor));
                texttimePaint.setTextSize(20);
                texttimePaint.setAntiAlias(true);
                texttimePaint.measureText(((LogisticsData) data.get(i)).getTime());
                canvas.drawText(((LogisticsData) data.get(i)).getDate() + "", 5,  20 + heightData + top, datePaint);
                canvas.drawText(((LogisticsData) data.get(i)).getTime() + "", 5, 44 + heightData + top, texttimePaint);
                TextPaint textPaint = new TextPaint();
                textPaint.setColor(getResources().getColor(R.color.normalColor));
                textPaint.setTextSize(30.0F);
                textPaint.setAntiAlias(true);
                String[] splitData = splitString(((LogisticsData) data.get(i)).getContext() + "");
                if (splitData != null) {
                    splitPhoneData(splitData, canvas, textPaint, heightData, false);
                } else {
                    StaticLayout layout = new StaticLayout(((LogisticsData) data.get(i)).getContext() + "", textPaint, (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);
                    canvas.save();
                    canvas.translate(left * 2 + radius * 2 + 10, heightData + top);
                    layout.draw(canvas);
                    canvas.restore();
                }

            }
        }
    }

    //onmesure方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //當沒有資料的時候截斷繪製過程,當set資料進來的時候還是會走這裡繪製圖形
        if (logisticsDataList == null || logisticsDataList.size() == 0)
            return;
        //這裡繪製所需的寬高
        setMeasuredDimension(widthMeasureSpec, heightTotal + top);
    }


    /**
     * 根據手機的解析度從 dp 的單位 轉成為 px(畫素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public String[] splitString(String data) {
        String initData = getPhoneNumber(data);
        phoneNumber = initData;
        if (initData != null) {
            //說明有電話號碼,進行資料分割,預設每一段content中最多包含一個手機號碼
            String[] splitData = data.split(initData);
            return splitData;
        }
        //沒有電話號碼就返回null
        return null;
    }


    /**
     * 獲取字串中是否包含11位的手機號碼
     */
    public String getPhoneNumber(String numer) {
        char[] temp = numer.toCharArray();
        String value = "";
        int licz = 0;

        for (int i = 0; i < temp.length; i++) {
            if (licz < 11) {
                if (Character.toString(temp[i]).matches("[0-9]")) {
                    value += Character.toString(temp[i]);
                    licz++;
                } else if (Character.toString(temp[i]).matches("\u0020|\\-|\\(|\\)")) {

                } else {
                    value = "";
                    licz = 0;
                }
            }
        }

        if (value.length() != 11) {
            value = null;
        } else {
            value = value.trim();
        }
//        LogUtil.e("手機號碼=" + value);
        return value;
    }

    /**
     * 邏輯操作電話號碼變色可點
     */
    public void splitPhoneData(String[] splitData, Canvas canvas, TextPaint textPaint, int heightData, boolean isTop) {
        StaticLayout layoutPhone = new StaticLayout(phoneNumber, textPaintPhone, (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);

        //1.首先繪製電話前段的資料
        StaticLayout layout = new StaticLayout(splitData[0], textPaint, (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);
        int layoutFirst = layout.getHeight();
        canvas.save();//很重要,不然會樣式出錯
        canvas.translate(left * 2 + radius * 2 + 10, heightData + (isTop ? 0 : top));
        layout.draw(canvas);
        canvas.restore();//重置

        //判斷擷取端是多少
        if (splitData.length <= 1) {
            //沒有後續
            //2.判斷是剩下的寬度是否能夠容納手機號碼寬度
            if ((int) (windowWidth * 0.7) - layout.getLineWidth(layout.getLineCount() - 1) > phoneNumberWidth) {
                phoneYNumber.put((float) (heightData + (isTop ? -10 : 10) + layoutPhone.getHeight()), phoneNumber);
                stopYX.put((float) (heightData + (isTop ? -10 : 10) + layoutPhone.getHeight()), left * 2 + radius * 2 + 10 + (layout.getLineWidth(layout.getLineCount() - 1)) + phoneNumberWidth);
                stopYList.add((float) (heightData + (isTop ? -10 : 10) + layoutPhone.getHeight()));
                mPaintPhone.setColor(getResources().getColor(R.color.colorPrimaryDark));
                canvas.drawText(phoneNumber, left * 2 + radius * 2 + 10 + (layout.getLineWidth(layout.getLineCount() - 1)), layoutFirst + heightData + (isTop ? -10 : 10), mPaintPhone);
            } else {
                phoneYNumber.put((float) (layoutFirst + heightData + (isTop ? 0 : top) + layoutPhone.getHeight()), phoneNumber);
                stopYX.put((float) (layoutFirst + heightData + (isTop ? 0 : top) + layoutPhone.getHeight()), left * 2 + radius * 2 + 10 + phoneNumberWidth);
                stopYList.add((float) (layoutFirst + heightData + (isTop ? 0 : top) + layoutPhone.getHeight()));
                //5.1獲取之前的高度
                canvas.save();//很重要,不然會樣式出錯
                canvas.translate(left * 2 + radius * 2 + 10, layoutFirst + heightData + (isTop ? 0 : top));
                layoutPhone.draw(canvas);
                canvas.restore();//重置
            }
        } else {
            //有後續
            //獲取最後一段的寬度
            StaticLayout layoutLast = new StaticLayout(splitData[1], textPaint, (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);

            //2.判斷是剩下的寬度是否能夠容納手機號碼寬度
            if ((int) (windowWidth * 0.7) - layout.getLineWidth(layout.getLineCount() - 1) > phoneNumberWidth) {
                //3.1.如果是可以容納的情況
                //記錄Map座標軸資料
                phoneYNumber.put((float) (heightData + (isTop ? -10 : 10) + layoutPhone.getHeight()), phoneNumber);
                stopYX.put((float) (heightData + (isTop ? -10 : 10) + layoutPhone.getHeight()), left * 2 + radius * 2 + 10 + (layout.getLineWidth(layout.getLineCount() - 1)) + phoneNumberWidth);
                stopYList.add((float) (heightData + (isTop ? -10 : 10) + layoutPhone.getHeight()));
                mPaintPhone.setColor(getResources().getColor(R.color.colorPrimaryDark));
                canvas.drawText(phoneNumber, left * 2 + radius * 2 + 10 + (layout.getLineWidth(layout.getLineCount() - 1)), layoutFirst + heightData + (isTop ? -10 : 10), mPaintPhone);
                if ((int) (windowWidth * 0.7) - layout.getLineWidth(layout.getLineCount() - 1) - phoneNumberWidth > layoutLast.getLineWidth(0)) {
                    //4.1.如果一行就可以繪製完成
                    mPaintPhone.setColor(getResources().getColor(isTop ? R.color.checkColor : R.color.normalColor));

                    canvas.drawText(splitData[1], left * 2 + radius * 2 + 10 + (layout.getLineWidth(layout.getLineCount() - 1) + phoneNumberWidth), layoutFirst + heightData + (isTop ? -10 : 10), mPaintPhone);
                } else {
                    //4.2.一行不可以完成的情況下繼續分割成兩份,一份是drawText拼接到最後,一份是StaticLayout另起一行繪製
                    double percentLast = (((int) (windowWidth * 0.7) - layout.getLineWidth(layout.getLineCount() - 1) - phoneNumberWidth));
                    //獲取字元能顯示的最大Length
                    double maxLength = percentLast / 30.0F;//這裡的35.0是一箇中文字型的大小
                    String lastStringPre = splitData[1].substring(0, (int) maxLength + 1);//獲取最大資料的長度的字串拼接
                    String lastStringLas = splitData[1].substring((int) maxLength + 1);
                    mPaintPhone.setColor(getResources().getColor(isTop ? R.color.checkColor : R.color.normalColor));
                    canvas.drawText(lastStringPre, left * 2 + radius * 2 + 10 + (layout.getLineWidth(layout.getLineCount() - 1) + phoneNumberWidth), layoutFirst + heightData + (isTop ? -10 : 10), mPaintPhone);

                    //另起一行寫剩餘的資料

                    StaticLayout layoutlastString = new StaticLayout(lastStringLas, textPaint, (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);
                    canvas.save();//很重要,不然會樣式出錯
                    canvas.translate(left * 2 + radius * 2 + 10, layoutFirst + heightData + (isTop ? 0 : top));
                    layoutlastString.draw(canvas);
                    canvas.restore();//重置
                }
            } else {
                //3.2.如果是不可以容納的情況,現在預設電話號碼不可以容納的情況就另起一行使用StaticLayout繪製
                phoneYNumber.put((float) (layoutFirst + heightData + (isTop ? 0 : top) + layoutPhone.getHeight()), phoneNumber);
                stopYX.put((float) (layoutFirst + heightData + (isTop ? 0 : top) + layoutPhone.getHeight()), left * 2 + radius * 2 + 10 + phoneNumberWidth);
                stopYList.add((float) (layoutFirst + heightData + (isTop ? 0 : top) + layoutPhone.getHeight()));
                //5.1獲取之前的高度
                canvas.save();//很重要,不然會樣式出錯
                canvas.translate(left * 2 + radius * 2 + 10, layoutFirst + heightData + (isTop ? 0 : top));
                layoutPhone.draw(canvas);
                canvas.restore();//重置
                if ((int) (windowWidth * 0.7) - phoneNumberWidth > layoutLast.getLineWidth(0)) {
                    //4.1.如果一行就可以繪製完成
                    canvas.drawText(splitData[1], left * 2 + radius * 2 + 10 + phoneNumberWidth, layoutPhone.getHeight() + layoutFirst + heightData + (isTop ? -10 : 10), mPaintPhone);
                } else {
                    //4.2.一行不可以完成的情況下繼續分割成兩份,一份是drawText拼接到最後,一份是StaticLayout另起一行繪製
                    double percentLast = (int) (windowWidth * 0.7) - phoneNumberWidth;
                    //獲取字元能顯示的最大Length
                    double maxLength = percentLast / 30.0F;//這裡的35.0是一箇中文字型的大小

                    String lastStringPre = splitData[1].substring(0, (int) maxLength + 1);//獲取最大資料的長度的字串拼接
                    String lastStringLas = splitData[1].substring((int) maxLength + 1);
                    mPaintPhone.setColor(getResources().getColor(isTop ? R.color.checkColor : R.color.normalColor));
                    canvas.drawText(lastStringPre, left * 2 + radius * 2 + 10 + phoneNumberWidth, layoutPhone.getHeight() + layoutFirst + heightData + (isTop ? -10 : 10), mPaintPhone);

                    //另起一行寫剩餘的資料

                    StaticLayout layoutlastString = new StaticLayout(lastStringLas, textPaint, (int) (windowWidth * 0.7), ALIGN_NORMAL, 1.0F, 0.0F, true);
                    canvas.save();//很重要,不然會樣式出錯
                    canvas.translate(left * 2 + radius * 2 + 10, layoutPhone.getHeight() + layoutFirst + heightData + (isTop ? 0 : top));
                    layoutlastString.draw(canvas);
                    canvas.restore();//重置
                }
            }

        }
    }


    /**
     * 實現電話號碼的點選事件
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //按下(這裡預設點選一下就彈出Dialog樣式)
                float x = event.getX();
                float y = event.getY();
                //判斷點選的範圍型別
                for (int i = 0; i < stopYList.size(); i++) {
                    if (y < stopYList.get(i) && (stopYList.get(i) - y) <= phoneNumberHeight
                            && x < stopYX.get(stopYList.get(i)) && (stopYX.get(stopYList.get(i)) - x) <= phoneNumberWidth) {
                        //成立,獲取X軸的相關資訊
                        if (mOnPhoneClickListener != null) {
                            mOnPhoneClickListener.onPhoneClick(phoneYNumber.get(stopYList.get(i)));
                        }

                        break;
                    }
                }

                break;
            case MotionEvent.ACTION_UP:
                //擡起
                break;
            case MotionEvent.ACTION_MOVE:
                //取消
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }


        return super.onTouchEvent(event);
    }

    /**
     * 提供介面
     */
    private OnPhoneClickListener mOnPhoneClickListener;

    public interface OnPhoneClickListener {
        void onPhoneClick(String phoneNumber);
    }

    public void setOnPhoneClickListener(OnPhoneClickListener l) {
        mOnPhoneClickListener = l;
    }

}

相關推薦

仿寶物流彈

兩種實現效果: 第一種是背景是透明度的: ViewPager+TabLayout +fragment是在一個dialog形式的Activity上的 Dialogactivity的佈局: <?xml version="1.0" encoding="utf-

Javascript:仿寶搜尋使用者輸入事件的實現

開啟淘寶網首頁,找到淘寶首頁的搜尋框,大家可以看到,當頁面一開啟,搜尋框中就可以看到灰色字型“少女高跟鞋”,還有閃爍的游標。當用戶點選輸入的時候,灰色字消失。當用戶清空文字框的所有內容的時候,灰色字自動恢復。 接下來,這個小案例就是要介紹如何實現這種效果,即使用者輸入事件。 判斷使用者輸入的事件有 oni

獲取物流資訊並動態展示(仿寶物流資訊)

最終效果如圖 前端程式碼如下 <div class="track-rcol">             <divclass="track-list">       

仿寶物流時間線的實現

物流時間線是根據物流狀態改變而改變的一種動態效果。 貼張圖: 下面看一下自定義的View: 第一步: //初始化引數 private void init(AttributeSet attrs) { TypedArray typedArray = getConte

仿寶物流資訊控制元件

——–商女不知亡國恨 隔江猶唱後庭花 先看下效果吧 在自定義一個控制元件前,我們一定要先想好自己怎麼可以實現它,當然這是廢話…..不過我是心血來潮的那種,大多都沒有成功。。唉,學的還遠遠不夠啊。做這個之前我是想過的,我一開始是想繼承ViewGro

Javascript小案例(一):仿寶搜尋使用者輸入事件的實現

淘寶是我們經常用的一個網上購物平臺,開啟淘寶網首頁,找到淘寶首頁的搜尋框,如下如所示: (截圖日期:2017年6月18日) 大家可以看到,當頁面一開啟,搜尋框中就可以看到灰色字型“少女高跟鞋”,還有閃爍的游標。當用戶點選輸入的時候,灰色字消失。當用戶清空

仿寶頁面的搜索引擎,點擊輸入文字不消失

arch 大堆 urn images ace src func 國際 lan 1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8

轉::iOS 仿寶,上拉進入詳情頁面

skin memory 增加 方法 fin goto elf jsb gis 今天做的主要是一個模仿淘寶,上拉進入商品詳情的功能,主要是通過 tableView 與 webView 一起來實現的,當然也可根據自己的需要把 webView 替換成你想要的 1 //

android軟件開發之仿寶選擇規格的實現

per con attribute back view.gone boolean 做了 over ear 在一些app開發項目中選擇商品規格這個功能最容易遇到問題,想要實現需要的全部功能,但一直沒有成功,所以就去找了個Demo,學習界面UI采用recyclerview,it

Android 輕松實現仿寶地區選擇

mod sin ted animator ogre selected height failure time 代碼地址如下:<br>http://www.demodashi.com/demo/11122.html 一、準備工作 Android開發環境,學習An

SSH框架實現仿寶購物demo

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

使用原生js實現仿寶放大鏡效果

放大鏡實現步驟 1.獲取元素 2.實現滑鼠移上時顯示小方塊 和大圖 3.再新增中圖的移動事件 獲取滑鼠的座標付給小方塊 注意必須座標還要減去小方塊的寬高的一半 讓游標在中間顯示 4.實現大圖同比例的顯示 原理:游標移動的座標/大圖移動的座標=中圖的寬度/大圖的寬度 求的是大圖

Android仿ios底部彈,支援傳入list集合,任意配置個數

不說廢話,一看程式碼誰都懂。   public class BottomDialog { private Context context; private Dialog dialog; private TextView txt_title; p

popupWindow詳解和仿微信彈例項

1、介紹 (1)使用PopupWindow可實現彈出視窗效果,,其實和AlertDialog一樣,也是一種對話方塊,兩者也經常混用,但是也各有特點。 AlertDialog是非阻塞式對話方塊:AlertDialog彈出時,後臺還可以做事情;而PopupWindow是阻塞式對話方塊:Pop

仿寶商品放大鏡效果

效果圖:     原始碼: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title>

仿寶、京東、美團使用ViewPager+GridView實現左右滑動檢視更多分類導航功能

文章說明 本文修改自開發者原始碼 微信公共號:China-dvlp 如果你有想學習的文章直接關注公眾號(開發者原始碼)回覆,我會整理徵稿。如果你有好的文章想和大家分享歡迎投稿,直接向我回覆文章連結即可。 概 述 仿淘寶、京東、美團使用ViewPage

Android開發仿寶商品詳情瀏覽效果 兩步曲

效果圖: 第一步佈局檔案: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/andr

仿寶的商品詳情拖動,ViewPager和ScrollView WebView的滑動衝突

仿淘寶的商品詳情拖動遇到的問題。 使用結構就是DirectionalViewPager 嵌套了(1)ScrollView (2)WebView 情況: 豎直方向的ViewPager DirectionalViewPager 嵌套了(1)ScrollView (2)WebView 出現滑動衝突

java B2B2C springmvc mybatis仿寶電子商城系統-Spring Cloud Ribbon

Spring Cloud Ribbon是一個基於HTTP和TCP的客戶端負載均衡工具,它基於Netflix Ribbon實現。通過Spring Cloud的封裝,可以讓我們輕鬆地將面向服務的REST模版請求自動轉換成客戶端負載均衡的服務呼叫。 願意瞭解原始碼的朋友直接求求交流分享技術:二一四

Android仿寶底部圖示導航欄

       在上一篇中,簡單的使用透明主題的Activity實現了仿微信右側頂部的對話方塊,上午又花了兩個小時研究了一下淘寶底部的導航欄實現,網上的做法也有很多,今天我就使用一種通過基本控制元件加上佈局的方式,沒有任何的自定義風格,控制元件等來實現,還是老樣子,先看一下效果