編輯:關於Android編程
Git上看到的一個蠻清爽的一個Dialog介紹給大家。
實現效果
個人感覺做的還是滿Q彈的
如何使用?
compile 'com.github.michaelye.easydialog:easydialog:1.0'
其實也就是一個類和幾個layout文件,建議直接copy進你的項目還更方便點。
項目結構:
因為標注的很清晰,直接就貼代碼看,不做什麼解釋了,如有什麼不理解可以留言可以回答你的問題
核心類EasyDialog
public class EasyDialog
{
private Context context;
/**
* 內容在三角形上面
*/
public static final int GRAVITY_TOP = 0;
/**
* 內容在三角形下面
*/
public static final int GRAVITY_BOTTOM = 1;
/**
* 對話框本身
*/
private Dialog dialog;
/**
* 坐標
*/
private int[] location;
/**
* 提醒框位置
*/
private int gravity;
/**
* 外面傳遞進來的View
*/
private View contentView;
/**
* 三角形
*/
private ImageView ivTriangle;
/**
* 用來放外面傳遞進來的View
*/
private LinearLayout llContent;
/**
* 觸摸外面,是否關閉對話框
*/
private boolean touchOutsideDismiss;
/**
* 提示框所在的容器
*/
private RelativeLayout rlOutsideBackground;
public EasyDialog(Context context)
{
initDialog(context);
}
private void initDialog(final Context context)
{
this.context = context;
LayoutInflater layoutInflater = ((Activity) context).getLayoutInflater();
View dialogView = layoutInflater.inflate(R.layout.layout_dialog, null);
ViewTreeObserver viewTreeObserver = dialogView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
@Override
public void onGlobalLayout()
{
//當View可以獲取寬高的時候,設置view的位置
relocation(location);
}
});
rlOutsideBackground = (RelativeLayout) dialogView.findViewById(R.id.rlOutsideBackground);
rlOutsideBackground.setOnTouchListener(new View.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (touchOutsideDismiss && dialog != null)
{
onDialogDismiss();
}
return false;
}
});
ivTriangle = (ImageView) dialogView.findViewById(R.id.ivTriangle);
llContent = (LinearLayout) dialogView.findViewById(R.id.llContent);
dialog = new Dialog(context, isFullScreen() ? android.R.style.Theme_Translucent_NoTitleBar_Fullscreen : android.R.style.Theme_Translucent_NoTitleBar);
dialog.setContentView(dialogView);
animatorSetForDialogShow = new AnimatorSet();
animatorSetForDialogDismiss = new AnimatorSet();
objectAnimatorsForDialogShow = new ArrayList<>();
objectAnimatorsForDialogDismiss = new ArrayList<>();
ini();
}
/**
* 初始化默認值
*/
private void ini()
{
this.setLocation(new int[]{0, 0})
.setGravity(GRAVITY_BOTTOM)
.setTouchOutsideDismiss(true)
.setOutsideColor(Color.TRANSPARENT)
.setBackgroundColor(Color.BLUE)
.setMatchParent(true)
.setMarginLeftAndRight(24, 24);
}
/**
* 設置提示框中要顯示的內容
*/
public EasyDialog setLayout(View layout)
{
if (layout != null)
{
this.contentView = layout;
}
return this;
}
/**
* 設置提示框中要顯示的內容的布局Id
*/
public EasyDialog setLayoutResourceId(int layoutResourceId)
{
View view = ((Activity) context).getLayoutInflater().inflate(layoutResourceId, null);
setLayout(view);
return this;
}
/**
* 設置三角形所在的位置
*/
public EasyDialog setLocation(int[] location)
{
this.location = location;
return this;
}
/**
* 設置三角形所在的位置
* location.x坐標值為attachedView所在屏幕位置的中心
* location.y坐標值依據當前的gravity,如果gravity是top,則為控件上方的y值,如果是bottom,則為控件的下方的y值
*
* * @param attachedView 在哪個View顯示提示信息 */ public EasyDialog setLocationByAttachedView(View attachedView) { if (attachedView != null) { this.attachedView = attachedView; int[] attachedViewLocation = new int[2]; attachedView.getLocationOnScreen(attachedViewLocation); attachedViewLocation[0] = attachedViewLocation[0] + attachedView.getWidth() / 2; switch (gravity) { case GRAVITY_BOTTOM: attachedViewLocation[1] = attachedViewLocation[1] + attachedView.getHeight(); break; case GRAVITY_TOP: break; } setLocation(attachedViewLocation); } return this; } /** * 對話框所依附的View * */ private View attachedView = null; /** * 設置顯示的內容在上方還是下方,如果設置錯誤,默認是在下方 */ public EasyDialog setGravity(int gravity) { if (gravity != GRAVITY_BOTTOM && gravity != GRAVITY_TOP) { gravity = GRAVITY_BOTTOM; } this.gravity = gravity; switch (this.gravity) { case GRAVITY_BOTTOM: ivTriangle.setBackgroundResource(R.drawable.triangle_bottom); break; case GRAVITY_TOP: ivTriangle.setBackgroundResource(R.drawable.triangle_top); break; } llContent.setBackgroundResource(R.drawable.round_corner_bg); if(attachedView != null)//如果用戶調用setGravity()之前就調用過setLocationByAttachedView,需要再調用一次setLocationByAttachedView { this.setLocationByAttachedView(attachedView); } this.setBackgroundColor(backgroundColor); return this; } /** * 設置是否填充屏幕,如果不填充就適應布局內容的寬度,顯示內容的位置會盡量隨著三角形的位置居中 */ public EasyDialog setMatchParent(boolean matchParent) { ViewGroup.LayoutParams layoutParams = llContent.getLayoutParams(); layoutParams.width = matchParent ? ViewGroup.LayoutParams.MATCH_PARENT : ViewGroup.LayoutParams.WRAP_CONTENT; llContent.setLayoutParams(layoutParams); return this; } /** * 距離屏幕左右的邊距 */ public EasyDialog setMarginLeftAndRight(int left, int right) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) llContent.getLayoutParams(); layoutParams.setMargins(left, 0, right, 0); llContent.setLayoutParams(layoutParams); return this; } /** * 設置觸摸對話框外面,對話框是否消失 */ public EasyDialog setTouchOutsideDismiss(boolean touchOutsideDismiss) { this.touchOutsideDismiss = touchOutsideDismiss; return this; } /** * 設置提醒框外部區域的顏色 */ public EasyDialog setOutsideColor(int color) { rlOutsideBackground.setBackgroundColor(color); return this; } private int backgroundColor; /** * 設置對話框的顏色 *
* 三角形的圖片是layer-list裡面嵌套一個RotateDrawable,在設置顏色的時候需要特別處理 * http://stackoverflow.com/questions/24492000/set-color-of-triangle-on-run-time * http://stackoverflow.com/questions/16636412/change-shape-solid-color-at-runtime-inside-drawable-xml-used-as-background */ public EasyDialog setBackgroundColor(int color) { backgroundColor = color; LayerDrawable drawableTriangle = (LayerDrawable) ivTriangle.getBackground(); GradientDrawable shapeTriangle = (GradientDrawable) (((RotateDrawable) drawableTriangle.findDrawableByLayerId(R.id.shape_id)).getDrawable()); if (shapeTriangle != null) { shapeTriangle.setColor(color); } else { Toast.makeText(context, shape is null, Toast.LENGTH_SHORT).show(); } GradientDrawable drawableRound = (GradientDrawable) llContent.getBackground(); if (drawableRound != null) { drawableRound.setColor(color); } return this; } /** * 顯示提示框 */ public EasyDialog show() { if (dialog != null) { if (contentView == null) { throw new RuntimeException(您是否未調用setLayout()或者setLayoutResourceId()方法來設置要顯示的內容呢?); } llContent.addView(contentView); dialog.show(); onDialogShowing(); } return this; } /** * 顯示對話框的View的parent,如果想自己寫動畫,可以獲取這個實例來寫動畫 * * */ public View getTipViewInstance() { return rlOutsideBackground.findViewById(R.id.rlParentForAnimate); } /**橫向*/ public static final int DIRECTION_X = 0; /**縱向*/ public static final int DIRECTION_Y = 1; /** * 水平動畫 * * @param direction 動畫的方向 * @param duration 動畫執行的時間長度 * @param values 動畫移動的位置 * */ public EasyDialog setAnimationTranslationShow(int direction, int duration, float... values) { return setAnimationTranslation(true, direction, duration, values); } /** * 水平動畫 * * @param direction 動畫的方向 * @param duration 動畫執行的時間長度 * @param values 動畫移動的位置 * */ public EasyDialog setAnimationTranslationDismiss(int direction, int duration, float... values) { return setAnimationTranslation(false, direction, duration, values); } private EasyDialog setAnimationTranslation(boolean isShow, int direction, int duration, float... values) { if(direction != DIRECTION_X && direction != DIRECTION_Y) { direction = DIRECTION_X; } String propertyName = ; switch (direction) { case DIRECTION_X: propertyName = translationX; break; case DIRECTION_Y: propertyName = translationY; break; } ObjectAnimator animator = ObjectAnimator.ofFloat(rlOutsideBackground.findViewById(R.id.rlParentForAnimate), propertyName, values) .setDuration(duration); if(isShow) { objectAnimatorsForDialogShow.add(animator); } else { objectAnimatorsForDialogDismiss.add(animator); } return this; } /** * 對話框出現時候的漸變動畫 * * @param duration 動畫執行的時間長度 * @param values 動畫移動的位置 * */ public EasyDialog setAnimationAlphaShow(int duration, float... values) { return setAnimationAlpha(true, duration, values); } /** * 對話框消失時候的漸變動畫 * * @param duration 動畫執行的時間長度 * @param values 動畫移動的位置 * */ public EasyDialog setAnimationAlphaDismiss(int duration, float... values) { return setAnimationAlpha(false, duration, values); } private EasyDialog setAnimationAlpha(boolean isShow, int duration, float... values) { ObjectAnimator animator = ObjectAnimator.ofFloat(rlOutsideBackground.findViewById(R.id.rlParentForAnimate), alpha, values).setDuration(duration); if(isShow) { objectAnimatorsForDialogShow.add(animator); } else { objectAnimatorsForDialogDismiss.add(animator); } return this; } private AnimatorSet animatorSetForDialogShow; private AnimatorSet animatorSetForDialogDismiss; private List objectAnimatorsForDialogShow; private List objectAnimatorsForDialogDismiss; private void onDialogShowing() { if(animatorSetForDialogShow != null && objectAnimatorsForDialogShow != null && objectAnimatorsForDialogShow.size() > 0) { animatorSetForDialogShow.playTogether(objectAnimatorsForDialogShow); animatorSetForDialogShow.start(); } //TODO 縮放的動畫效果不好,不能從控件所在的位置開始縮放 // ObjectAnimator.ofFloat(rlOutsideBackground.findViewById(R.id.rlParentForAnimate), scaleX, 0.3f, 1.0f).setDuration(500).start(); // ObjectAnimator.ofFloat(rlOutsideBackground.findViewById(R.id.rlParentForAnimate), scaleY, 0.3f, 1.0f).setDuration(500).start(); } private void onDialogDismiss() { if(animatorSetForDialogDismiss.isRunning()) { return; } if(animatorSetForDialogDismiss != null && objectAnimatorsForDialogDismiss != null && objectAnimatorsForDialogDismiss.size() > 0) { animatorSetForDialogDismiss.playTogether(objectAnimatorsForDialogDismiss); animatorSetForDialogDismiss.start(); animatorSetForDialogDismiss.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { dialog.dismiss(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); } else { dialog.dismiss(); } } /** * 關閉提示框 */ public void dismiss() { if (dialog != null && dialog.isShowing()) { onDialogDismiss(); } } /** * 根據x,y,重新設置控件的位置 *
* 因為setX setY為0的時候,都是在狀態欄以下的,所以app不是全屏的話,需要扣掉狀態欄的高度 */ private void relocation(int[] location) { ivTriangle.setX(location[0] - ivTriangle.getWidth() / 2); ivTriangle.setY(location[1] - ivTriangle.getHeight() / 2 - (isFullScreen() ? 0.0f : getStatusBarHeight()));//因為三角形是通過XML繪制出來的,可以到activity_tip_overlay.xml中把三角形的那個ImageView背景設置一下,就知道什麼情況了。所以需要減掉一半的高度 switch (gravity) { case GRAVITY_BOTTOM: llContent.setY(location[1] - ivTriangle.getHeight() / 2 - (isFullScreen() ? 0.0f : getStatusBarHeight()) + ivTriangle.getHeight()); break; case GRAVITY_TOP: llContent.setY(location[1] - llContent.getHeight() - (isFullScreen() ? 0.0f : getStatusBarHeight()) - ivTriangle.getHeight() / 2); break; } //顯示內容的區域往三角形靠攏 int triangleCenterX = (int)(ivTriangle.getX() + ivTriangle.getWidth()/2);//三角形的中心點 int contentWidth = llContent.getWidth(); int rightMargin = getScreenWidth() - triangleCenterX;//三角形中心距離屏幕右邊的距離 int leftMargin = getScreenWidth() - rightMargin;//三角形中心距離屏幕左邊的距離 RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) llContent.getLayoutParams(); int availableLeftMargin = leftMargin - layoutParams.leftMargin;//左邊可用的距離 int availableRightMargin = rightMargin - layoutParams.rightMargin;//右邊可用的距離 int x = 0; if(contentWidth/2 <= availableLeftMargin && contentWidth/2 <= availableRightMargin)//左右兩邊有足夠的距離 { x = triangleCenterX - contentWidth/2; } else { if(availableLeftMargin <= availableRightMargin)//判斷三角形在屏幕中心的左邊 { x = layoutParams.leftMargin; } else//三角形在屏幕中心的右邊 { x = getScreenWidth() - (contentWidth + layoutParams.rightMargin); } } llContent.setX(x); } /** * 獲取屏幕的寬度 * */ private int getScreenWidth() { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return metrics.widthPixels; } /** * 獲取狀態欄的高度 */ private int getStatusBarHeight() { int result = 0; int resourceId = context.getResources().getIdentifier(status_bar_height, dimen, android); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } /** * 判斷下當前要顯示對話框的Activity是否是全屏 */ public boolean isFullScreen() { int flg = ((Activity) context).getWindow().getAttributes().flags; boolean flag = false; if ((flg & 1024) == 1024) { flag = true; } return flag; } /** * 設置是否可以按返回按鈕取消 * */ public EasyDialog setCancelable(boolean cancelable) { dialog.setCancelable(cancelable); return this; } }
MainActivity
public class MainActivity extends ActionBarActivity implements View.OnClickListener
{
private RelativeLayout rlBackground;
private Button btnTopLeft;
private Button btnTopRight;
private Button btnMiddleTop;
private Button btnMiddleBottom;
private Button btnBottomLeft;
private Button btnBottomRight;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iniComponent();
}
private void iniComponent()
{
rlBackground = (RelativeLayout)findViewById(R.id.rlBackground);
btnTopLeft = (Button) findViewById(R.id.btnTopLeft);
btnTopRight = (Button) findViewById(R.id.btnTopRight);
btnMiddleTop = (Button) findViewById(R.id.btnMiddleTop);
btnMiddleBottom = (Button) findViewById(R.id.btnMiddleBottom);
btnBottomLeft = (Button) findViewById(R.id.btnBottomLeft);
btnBottomRight = (Button) findViewById(R.id.btnBottomRight);
btnTopLeft.setOnClickListener(this);
btnTopRight.setOnClickListener(this);
btnMiddleTop.setOnClickListener(this);
btnMiddleBottom.setOnClickListener(this);
btnBottomLeft.setOnClickListener(this);
btnBottomRight.setOnClickListener(this);
rlBackground.setOnTouchListener(new View.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
int[] location = new int[2];
location[0] = (int)event.getX();
location[1] = (int)event.getY();
location[1] = location[1] + getActionBarHeight() + getStatusBarHeight();
Toast.makeText(MainActivity.this, x: + location[0] + y: + location[1], Toast.LENGTH_SHORT).show();
new EasyDialog(MainActivity.this)
.setLayoutResourceId(R.layout.layout_tip_content_horizontal)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_black))
.setLocation(location)
.setGravity(EasyDialog.GRAVITY_TOP)
.setTouchOutsideDismiss(true)
.setMatchParent(false)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_gray))
.show();
return false;
}
});
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.btnTopLeft:
View view = this.getLayoutInflater().inflate(R.layout.layout_tip_content_horizontal, null);
new EasyDialog(MainActivity.this)
.setLayout(view)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_black))
.setLocationByAttachedView(btnTopLeft)
.setGravity(EasyDialog.GRAVITY_BOTTOM)
.setAnimationTranslationShow(EasyDialog.DIRECTION_X, 1000, -600, 100, -50, 50, 0)
.setAnimationAlphaShow(1000, 0.3f, 1.0f)
.setAnimationTranslationDismiss(EasyDialog.DIRECTION_X, 500, -50, 800)
.setAnimationAlphaDismiss(500, 1.0f, 0.0f)
.setTouchOutsideDismiss(true)
.setMatchParent(true)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_trans))
.show();
break;
case R.id.btnTopRight:
new EasyDialog(MainActivity.this)
.setLayoutResourceId(R.layout.layout_tip_image_text)
.setGravity(EasyDialog.GRAVITY_BOTTOM)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_black))
.setLocationByAttachedView(btnTopRight)
.setAnimationTranslationShow(EasyDialog.DIRECTION_X, 350, 400, 0)
.setAnimationTranslationDismiss(EasyDialog.DIRECTION_X, 350, 0, 400)
.setTouchOutsideDismiss(true)
.setMatchParent(false)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_trans))
.show();
break;
case R.id.btnMiddleTop:
new EasyDialog(MainActivity.this)
.setLayoutResourceId(R.layout.layout_tip_content_horizontal)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_blue))
.setLocationByAttachedView(btnMiddleTop)
.setAnimationTranslationShow(EasyDialog.DIRECTION_Y, 1000, -800, 100, -50, 50, 0)
.setAnimationTranslationDismiss(EasyDialog.DIRECTION_Y, 500, 0, -800)
.setGravity(EasyDialog.GRAVITY_TOP)
.setTouchOutsideDismiss(true)
.setMatchParent(false)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_pink))
.show();
break;
case R.id.btnMiddleBottom:
new EasyDialog(MainActivity.this)
.setLayoutResourceId(R.layout.layout_tip_content_horizontal)
.setGravity(EasyDialog.GRAVITY_BOTTOM)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_brown))
.setLocationByAttachedView(btnMiddleBottom)
.setAnimationTranslationShow(EasyDialog.DIRECTION_Y, 1000, 800, -100, -50, 50, 0)
.setAnimationTranslationDismiss(EasyDialog.DIRECTION_Y, 500, 0, 800)
.setAnimationAlphaShow(1000, 0.3f, 1.0f)
.setTouchOutsideDismiss(true)
.setMatchParent(true)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_gray))
.show();
break;
case R.id.btnBottomLeft:
new EasyDialog(MainActivity.this)
.setLayoutResourceId(R.layout.layout_tip_text)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_pink))
.setLocationByAttachedView(btnBottomLeft)
.setGravity(EasyDialog.GRAVITY_TOP)
.setAnimationAlphaShow(600, 0.0f, 1.0f)
.setAnimationAlphaDismiss(600, 1.0f, 0.0f)
.setTouchOutsideDismiss(true)
.setMatchParent(false)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_trans))
.show();
break;
case R.id.btnBottomRight:
new EasyDialog(MainActivity.this)
.setLayoutResourceId(R.layout.layout_tip_image_text)
.setBackgroundColor(MainActivity.this.getResources().getColor(R.color.background_color_yellow))
.setLocationByAttachedView(btnBottomRight)
.setGravity(EasyDialog.GRAVITY_TOP)
.setAnimationTranslationShow(EasyDialog.DIRECTION_X, 300, 400, 0)
.setAnimationTranslationShow(EasyDialog.DIRECTION_Y, 300, 400, 0)
.setAnimationTranslationDismiss(EasyDialog.DIRECTION_X, 300, 0, 400)
.setAnimationTranslationDismiss(EasyDialog.DIRECTION_Y, 300, 0, 400)
.setTouchOutsideDismiss(true)
.setMatchParent(false)
.setMarginLeftAndRight(24, 24)
.setOutsideColor(MainActivity.this.getResources().getColor(R.color.outside_color_trans))
.show();
break;
}
}
private int getStatusBarHeight()
{
int result = 0;
int resourceId = this.getResources().getIdentifier(status_bar_height, dimen, android);
if (resourceId > 0)
{
result = this.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
private int getActionBarHeight()
{
return this.getSupportActionBar().getHeight();
}
}
布局文件:
具體的東西可以直接看源碼,直接可以RUN並沒有什麼 問題
Android的apk文件越來越大了這已經是一個不爭的事實。在Android 還是最初版本的時候,一個app的apk文件大小也還只有2 MB左右,到了現在,
首先看下效果圖布局文件:<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
前言:最近在開發中發現了一個比較嚴重的問題,當我們將應用按home鍵放入後台運行,一段時間後,當我們再次打開應用的時候,十有八九會出現一個NullPointExcepti
手勢有三個主要特征:手型,方向,運動軌跡一個基於視覺手勢識別系統的構成應包括:圖像的采集,預處理,特征提取和選擇,分類器的設計,以及手勢識別。其流程大致如下:上面識別過程