仿淘寶物流彈框
兩種實現效果:
第一種是背景是透明度的:
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實現了仿微信右側頂部的對話方塊,上午又花了兩個小時研究了一下淘寶底部的導航欄實現,網上的做法也有很多,今天我就使用一種通過基本控制元件加上佈局的方式,沒有任何的自定義風格,控制元件等來實現,還是老樣子,先看一下效果