@TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { mText = new TextView(context); mText.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); addView(mText, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); mAction = new Button(context); mAction.setBackgroundResource(0); mAction.setGravity(Gravity.CENTER); mAction.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { if (mActionClickListener != null) mActionClickListener.onActionClick(SnackBar.this, mActionId); dismiss(); } }); addView(mAction, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); mBackground = new BackgroundDrawable(); ViewUtil.setBackground(this, mBackground); setClickable(true); applyStyle(context, attrs, defStyleAttr, defStyleRes); }
public void applyStyle(int resId) { ViewUtil.applyStyle(this, resId); applyStyle(getContext(), null, 0, resId); }
private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { setWillNotDraw(false); mRippleManager.onCreate(this, context, attrs, defStyleAttr, defStyleRes); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ContactView, defStyleAttr, defStyleRes); mAvatarSize = a.getDimensionPixelSize( R.styleable.ContactView_cv_avatarSize, ThemeUtil.dpToPx(context, 40)); mSpacing = a.getDimensionPixelOffset(R.styleable.ContactView_cv_spacing, ThemeUtil.dpToPx(context, 8)); mMinHeight = a.getDimensionPixelOffset(R.styleable.ContactView_android_minHeight, 0); int avatarSrc = a.getResourceId(R.styleable.ContactView_cv_avatarSrc, 0); mNameView = new TextView(context); mNameView.setGravity(GravityCompat.START); mNameView.setSingleLine(true); mNameView.setEllipsize(TextUtils.TruncateAt.END); int nameTextSize = a.getDimensionPixelSize(R.styleable.ContactView_cv_nameTextSize, 0); ColorStateList nameTextColor = a.getColorStateList(R.styleable.ContactView_cv_nameTextColor); int nameTextAppearance = a.getResourceId(R.styleable.ContactView_cv_nameTextAppearance, 0); if (nameTextAppearance > 0) mNameView.setTextAppearance(context, nameTextAppearance); if (nameTextSize > 0) mNameView.setTextSize(TypedValue.COMPLEX_UNIT_PX, nameTextSize); if (nameTextColor != null) mNameView.setTextColor(nameTextColor); setNameText(a.getString(R.styleable.ContactView_cv_name)); mAddressView = new TextView(context); mAddressView.setGravity(GravityCompat.START); mAddressView.setSingleLine(true); mAddressView.setEllipsize(TextUtils.TruncateAt.END); int addressTextSize = a.getDimensionPixelSize(R.styleable.ContactView_cv_addressTextSize, 0); ColorStateList addressTextColor = a.getColorStateList(R.styleable.ContactView_cv_addressTextColor); int addressTextAppearance = a.getResourceId(R.styleable.ContactView_cv_addressTextAppearance, 0); if (addressTextAppearance > 0) mAddressView.setTextAppearance(context, addressTextAppearance); if (addressTextSize > 0) mAddressView.setTextSize(TypedValue.COMPLEX_UNIT_PX, addressTextSize); if (addressTextColor != null) mAddressView.setTextColor(addressTextColor); setAddressText(a.getString(R.styleable.ContactView_cv_address)); mButtonSize = a.getDimensionPixelOffset(R.styleable.ContactView_cv_buttonSize, 0); if (mButtonSize > 0) { mButton = new ImageButton(context); int resId = a.getResourceId(R.styleable.ContactView_cv_buttonSrc, 0); if (resId != 0) mButton.setImageResource(resId); ViewUtil.setBackground(mButton, BlankDrawable.getInstance()); mButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); mButton.setFocusableInTouchMode(false); mButton.setFocusable(false); mButton.setClickable(false); } a.recycle(); addView(mNameView); addView(mAddressView); if (mButton != null) addView(mButton); mAvatarDrawable = new AvatarDrawable(); if (avatarSrc != 0) setAvatarResource(avatarSrc); }
/** * Set the style of RippleEffect of the ActionButton. * * @param resId The resourceId of RippleEffect. * @return This SnackBar for chaining methods. */ public SnackBar actionRipple(int resId) { if (resId != 0) ViewUtil.setBackground(mAction, new RippleDrawable.Builder(getContext(), resId).build()); return this; }
/** Created by Rey on 12/10/2014. */ public class Dialog extends android.app.Dialog { private ContainerFrameLayout mContainer; private int mLayoutWidth; private int mLayoutHeight; protected TextView mTitle; protected Button mPositiveAction; protected Button mNegativeAction; protected Button mNeutralAction; private View mContent; private DialogCardView mCardView; protected int mContentPadding; protected int mActionHeight; protected int mActionOuterHeight; protected int mActionOuterPadding; protected int mActionMinWidth; protected int mActionPadding; protected int mDialogHorizontalPadding; protected int mDialogVerticalPadding; protected int mInAnimationId; protected int mOutAnimationId; private final Handler mHandler = new Handler(); private final Runnable mDismissAction = new Runnable() { public void run() { // dirty fix for java.lang.IllegalArgumentException: View not attached to window manager try { Dialog.super.dismiss(); } catch (IllegalArgumentException ex) { } } }; private boolean mLayoutActionVertical = false; private boolean mCancelable = true; private boolean mCanceledOnTouchOutside = true; public static final int ACTION_POSITIVE = ViewUtil.generateViewId(); public static final int ACTION_NEGATIVE = ViewUtil.generateViewId(); public static final int ACTION_NEUTRAL = ViewUtil.generateViewId(); public Dialog(Context context) { this(context, R.style.Material_App_Dialog_Light); } public Dialog(Context context, int style) { super(context, style); // Override style to ensure not show window's title or background. // TODO: find a way to ensure windowIsFloating attribute is false. requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setBackgroundDrawable(BlankDrawable.getInstance()); getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); init(context, style); } private void init(Context context, int style) { mContentPadding = ThemeUtil.dpToPx(context, 24); mActionMinWidth = ThemeUtil.dpToPx(context, 64); mActionHeight = ThemeUtil.dpToPx(context, 36); mActionOuterHeight = ThemeUtil.dpToPx(context, 48); mActionPadding = ThemeUtil.dpToPx(context, 8); mActionOuterPadding = ThemeUtil.dpToPx(context, 16); mDialogHorizontalPadding = ThemeUtil.dpToPx(context, 40); mDialogVerticalPadding = ThemeUtil.dpToPx(context, 24); mCardView = new DialogCardView(context); mContainer = new ContainerFrameLayout(context); mTitle = new TextView(context); mPositiveAction = new Button(context); mNegativeAction = new Button(context); mNeutralAction = new Button(context); mCardView.setPreventCornerOverlap(false); mCardView.setUseCompatPadding(true); mTitle.setPadding( mContentPadding, mContentPadding, mContentPadding, mContentPadding - mActionPadding); mPositiveAction.setId(ACTION_POSITIVE); mPositiveAction.setPadding(mActionPadding, 0, mActionPadding, 0); mPositiveAction.setBackgroundResource(0); mNegativeAction.setId(ACTION_NEGATIVE); mNegativeAction.setPadding(mActionPadding, 0, mActionPadding, 0); mNegativeAction.setBackgroundResource(0); mNeutralAction.setId(ACTION_NEUTRAL); mNeutralAction.setPadding(mActionPadding, 0, mActionPadding, 0); mNeutralAction.setBackgroundResource(0); mContainer.addView(mCardView); mCardView.addView(mTitle); mCardView.addView(mPositiveAction); mCardView.addView(mNegativeAction); mCardView.addView(mNeutralAction); cancelable(true); canceledOnTouchOutside(true); clearContent(); onCreate(); applyStyle(style); super.setContentView(mContainer); } protected void onCreate() {} public Dialog applyStyle(int resId) { Context context = getContext(); TypedArray a = context.obtainStyledAttributes(resId, R.styleable.Dialog); int layout_width; int layout_height; if (ThemeUtil.getType(a, R.styleable.Dialog_android_layout_width) == TypedValue.TYPE_DIMENSION) layout_width = a.getDimensionPixelSize(R.styleable.Dialog_android_layout_width, 0); else layout_width = a.getInteger( R.styleable.Dialog_android_layout_width, ViewGroup.LayoutParams.WRAP_CONTENT); if (ThemeUtil.getType(a, R.styleable.Dialog_android_layout_height) == TypedValue.TYPE_DIMENSION) layout_height = a.getDimensionPixelSize(R.styleable.Dialog_android_layout_height, 0); else layout_height = a.getInteger( R.styleable.Dialog_android_layout_height, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams(layout_width, layout_height); dimAmount(a.getFloat(R.styleable.Dialog_di_dimAmount, 0.5f)); backgroundColor( a.getColor( R.styleable.Dialog_di_backgroundColor, ThemeUtil.windowBackground(context, 0xFFFFFFFF))); maxElevation(a.getDimensionPixelOffset(R.styleable.Dialog_di_maxElevation, 0)); elevation( a.getDimensionPixelOffset(R.styleable.Dialog_di_elevation, ThemeUtil.dpToPx(context, 4))); cornerRadius( a.getDimensionPixelOffset( R.styleable.Dialog_di_cornerRadius, ThemeUtil.dpToPx(context, 2))); titleTextAppearance( a.getResourceId( R.styleable.Dialog_di_titleTextAppearance, R.style.TextAppearance_AppCompat_Title)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_titleTextColor) != TypedValue.TYPE_NULL) titleColor(a.getColor(R.styleable.Dialog_di_titleTextColor, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_actionBackground) != TypedValue.TYPE_NULL) actionBackground(a.getResourceId(R.styleable.Dialog_di_actionBackground, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_actionRipple) != TypedValue.TYPE_NULL) actionRipple(a.getResourceId(R.styleable.Dialog_di_actionRipple, 0)); actionTextAppearance( a.getResourceId( R.styleable.Dialog_di_actionTextAppearance, R.style.TextAppearance_AppCompat_Button)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_actionTextColor) != TypedValue.TYPE_NULL) actionTextColor(a.getColorStateList(R.styleable.Dialog_di_actionTextColor)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_positiveActionBackground) != TypedValue.TYPE_NULL) positiveActionBackground(a.getResourceId(R.styleable.Dialog_di_positiveActionBackground, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_positiveActionRipple) != TypedValue.TYPE_NULL) positiveActionRipple(a.getResourceId(R.styleable.Dialog_di_positiveActionRipple, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_positiveActionTextAppearance) != TypedValue.TYPE_NULL) positiveActionTextAppearance( a.getResourceId(R.styleable.Dialog_di_positiveActionTextAppearance, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_positiveActionTextColor) != TypedValue.TYPE_NULL) positiveActionTextColor(a.getColorStateList(R.styleable.Dialog_di_positiveActionTextColor)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_negativeActionBackground) != TypedValue.TYPE_NULL) negativeActionBackground(a.getResourceId(R.styleable.Dialog_di_negativeActionBackground, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_negativeActionRipple) != TypedValue.TYPE_NULL) negativeActionRipple(a.getResourceId(R.styleable.Dialog_di_negativeActionRipple, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_negativeActionTextAppearance) != TypedValue.TYPE_NULL) negativeActionTextAppearance( a.getResourceId(R.styleable.Dialog_di_negativeActionTextAppearance, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_negativeActionTextColor) != TypedValue.TYPE_NULL) negativeActionTextColor(a.getColorStateList(R.styleable.Dialog_di_negativeActionTextColor)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_neutralActionBackground) != TypedValue.TYPE_NULL) neutralActionBackground(a.getResourceId(R.styleable.Dialog_di_neutralActionBackground, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_neutralActionRipple) != TypedValue.TYPE_NULL) neutralActionRipple(a.getResourceId(R.styleable.Dialog_di_neutralActionRipple, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_neutralActionTextAppearance) != TypedValue.TYPE_NULL) neutralActionTextAppearance( a.getResourceId(R.styleable.Dialog_di_neutralActionTextAppearance, 0)); if (ThemeUtil.getType(a, R.styleable.Dialog_di_neutralActionTextColor) != TypedValue.TYPE_NULL) neutralActionTextColor(a.getColorStateList(R.styleable.Dialog_di_neutralActionTextColor)); inAnimation(a.getResourceId(R.styleable.Dialog_di_inAnimation, 0)); outAnimation(a.getResourceId(R.styleable.Dialog_di_outAnimation, 0)); dividerColor(a.getColor(R.styleable.Dialog_di_dividerColor, 0x1E000000)); dividerHeight( a.getDimensionPixelOffset( R.styleable.Dialog_di_dividerHeight, ThemeUtil.dpToPx(context, 1))); setCancelable(a.getBoolean(R.styleable.Dialog_di_cancelable, true)); setCanceledOnTouchOutside(a.getBoolean(R.styleable.Dialog_di_canceledOnTouchOutside, true)); a.recycle(); return this; } public Dialog clearContent() { title(0); positiveAction(0); positiveActionClickListener(null); negativeAction(0); negativeActionClickListener(null); neutralAction(0); neutralActionClickListener(null); contentView(null); return this; } public Dialog layoutParams(int width, int height) { mLayoutWidth = width; mLayoutHeight = height; return this; } public Dialog dimAmount(float amount) { Window window = getWindow(); if (amount > 0f) { window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); WindowManager.LayoutParams lp = window.getAttributes(); lp.dimAmount = amount; window.setAttributes(lp); } else window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); return this; } public Dialog backgroundColor(int color) { mCardView.setCardBackgroundColor(color); return this; } public Dialog elevation(float radius) { if (mCardView.getMaxCardElevation() < radius) mCardView.setMaxCardElevation(radius); mCardView.setCardElevation(radius); return this; } public Dialog maxElevation(float radius) { mCardView.setMaxCardElevation(radius); return this; } public Dialog cornerRadius(float radius) { mCardView.setRadius(radius); return this; } public Dialog dividerColor(int color) { mCardView.setDividerColor(color); return this; } public Dialog dividerHeight(int height) { mCardView.setDividerHeight(height); return this; } public Dialog title(CharSequence title) { mTitle.setText(title); mTitle.setVisibility(TextUtils.isEmpty(title) ? View.GONE : View.VISIBLE); return this; } public Dialog title(int id) { return title(id == 0 ? null : getContext().getResources().getString(id)); } @Override public void setTitle(CharSequence title) { title(title); } @Override public void setTitle(int titleId) { title(titleId); } public Dialog titleColor(int color) { mTitle.setTextColor(color); return this; } public Dialog titleTextAppearance(int resId) { mTitle.setTextAppearance(getContext(), resId); return this; } public Dialog actionBackground(int id) { positiveActionBackground(id); negativeActionBackground(id); neutralActionBackground(id); return this; } public Dialog actionBackground(Drawable drawable) { positiveActionBackground(drawable); negativeActionBackground(drawable); neutralActionBackground(drawable); return this; } public Dialog actionRipple(int resId) { positiveActionRipple(resId); negativeActionRipple(resId); neutralActionRipple(resId); return this; } public Dialog actionTextAppearance(int resId) { positiveActionTextAppearance(resId); negativeActionTextAppearance(resId); neutralActionTextAppearance(resId); return this; } public Dialog actionTextColor(ColorStateList color) { positiveActionTextColor(color); negativeActionTextColor(color); neutralActionTextColor(color); return this; } public Dialog actionTextColor(int color) { positiveActionTextColor(color); negativeActionTextColor(color); neutralActionTextColor(color); return this; } public Dialog positiveAction(CharSequence action) { mPositiveAction.setText(action); mPositiveAction.setVisibility(TextUtils.isEmpty(action) ? View.GONE : View.VISIBLE); return this; } public Dialog positiveAction(int id) { return positiveAction(id == 0 ? null : getContext().getResources().getString(id)); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @SuppressWarnings("deprecation") public Dialog positiveActionBackground(Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) mPositiveAction.setBackground(drawable); else mPositiveAction.setBackgroundDrawable(drawable); return this; } public Dialog positiveActionBackground(int id) { return positiveActionBackground(id == 0 ? null : getContext().getResources().getDrawable(id)); } public Dialog positiveActionRipple(int resId) { RippleDrawable drawable = new RippleDrawable.Builder(getContext(), resId).build(); return positiveActionBackground(drawable); } public Dialog positiveActionTextAppearance(int resId) { mPositiveAction.setTextAppearance(getContext(), resId); return this; } public Dialog positiveActionTextColor(ColorStateList color) { mPositiveAction.setTextColor(color); return this; } public Dialog positiveActionTextColor(int color) { mPositiveAction.setTextColor(color); return this; } public Dialog positiveActionClickListener(View.OnClickListener listener) { mPositiveAction.setOnClickListener(listener); return this; } public Dialog negativeAction(CharSequence action) { mNegativeAction.setText(action); mNegativeAction.setVisibility(TextUtils.isEmpty(action) ? View.GONE : View.VISIBLE); return this; } public Dialog negativeAction(int id) { return negativeAction(id == 0 ? null : getContext().getResources().getString(id)); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @SuppressWarnings("deprecation") public Dialog negativeActionBackground(Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) mNegativeAction.setBackground(drawable); else mNegativeAction.setBackgroundDrawable(drawable); return this; } public Dialog negativeActionBackground(int id) { return negativeActionBackground(id == 0 ? null : getContext().getResources().getDrawable(id)); } public Dialog negativeActionRipple(int resId) { RippleDrawable drawable = new RippleDrawable.Builder(getContext(), resId).build(); return negativeActionBackground(drawable); } public Dialog negativeActionTextAppearance(int resId) { mNegativeAction.setTextAppearance(getContext(), resId); return this; } public Dialog negativeActionTextColor(ColorStateList color) { mNegativeAction.setTextColor(color); return this; } public Dialog negativeActionTextColor(int color) { mNegativeAction.setTextColor(color); return this; } public Dialog negativeActionClickListener(View.OnClickListener listener) { mNegativeAction.setOnClickListener(listener); return this; } public Dialog neutralAction(CharSequence action) { mNeutralAction.setText(action); mNeutralAction.setVisibility(TextUtils.isEmpty(action) ? View.GONE : View.VISIBLE); return this; } public Dialog neutralAction(int id) { return neutralAction(id == 0 ? null : getContext().getResources().getString(id)); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @SuppressWarnings("deprecation") public Dialog neutralActionBackground(Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) mNeutralAction.setBackground(drawable); else mNeutralAction.setBackgroundDrawable(drawable); return this; } public Dialog neutralActionBackground(int id) { return neutralActionBackground(id == 0 ? null : getContext().getResources().getDrawable(id)); } public Dialog neutralActionRipple(int resId) { RippleDrawable drawable = new RippleDrawable.Builder(getContext(), resId).build(); return neutralActionBackground(drawable); } public Dialog neutralActionTextAppearance(int resId) { mNeutralAction.setTextAppearance(getContext(), resId); return this; } public Dialog neutralActionTextColor(ColorStateList color) { mNeutralAction.setTextColor(color); return this; } public Dialog neutralActionTextColor(int color) { mNeutralAction.setTextColor(color); return this; } public Dialog neutralActionClickListener(View.OnClickListener listener) { mNeutralAction.setOnClickListener(listener); return this; } public Dialog inAnimation(int resId) { mInAnimationId = resId; return this; } public Dialog outAnimation(int resId) { mOutAnimationId = resId; return this; } public Dialog showDivider(boolean show) { mCardView.setShowDivider(show); return this; } public Dialog contentView(View v) { if (mContent != v) { if (mContent != null) mCardView.removeView(mContent); mContent = v; } if (mContent != null) mCardView.addView(mContent); return this; } public Dialog contentView(int layoutId) { if (layoutId == 0) return this; View v = LayoutInflater.from(getContext()).inflate(layoutId, null); return contentView(v); } public Dialog cancelable(boolean cancelable) { super.setCancelable(cancelable); mCancelable = cancelable; return this; } public Dialog canceledOnTouchOutside(boolean cancel) { super.setCanceledOnTouchOutside(cancel); mCanceledOnTouchOutside = cancel; return this; } public Dialog contentMargin(int margin) { mCardView.setContentMargin(margin); return this; } public Dialog contentMargin(int left, int top, int right, int bottom) { mCardView.setContentMargin(left, top, right, bottom); return this; } @Override public void setCancelable(boolean flag) { cancelable(flag); } @Override public void setCanceledOnTouchOutside(boolean cancel) { canceledOnTouchOutside(cancel); } @Override public void setContentView(View v) { contentView(v); } @Override public void setContentView(int layoutId) { contentView(layoutId); } @Override public void setContentView(View v, ViewGroup.LayoutParams params) { contentView(v); } @Override public void addContentView(View view, ViewGroup.LayoutParams params) { contentView(view); } @Override public void show() { if (mInAnimationId != 0) mCardView .getViewTreeObserver() .addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mCardView.getViewTreeObserver().removeOnPreDrawListener(this); Animation anim = AnimationUtils.loadAnimation(mCardView.getContext(), mInAnimationId); mCardView.startAnimation(anim); return false; } }); super.show(); } @Override public void dismiss() { if (mOutAnimationId != 0) { Animation anim = AnimationUtils.loadAnimation(mContainer.getContext(), mOutAnimationId); anim.setAnimationListener( new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationRepeat(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { mHandler.post(mDismissAction); } }); mCardView.startAnimation(anim); } else mHandler.post(mDismissAction); } private class ContainerFrameLayout extends FrameLayout { private boolean mClickOutside = false; public ContainerFrameLayout(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); mCardView.measure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int childLeft = (right - left - mCardView.getMeasuredWidth()) / 2; int childTop = (bottom - top - mCardView.getMeasuredHeight()) / 2; int childRight = childLeft + mCardView.getMeasuredWidth(); int childBottom = childTop + mCardView.getMeasuredHeight(); mCardView.layout(childLeft, childTop, childRight, childBottom); } private boolean isOutsideDialog(float x, float y) { return x < mCardView.getLeft() + mCardView.getPaddingLeft() || x > mCardView.getRight() - mCardView.getPaddingRight() || y < mCardView.getTop() + mCardView.getPaddingTop() || y > mCardView.getBottom() - mCardView.getPaddingBottom(); } @Override public boolean onTouchEvent(MotionEvent event) { boolean handled = super.onTouchEvent(event); if (handled) return true; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (isOutsideDialog(event.getX(), event.getY())) { mClickOutside = true; return true; } return false; case MotionEvent.ACTION_MOVE: return mClickOutside; case MotionEvent.ACTION_CANCEL: mClickOutside = false; return false; case MotionEvent.ACTION_UP: if (mClickOutside && isOutsideDialog(event.getX(), event.getY())) { mClickOutside = false; if (mCancelable && mCanceledOnTouchOutside) dismiss(); return true; } return false; } return false; } } private class DialogCardView extends CardView { private Paint mDividerPaint; private float mDividerPos = -1f; private boolean mShowDivider = false; private int mContentMarginLeft; private int mContentMarginTop; private int mContentMarginRight; private int mContentMarginBottom; public DialogCardView(Context context) { super(context); mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mDividerPaint.setStyle(Paint.Style.STROKE); setWillNotDraw(false); } public void setContentMargin(int margin) { setContentMargin(margin, margin, margin, margin); } public void setContentMargin(int left, int top, int right, int bottom) { mContentMarginLeft = left; mContentMarginTop = top; mContentMarginRight = right; mContentMarginBottom = bottom; } public void setDividerColor(int color) { mDividerPaint.setColor(color); invalidate(); } public void setDividerHeight(int height) { mDividerPaint.setStrokeWidth(height); invalidate(); } public void setShowDivider(boolean show) { if (mShowDivider != show) { mShowDivider = show; invalidate(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int paddingLeft = Math.max(mDialogHorizontalPadding, mCardView.getPaddingLeft()); int paddingRight = Math.max(mDialogHorizontalPadding, mCardView.getPaddingRight()); int paddingTop = Math.max(mDialogVerticalPadding, mCardView.getPaddingTop()); int paddingBottom = Math.max(mDialogVerticalPadding, mCardView.getPaddingBottom()); int maxWidth = widthSize - paddingLeft - paddingRight; int maxHeight = heightSize - paddingTop - paddingBottom; int width = mLayoutWidth == ViewGroup.LayoutParams.MATCH_PARENT ? maxWidth : mLayoutWidth; int height = mLayoutHeight == ViewGroup.LayoutParams.MATCH_PARENT ? maxHeight : mLayoutHeight; int widthMs; int heightMs; int titleWidth = 0; int titleHeight = 0; if (mTitle.getVisibility() == View.VISIBLE) { widthMs = MeasureSpec.makeMeasureSpec( width == ViewGroup.LayoutParams.WRAP_CONTENT ? maxWidth : width, MeasureSpec.AT_MOST); heightMs = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST); mTitle.measure(widthMs, heightMs); titleWidth = mTitle.getMeasuredWidth(); titleHeight = mTitle.getMeasuredHeight(); } int contentWidth = 0; int contentHeight = 0; if (mContent != null) { widthMs = MeasureSpec.makeMeasureSpec( (width == ViewGroup.LayoutParams.WRAP_CONTENT ? maxWidth : width) - mContentMarginLeft - mContentMarginRight, MeasureSpec.AT_MOST); heightMs = MeasureSpec.makeMeasureSpec( maxHeight - mContentMarginTop - mContentMarginBottom, MeasureSpec.AT_MOST); mContent.measure(widthMs, heightMs); contentWidth = mContent.getMeasuredWidth(); contentHeight = mContent.getMeasuredHeight(); } int visibleActions = 0; int positiveActionWidth = 0; if (mPositiveAction.getVisibility() == View.VISIBLE) { widthMs = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); heightMs = MeasureSpec.makeMeasureSpec(mActionHeight, MeasureSpec.EXACTLY); mPositiveAction.measure(widthMs, heightMs); positiveActionWidth = mPositiveAction.getMeasuredWidth(); if (positiveActionWidth < mActionMinWidth) { mPositiveAction.measure( MeasureSpec.makeMeasureSpec(mActionMinWidth, MeasureSpec.EXACTLY), heightMs); positiveActionWidth = mActionMinWidth; } visibleActions++; } int negativeActionWidth = 0; if (mNegativeAction.getVisibility() == View.VISIBLE) { widthMs = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); heightMs = MeasureSpec.makeMeasureSpec(mActionHeight, MeasureSpec.EXACTLY); mNegativeAction.measure(widthMs, heightMs); negativeActionWidth = mNegativeAction.getMeasuredWidth(); if (negativeActionWidth < mActionMinWidth) { mNegativeAction.measure( MeasureSpec.makeMeasureSpec(mActionMinWidth, MeasureSpec.EXACTLY), heightMs); negativeActionWidth = mActionMinWidth; } visibleActions++; } int neutralActionWidth = 0; if (mNeutralAction.getVisibility() == View.VISIBLE) { widthMs = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); heightMs = MeasureSpec.makeMeasureSpec(mActionHeight, MeasureSpec.EXACTLY); mNeutralAction.measure(widthMs, heightMs); neutralActionWidth = mNeutralAction.getMeasuredWidth(); if (neutralActionWidth < mActionMinWidth) { mNeutralAction.measure( MeasureSpec.makeMeasureSpec(mActionMinWidth, MeasureSpec.EXACTLY), heightMs); neutralActionWidth = mActionMinWidth; } visibleActions++; } int actionBarWidth = positiveActionWidth + negativeActionWidth + neutralActionWidth + mActionOuterPadding * 2 + mActionPadding * Math.max(0, visibleActions - 1); if (width == ViewGroup.LayoutParams.WRAP_CONTENT) width = Math.min( maxWidth, Math.max( titleWidth, Math.max( contentWidth + mContentMarginLeft + mContentMarginRight, actionBarWidth))); mLayoutActionVertical = actionBarWidth > width; int nonContentHeight = titleHeight + mActionPadding + mContentMarginTop + mContentMarginBottom; if (mLayoutActionVertical) nonContentHeight += mActionOuterHeight * visibleActions; else nonContentHeight += (visibleActions > 0) ? mActionOuterHeight : 0; if (height == ViewGroup.LayoutParams.WRAP_CONTENT) height = Math.min(maxHeight, contentHeight + nonContentHeight); if (mContent != null) mContent.measure( MeasureSpec.makeMeasureSpec( width - mContentMarginLeft - mContentMarginRight, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height - nonContentHeight, MeasureSpec.EXACTLY)); setMeasuredDimension( width + getPaddingLeft() + getPaddingRight(), height + getPaddingTop() + getPaddingBottom()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int childLeft = 0; int childTop = 0; int childRight = right - left; int childBottom = bottom - top; childLeft += getPaddingLeft(); childTop += getPaddingTop(); childRight -= getPaddingRight(); childBottom -= getPaddingBottom(); if (mTitle.getVisibility() == View.VISIBLE) { mTitle.layout(childLeft, childTop, childRight, childTop + mTitle.getMeasuredHeight()); childTop += mTitle.getMeasuredHeight(); } childBottom -= mActionPadding; int temp = (mActionOuterHeight - mActionHeight) / 2; if (mLayoutActionVertical) { if (mNeutralAction.getVisibility() == View.VISIBLE) { mNeutralAction.layout( childRight - mActionOuterPadding - mNeutralAction.getMeasuredWidth(), childBottom - mActionOuterHeight + temp, childRight - mActionOuterPadding, childBottom - temp); childBottom -= mActionOuterHeight; } if (mNegativeAction.getVisibility() == View.VISIBLE) { mNegativeAction.layout( childRight - mActionOuterPadding - mNegativeAction.getMeasuredWidth(), childBottom - mActionOuterHeight + temp, childRight - mActionOuterPadding, childBottom - temp); childBottom -= mActionOuterHeight; } if (mPositiveAction.getVisibility() == View.VISIBLE) { mPositiveAction.layout( childRight - mActionOuterPadding - mPositiveAction.getMeasuredWidth(), childBottom - mActionOuterHeight + temp, childRight - mActionOuterPadding, childBottom - temp); childBottom -= mActionOuterHeight; } } else { int actionRight = childRight - mActionOuterPadding; int actionTop = childBottom - mActionOuterHeight + temp; int actionBottom = childBottom - temp; boolean hasAction = false; if (mPositiveAction.getVisibility() == View.VISIBLE) { mPositiveAction.layout( actionRight - mPositiveAction.getMeasuredWidth(), actionTop, actionRight, actionBottom); actionRight -= mPositiveAction.getMeasuredWidth() + mActionPadding; hasAction = true; } if (mNegativeAction.getVisibility() == View.VISIBLE) { mNegativeAction.layout( actionRight - mNegativeAction.getMeasuredWidth(), actionTop, actionRight, actionBottom); hasAction = true; } if (mNeutralAction.getVisibility() == View.VISIBLE) { mNeutralAction.layout( childLeft + mActionOuterPadding, actionTop, childLeft + mActionOuterPadding + mNeutralAction.getMeasuredWidth(), actionBottom); hasAction = true; } if (hasAction) childBottom -= mActionOuterHeight; } mDividerPos = childBottom - mDividerPaint.getStrokeWidth() / 2f; if (mContent != null) mContent.layout( childLeft + mContentMarginLeft, childTop + mContentMarginTop, childRight - mContentMarginRight, childBottom - mContentMarginBottom); } @Override public void draw(Canvas canvas) { super.draw(canvas); if (mShowDivider && (mPositiveAction.getVisibility() == View.VISIBLE || mNegativeAction.getVisibility() == View.VISIBLE || mNeutralAction.getVisibility() == View.VISIBLE)) canvas.drawLine( getPaddingLeft(), mDividerPos, getWidth() - getPaddingRight(), mDividerPos, mDividerPaint); } } public static class Builder implements DialogFragment.Builder, Parcelable { protected int mStyleId; protected int mContentViewId; protected CharSequence mTitle; protected CharSequence mPositive; protected CharSequence mNegative; protected CharSequence mNeutral; protected Dialog mDialog; public Builder() { this(R.style.Material_App_Dialog_Light); } public Builder(int styleId) { mStyleId = styleId; } public Builder style(int styleId) { mStyleId = styleId; return this; } public Builder contentView(int layoutId) { mContentViewId = layoutId; return this; } public Builder title(CharSequence title) { mTitle = title; return this; } public Builder positiveAction(CharSequence action) { mPositive = action; return this; } public Builder negativeAction(CharSequence action) { mNegative = action; return this; } public Builder neutralAction(CharSequence action) { mNeutral = action; return this; } @Override public void onPositiveActionClicked(DialogFragment fragment) { fragment.dismiss(); } @Override public void onNegativeActionClicked(DialogFragment fragment) { fragment.dismiss(); } @Override public void onNeutralActionClicked(DialogFragment fragment) { fragment.dismiss(); } @Override public Dialog build(Context context) { mDialog = onBuild(context, mStyleId); mDialog .title(mTitle) .positiveAction(mPositive) .negativeAction(mNegative) .neutralAction(mNeutral); if (mContentViewId != 0) mDialog.contentView(mContentViewId); return mDialog; } protected Dialog onBuild(Context context, int styleId) { return new Dialog(context, styleId); } protected Builder(Parcel in) { mStyleId = in.readInt(); mContentViewId = in.readInt(); mTitle = (CharSequence) in.readParcelable(null); mPositive = (CharSequence) in.readParcelable(null); mNegative = (CharSequence) in.readParcelable(null); mNeutral = (CharSequence) in.readParcelable(null); onReadFromParcel(in); } protected void onReadFromParcel(Parcel in) {} protected void onWriteToParcel(Parcel dest, int flags) {} @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mStyleId); dest.writeInt(mContentViewId); dest.writeValue(mTitle); dest.writeValue(mPositive); dest.writeValue(mNegative); dest.writeValue(mNeutral); onWriteToParcel(dest, flags); } @Override public int describeContents() { return 0; } public static final Parcelable.Creator<Builder> CREATOR = new Parcelable.Creator<Builder>() { public Builder createFromParcel(Parcel in) { return new Builder(in); } public Builder[] newArray(int size) { return new Builder[size]; } }; } }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override protected void onCreate() { View v = LayoutInflater.from(getContext()).inflate(R.layout.dialog_recurring, null); setContentView(v); FrameLayout fl_mode = (FrameLayout) v.findViewById(R.id.rd_fl_mode); final ScrollView sv_repeat = (ScrollView) v.findViewById(R.id.rd_sv_repeat); final LinearLayout ll_repeat = (LinearLayout) v.findViewById(R.id.rd_ll_repeat); mModeSpinner = (Spinner) fl_mode.findViewById(R.id.rd_spn_mode); mEndSpinner = (Spinner) v.findViewById(R.id.rd_spn_end); mPeriodEditText = (EditText) v.findViewById(R.id.rd_et_period); mPeriodUnitTextView = (TextView) v.findViewById(R.id.rd_tv_period_unit); mSameDayRadioButton = (RadioButton) v.findViewById(R.id.rd_month_rb_same); mSameWeekdayRadioButton = (RadioButton) v.findViewById(R.id.rd_month_rb_week); mEndNumEditText = (EditText) v.findViewById(R.id.rd_et_end_num); mEndNumUnitTextView = (TextView) v.findViewById(R.id.rd_tv_end_num_unit); mEndDateButton = (Button) v.findViewById(R.id.rd_bt_end_date); mWeekView = (WeekView) v.findViewById(R.id.rd_wv_week); sv_repeat .getViewTreeObserver() .addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { showDivider(ll_repeat.getMeasuredHeight() > sv_repeat.getMeasuredHeight()); } }); mHeaderBackground = new HeaderDrawable(getContext()); ViewCompat.setPaddingRelative(fl_mode, mContentPadding, 0, mContentPadding, 0); ViewUtil.setBackground(fl_mode, mHeaderBackground); ViewCompat.setPaddingRelative( ll_repeat, mContentPadding, mActionOuterPadding, mContentPadding, mActionPadding); mModeAdapter = new ModeAdapter(); mModeSpinner.setAdapter(mModeAdapter); mModeSpinner.setOnItemSelectedListener( new Spinner.OnItemSelectedListener() { @Override public void onItemSelected(Spinner parent, View view, int position, long id) { onModeSelected(position); } }); mEndAdapter = new EndAdapter(); mEndSpinner.setAdapter(mEndAdapter); mEndSpinner.setOnItemSelectedListener( new Spinner.OnItemSelectedListener() { @Override public void onItemSelected(Spinner parent, View view, int position, long id) { onEndSelected(position); } }); mPeriodEditText.addTextChangedListener( new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { onPeriodChanged(); } }); mPeriodEditText.setOnKeyListener( new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { String text = mPeriodEditText.getText().toString(); if (TextUtils.isEmpty(text)) mPeriodEditText.setText(String.valueOf(mRecurring.getPeriod())); } return false; } }); CompoundButton.OnCheckedChangeListener mCheckChangeListener = new android.widget.CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged( android.widget.CompoundButton buttonView, boolean isChecked) { if (isChecked) { if (buttonView == mSameDayRadioButton) mSameWeekdayRadioButton.setChecked(false); else mSameDayRadioButton.setChecked(false); onMonthSettingChanged(); } } }; mSameDayRadioButton.setOnCheckedChangeListener(mCheckChangeListener); mSameWeekdayRadioButton.setOnCheckedChangeListener(mCheckChangeListener); mEndNumEditText.addTextChangedListener( new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { onEventNumberChanged(); } }); mEndNumEditText.setOnKeyListener( new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { String text = mEndNumEditText.getText().toString(); if (TextUtils.isEmpty(text)) mEndNumEditText.setText(String.valueOf(mRecurring.getEventNumber())); } return false; } }); View.OnClickListener mDateClickListener = new View.OnClickListener() { @Override public void onClick(View v) { final DatePickerDialog dialog = new DatePickerDialog(getContext(), mDatePickerDialogStyleId); long minTime = System.currentTimeMillis(); Calendar cal = dialog.getCalendar(); cal.setTimeInMillis(minTime); cal.add(Calendar.YEAR, 100); long maxTime = cal.getTimeInMillis(); dialog .dateRange(minTime, maxTime) .date((long) mEndDateButton.getTag()) .positiveAction(mPositiveAction.getText()) .positiveActionClickListener( new View.OnClickListener() { @Override public void onClick(View v) { onEndDateChanged(dialog.getDate()); dialog.dismiss(); } }) .negativeAction(mNegativeAction.getText()) .negativeActionClickListener( new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }) .show(); } }; mEndDateButton.setOnClickListener(mDateClickListener); mWeekView.setOnDaySelectionChangedListener(this); }