diff --git a/build.gradle b/build.gradle index 9405f3fd..62e1a982 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,14 @@ buildscript { repositories { jcenter() + maven { + url 'https://repos.zeroturnaround.com/nexus/content/repositories/zt-public-releases' + } } dependencies { classpath 'com.android.tools.build:gradle:1.2.3' + // This does not break the build when Android Studio is missing the JRebel for Android plugin. + classpath 'com.zeroturnaround.jrebel.android:jr-android-gradle:0.8.+' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/library/build.gradle b/library/build.gradle index 8e6d313e..8a509c61 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + compileSdkVersion 23 + buildToolsVersion "23" defaultConfig { minSdkVersion 14 - targetSdkVersion 22 + targetSdkVersion 23 versionCode 1 versionName "1.0" } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/AnimationFactory.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/AnimationFactory.java index 411cd0a3..7aefb353 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/AnimationFactory.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/AnimationFactory.java @@ -7,9 +7,7 @@ import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; -/** - * Created by deanwild on 05/08/15. - */ + public class AnimationFactory implements IAnimationFactory{ private static final String ALPHA = "alpha"; diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/IAnimationFactory.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/IAnimationFactory.java index 1d01d4ec..f63afd15 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/IAnimationFactory.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/IAnimationFactory.java @@ -3,9 +3,7 @@ import android.graphics.Point; import android.view.View; -/** - * Created by deanwild on 05/08/15. - */ + public interface IAnimationFactory { void fadeInView(View target, long duration, AnimationStartListener listener); diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/IDetachedListener.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/IDetachedListener.java index e6e6849c..e964d568 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/IDetachedListener.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/IDetachedListener.java @@ -1,9 +1,6 @@ package uk.co.deanwild.materialshowcaseview; -/** - * Created by deanwild on 24/08/15. - */ -interface IDetachedListener { - void onShowcaseDetached(MaterialShowcaseView showcaseView, boolean wasDismissed); +public interface IDetachedListener { + void onShowcaseDetached(MaterialShowcaseView showcaseView, boolean wasDismissed); } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/IShowcaseListener.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/IShowcaseListener.java index 1edfbeeb..c527b092 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/IShowcaseListener.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/IShowcaseListener.java @@ -1,10 +1,7 @@ package uk.co.deanwild.materialshowcaseview; -/** - * Created by deanwild on 11/08/15. - */ + public interface IShowcaseListener { void onShowcaseDisplayed(MaterialShowcaseView showcaseView); void onShowcaseDismissed(MaterialShowcaseView showcaseView); - } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseSequence.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseSequence.java index 2bdef5b2..2b4e9dd6 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseSequence.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseSequence.java @@ -6,9 +6,7 @@ import java.util.LinkedList; import java.util.Queue; -/** - * Created by deanwild on 11/08/15. - */ + public class MaterialShowcaseSequence implements IDetachedListener { PrefsManager mPrefsManager; @@ -18,6 +16,9 @@ public class MaterialShowcaseSequence implements IDetachedListener { private ShowcaseConfig mConfig; private int mSequencePosition = 0; + private OnSequenceItemShownListener mOnItemShownListener = null; + private OnSequenceItemDismissedListener mOnItemDismissedListener = null; + public MaterialShowcaseSequence(Activity activity) { mActivity = activity; mShowcaseQueue = new LinkedList<>(); @@ -55,6 +56,14 @@ public MaterialShowcaseSequence singleUse(String sequenceID) { return this; } + public void setOnItemShownListener(OnSequenceItemShownListener listener) { + this.mOnItemShownListener = listener; + } + + public void setOnItemDismissedListener(OnSequenceItemDismissedListener listener) { + this.mOnItemDismissedListener = listener; + } + public boolean hasFired() { if (mPrefsManager.getSequenceStatus() == PrefsManager.SEQUENCE_FINISHED) { @@ -99,6 +108,9 @@ private void showNextItem() { MaterialShowcaseView sequenceItem = mShowcaseQueue.remove(); sequenceItem.setDetachedListener(this); sequenceItem.show(mActivity); + if (mOnItemShownListener != null) { + mOnItemShownListener.onShow(sequenceItem, mSequencePosition); + } } else { /** * We've reached the end of the sequence, save the fired state @@ -120,6 +132,10 @@ public void onShowcaseDetached(MaterialShowcaseView showcaseView, boolean wasDis */ if (wasDismissed) { + if (mOnItemDismissedListener != null) { + mOnItemDismissedListener.onDismiss(showcaseView, mSequencePosition); + } + /** * If so, update the prefsManager so we can potentially resume this sequence in the future */ @@ -136,8 +152,12 @@ public void setConfig(ShowcaseConfig config) { this.mConfig = config; } + public interface OnSequenceItemShownListener { + void onShow(MaterialShowcaseView itemView, int position); + } - - + public interface OnSequenceItemDismissedListener { + void onDismiss(MaterialShowcaseView itemView, int position); + } } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseView.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseView.java index 88571d6e..b2d22bd3 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseView.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/MaterialShowcaseView.java @@ -10,8 +10,10 @@ import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.os.Build; import android.os.Handler; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; @@ -26,9 +28,16 @@ import java.util.ArrayList; import java.util.List; +import uk.co.deanwild.materialshowcaseview.shape.CircleShape; +import uk.co.deanwild.materialshowcaseview.shape.NoShape; +import uk.co.deanwild.materialshowcaseview.shape.RectangleShape; +import uk.co.deanwild.materialshowcaseview.shape.Shape; +import uk.co.deanwild.materialshowcaseview.target.Target; +import uk.co.deanwild.materialshowcaseview.target.ViewTarget; + /** - * Created by deanwild on 04/08/15. + * Helper class to show a sequence of showcase views. */ public class MaterialShowcaseView extends FrameLayout implements View.OnTouchListener, View.OnClickListener { @@ -38,12 +47,12 @@ public class MaterialShowcaseView extends FrameLayout implements View.OnTouchLis private Canvas mCanvas; private Paint mEraser; private Target mTarget; + private Shape mShape; private int mXPosition; private int mYPosition; private boolean mWasDismissed = false; + private int mShapePadding = ShowcaseConfig.DEFAULT_SHAPE_PADDING; - private int mRadius = ShowcaseConfig.DEFAULT_RADIUS; - private boolean mUseAutoRadius = true; private View mContentBox; private TextView mContentTextView; private TextView mDismissButton; @@ -153,14 +162,16 @@ protected void onDraw(Canvas canvas) { // draw solid background mCanvas.drawColor(mMaskColour); - // Erase a circle + // Prepare eraser Paint if needed if (mEraser == null) { mEraser = new Paint(); mEraser.setColor(0xFFFFFFFF); mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); mEraser.setFlags(Paint.ANTI_ALIAS_FLAG); } - mCanvas.drawCircle(mXPosition, mYPosition, mRadius, mEraser); + + // draw (erase) shape + mShape.draw(mCanvas, mEraser, mXPosition, mYPosition, mShapePadding); // Draw the bitmap on our views canvas. canvas.drawBitmap(mBitmap, 0, 0, null); @@ -237,6 +248,9 @@ public void onClick(View v) { public void setTarget(Target target) { mTarget = target; + // update dismiss button state + updateDismissButton(); + if (mTarget != null) { /** @@ -246,32 +260,34 @@ public void setTarget(Target target) { mBottomMargin = getSoftButtonsBarSizePort((Activity) getContext()); FrameLayout.LayoutParams contentLP = (LayoutParams) getLayoutParams(); - if (contentLP!=null && contentLP.bottomMargin != mBottomMargin) + if (contentLP != null && contentLP.bottomMargin != mBottomMargin) contentLP.bottomMargin = mBottomMargin; } // apply the target position Point targetPoint = mTarget.getPoint(); + Rect targetBounds = mTarget.getBounds(); setPosition(targetPoint); - // apply auto radius - if (mUseAutoRadius) { - setRadius(mTarget.getRadius()); - } - // now figure out whether to put content above or below it int height = getMeasuredHeight(); int midPoint = height / 2; int yPos = targetPoint.y; + int radius = Math.max(targetBounds.height(), targetBounds.width()) / 2; + if (mShape != null) { + mShape.updateTarget(mTarget); + radius = mShape.getHeight() / 2; + } + if (yPos > midPoint) { // target is in lower half of screen, we'll sit above it mContentTopMargin = 0; - mContentBottomMargin = (height - yPos) + mRadius; + mContentBottomMargin = (height - yPos) + radius + mShapePadding; mGravity = Gravity.BOTTOM; } else { // target is in upper half of screen, we'll sit below it - mContentTopMargin = yPos + mRadius; + mContentTopMargin = yPos + radius + mShapePadding; mContentBottomMargin = 0; mGravity = Gravity.TOP; } @@ -332,6 +348,8 @@ private void setContentText(CharSequence contentText) { private void setDismissText(CharSequence dismissText) { if (mDismissButton != null) { mDismissButton.setText(dismissText); + + updateDismissButton(); } } @@ -347,17 +365,12 @@ private void setDismissTextColor(int textColour) { } } - private void setDismissOnTouch(boolean dismissOnTouch) { - mDismissOnTouch = dismissOnTouch; - } - - private void setUseAutoRadius(boolean useAutoRadius) { - mUseAutoRadius = useAutoRadius; + private void setShapePadding(int padding) { + mShapePadding = padding; } - private void setRadius(int radius) { - mRadius = radius; - + private void setDismissOnTouch(boolean dismissOnTouch) { + mDismissOnTouch = dismissOnTouch; } private void setShouldRender(boolean shouldRender) { @@ -390,6 +403,9 @@ void setDetachedListener(IDetachedListener detachedListener) { mDetachedListener = detachedListener; } + public void setShape(Shape mShape) { + this.mShape = mShape; + } /** * Set properties based on a config object @@ -402,6 +418,23 @@ public void setConfig(ShowcaseConfig config) { setContentTextColor(config.getContentTextColor()); setDismissTextColor(config.getDismissTextColor()); setMaskColour(config.getMaskColor()); + setShape(config.getShape()); + setShapePadding(config.getShapePadding()); + } + + private void updateDismissButton() { + // hide or show button + if (mDismissButton != null) { + if (TextUtils.isEmpty(mDismissButton.getText())) { + mDismissButton.setVisibility(GONE); + } else { + mDismissButton.setVisibility(VISIBLE); + } + } + } + + public boolean hasFired() { + return mPrefsManager.hasFired(); } /** @@ -421,6 +454,13 @@ public void onGlobalLayout() { * Gives us a builder utility class with a fluent API for eaily configuring showcase views */ public static class Builder { + private static final int CIRCLE_SHAPE = 0; + private static final int RECTANGLE_SHAPE = 1; + private static final int NO_SHAPE = 2; + + private boolean fullWidth = false; + private int shapeType = CIRCLE_SHAPE; + final MaterialShowcaseView showcaseView; private final Activity activity; @@ -467,24 +507,6 @@ public Builder setContentText(CharSequence text) { } - /** - * Use auto radius, if true then the showcase circle will auto size based on the target view - * Defaults to true - */ - public Builder setUseAutoRadius(boolean useAutoRadius) { - showcaseView.setUseAutoRadius(useAutoRadius); - return this; - } - - /** - * Manually define a radius in pixels - should set setUseAutoRadius to false - * Defaults to 200 pixels - */ - public Builder setRadius(int radius) { - showcaseView.setRadius(radius); - return this; - } - public Builder setDismissOnTouch(boolean dismissOnTouch) { showcaseView.setDismissOnTouch(dismissOnTouch); return this; @@ -525,12 +547,61 @@ public Builder singleUse(String showcaseID) { return this; } + public Builder setShape(Shape shape) { + showcaseView.setShape(shape); + return this; + } + + public Builder withCircleShape() { + shapeType = CIRCLE_SHAPE; + return this; + } + + public Builder withoutShape() { + shapeType = NO_SHAPE; + return this; + } + + public Builder setShapePadding(int padding) { + showcaseView.setShapePadding(padding); + return this; + } + + public Builder withRectangleShape() { + return withRectangleShape(false); + } + + public Builder withRectangleShape(boolean fullWidth) { + this.shapeType = RECTANGLE_SHAPE; + this.fullWidth = fullWidth; + return this; + } + public MaterialShowcaseView build() { + if (showcaseView.mShape == null) { + switch (shapeType) { + case RECTANGLE_SHAPE: { + showcaseView.setShape(new RectangleShape(showcaseView.mTarget.getBounds(), fullWidth)); + break; + } + case CIRCLE_SHAPE: { + showcaseView.setShape(new CircleShape(showcaseView.mTarget)); + break; + } + case NO_SHAPE: { + showcaseView.setShape(new NoShape()); + break; + } + default: + throw new IllegalArgumentException("Unsupported shape type: " + shapeType); + } + } + return showcaseView; } public MaterialShowcaseView show() { - showcaseView.show(activity); + build().show(activity); return showcaseView; } @@ -605,6 +676,8 @@ public void run() { } }, mDelayInMillis); + updateDismissButton(); + return true; } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/PrefsManager.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/PrefsManager.java index 095b2763..8bad7031 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/PrefsManager.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/PrefsManager.java @@ -3,9 +3,7 @@ import android.content.Context; import android.content.SharedPreferences; -/** - * Created by deanwild on 11/08/15. - */ + public class PrefsManager { public static int SEQUENCE_NEVER_STARTED = 0; diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/ShowcaseConfig.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/ShowcaseConfig.java index bc3c8aa4..32d6ecbf 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/ShowcaseConfig.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/ShowcaseConfig.java @@ -2,21 +2,25 @@ import android.graphics.Color; -/** - * Created by deanwild on 11/08/15. - */ +import uk.co.deanwild.materialshowcaseview.shape.CircleShape; +import uk.co.deanwild.materialshowcaseview.shape.Shape; + + public class ShowcaseConfig { public static final String DEFAULT_MASK_COLOUR = "#dd335075"; public static final long DEFAULT_FADE_TIME = 300; public static final long DEFAULT_DELAY = 0; - public static final int DEFAULT_RADIUS = 200; + public static final Shape DEFAULT_SHAPE = new CircleShape(); + public static final int DEFAULT_SHAPE_PADDING = 10; private long mDelay = DEFAULT_DELAY; private int mMaskColour; private int mContentTextColor; private int mDismissTextColor; private long mFadeDuration = DEFAULT_FADE_TIME; + private Shape mShape = DEFAULT_SHAPE; + private int mShapePadding = DEFAULT_SHAPE_PADDING; public ShowcaseConfig() { mMaskColour = Color.parseColor(ShowcaseConfig.DEFAULT_MASK_COLOUR); @@ -63,4 +67,20 @@ public long getFadeDuration() { public void setFadeDuration(long fadeDuration) { this.mFadeDuration = fadeDuration; } + + public Shape getShape() { + return mShape; + } + + public void setShape(Shape shape) { + this.mShape = shape; + } + + public void setShapePadding(int padding) { + this.mShapePadding = padding; + } + + public int getShapePadding() { + return mShapePadding; + } } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/CircleShape.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/CircleShape.java new file mode 100644 index 00000000..7a51f015 --- /dev/null +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/CircleShape.java @@ -0,0 +1,74 @@ +package uk.co.deanwild.materialshowcaseview.shape; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; + +import uk.co.deanwild.materialshowcaseview.target.Target; + +/** + * Circular shape for target. + */ +public class CircleShape implements Shape { + + private int radius = 200; + private boolean adjustToTarget = true; + + public CircleShape() { + } + + public CircleShape(int radius) { + this.radius = radius; + } + + public CircleShape(Rect bounds) { + this(getPreferredRadius(bounds)); + } + + public CircleShape(Target target) { + this(target.getBounds()); + } + + public void setAdjustToTarget(boolean adjustToTarget) { + this.adjustToTarget = adjustToTarget; + } + + public boolean isAdjustToTarget() { + return adjustToTarget; + } + + public int getRadius() { + return radius; + } + + public void setRadius(int radius) { + this.radius = radius; + } + + @Override + public void draw(Canvas canvas, Paint paint, int x, int y, int padding) { + if (radius > 0) { + canvas.drawCircle(x, y, radius + padding, paint); + } + } + + @Override + public void updateTarget(Target target) { + if (adjustToTarget) + radius = getPreferredRadius(target.getBounds()); + } + + @Override + public int getWidth() { + return radius * 2; + } + + @Override + public int getHeight() { + return radius * 2; + } + + public static int getPreferredRadius(Rect bounds) { + return Math.max(bounds.width(), bounds.height()) / 2; + } +} diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/NoShape.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/NoShape.java new file mode 100644 index 00000000..1866d4bf --- /dev/null +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/NoShape.java @@ -0,0 +1,32 @@ +package uk.co.deanwild.materialshowcaseview.shape; + +import android.graphics.Canvas; +import android.graphics.Paint; + +import uk.co.deanwild.materialshowcaseview.target.Target; + +/** + * A Shape implementation that draws nothing. + */ +public class NoShape implements Shape { + + @Override + public void updateTarget(Target target) { + // do nothing + } + + @Override + public void draw(Canvas canvas, Paint paint, int x, int y, int padding) { + // do nothing + } + + @Override + public int getWidth() { + return 0; + } + + @Override + public int getHeight() { + return 0; + } +} diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/RectangleShape.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/RectangleShape.java new file mode 100644 index 00000000..f06d9901 --- /dev/null +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/RectangleShape.java @@ -0,0 +1,85 @@ +package uk.co.deanwild.materialshowcaseview.shape; + + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; + +import uk.co.deanwild.materialshowcaseview.target.Target; + +public class RectangleShape implements Shape { + + private boolean fullWidth = false; + + private int width = 0; + private int height = 0; + private boolean adjustToTarget = true; + + private Rect rect; + + public RectangleShape(int width, int height) { + this.width = width; + this.height = height; + init(); + } + + public RectangleShape(Rect bounds) { + this(bounds, false); + } + + public RectangleShape(Rect bounds, boolean fullWidth) { + this.fullWidth = fullWidth; + height = bounds.height(); + if (fullWidth) + width = Integer.MAX_VALUE; + else width = bounds.width(); + init(); + } + + public boolean isAdjustToTarget() { + return adjustToTarget; + } + + public void setAdjustToTarget(boolean adjustToTarget) { + this.adjustToTarget = adjustToTarget; + } + + private void init() { + rect = new Rect(- width / 2, - height / 2, width / 2, height / 2); + } + + @Override + public void draw(Canvas canvas, Paint paint, int x, int y, int padding) { + if (!rect.isEmpty()) { + canvas.drawRect( + rect.left + x - padding, + rect.top + y - padding, + rect.right + x + padding, + rect.bottom + y + padding, + paint + ); + } + } + + @Override + public void updateTarget(Target target) { + if (adjustToTarget) { + Rect bounds = target.getBounds(); + height = bounds.height(); + if (fullWidth) + width = Integer.MAX_VALUE; + else width = bounds.width(); + init(); + } + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } +} \ No newline at end of file diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/Shape.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/Shape.java new file mode 100644 index 00000000..53bdfa90 --- /dev/null +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/shape/Shape.java @@ -0,0 +1,35 @@ +package uk.co.deanwild.materialshowcaseview.shape; + +import android.graphics.Canvas; +import android.graphics.Paint; + +import uk.co.deanwild.materialshowcaseview.target.Target; + +/** + * Specifies a shape of the target (e.g circle, rectangle). + * Implementations of this interface will be responsible to draw the shape + * at specified center point (x, y). + */ +public interface Shape { + + /** + * Draw shape on the canvas with the center at (x, y) using Paint object provided. + */ + void draw(Canvas canvas, Paint paint, int x, int y, int padding); + + /** + * Get width of the shape. + */ + int getWidth(); + + /** + * Get height of the shape. + */ + int getHeight(); + + /** + * Update shape bounds if necessary + */ + void updateTarget(Target target); + +} diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/Target.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/target/Target.java similarity index 51% rename from library/src/main/java/uk/co/deanwild/materialshowcaseview/Target.java rename to library/src/main/java/uk/co/deanwild/materialshowcaseview/target/Target.java index eacc197c..3d854819 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/Target.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/target/Target.java @@ -1,10 +1,9 @@ -package uk.co.deanwild.materialshowcaseview; +package uk.co.deanwild.materialshowcaseview.target; import android.graphics.Point; +import android.graphics.Rect; + -/** - * Created by deanwild on 04/08/15. - */ public interface Target { Target NONE = new Target() { @Override @@ -13,12 +12,13 @@ public Point getPoint() { } @Override - public int getRadius() { - return 200; + public Rect getBounds() { + Point p = getPoint(); + return new Rect(p.x - 190, p.y - 190, p.x + 190, p.y + 190); } }; Point getPoint(); - int getRadius(); + Rect getBounds(); } diff --git a/library/src/main/java/uk/co/deanwild/materialshowcaseview/ViewTarget.java b/library/src/main/java/uk/co/deanwild/materialshowcaseview/target/ViewTarget.java similarity index 56% rename from library/src/main/java/uk/co/deanwild/materialshowcaseview/ViewTarget.java rename to library/src/main/java/uk/co/deanwild/materialshowcaseview/target/ViewTarget.java index d855b0d1..8595a2ae 100644 --- a/library/src/main/java/uk/co/deanwild/materialshowcaseview/ViewTarget.java +++ b/library/src/main/java/uk/co/deanwild/materialshowcaseview/target/ViewTarget.java @@ -1,12 +1,11 @@ -package uk.co.deanwild.materialshowcaseview; +package uk.co.deanwild.materialshowcaseview.target; import android.app.Activity; import android.graphics.Point; +import android.graphics.Rect; import android.view.View; -/** - * Created by deanwild on 04/08/15. - */ + public class ViewTarget implements Target { private final View mView; @@ -29,21 +28,14 @@ public Point getPoint() { } @Override - public int getRadius() { - - int radius = 200; - - if (mView != null) { - - if (mView.getMeasuredHeight() > mView.getMeasuredWidth()) { - radius = mView.getMeasuredHeight() / 2; - }else{ - radius = mView.getMeasuredWidth() / 2; - } - - radius += 10; // add a 10 pixel padding to circle - } - - return radius; + public Rect getBounds() { + int[] location = new int[2]; + mView.getLocationInWindow(location); + return new Rect( + location[0], + location[1], + location[0] + mView.getMeasuredWidth(), + location[1] + mView.getMeasuredHeight() + ); } } diff --git a/library/src/main/res/layout/showcase_content.xml b/library/src/main/res/layout/showcase_content.xml index ef7c9c74..efd81d63 100644 --- a/library/src/main/res/layout/showcase_content.xml +++ b/library/src/main/res/layout/showcase_content.xml @@ -5,10 +5,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingBottom="30dp" - android:paddingLeft="15dp" - android:paddingRight="20dp" - android:paddingTop="30dp"> + android:padding="16dp"> + android:textSize="22dp" + android:visibility="gone" /> + \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index d71a32b1..7d2a6aa4 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,13 +1,15 @@ apply plugin: 'com.android.application' +// This does not break the build when Android Studio is missing the JRebel for Android plugin. +apply plugin: 'com.zeroturnaround.jrebel.android' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + compileSdkVersion 23 + buildToolsVersion "23" defaultConfig { applicationId "uk.co.deanwild.materialshowcaseviewsample" minSdkVersion 14 - targetSdkVersion 22 + targetSdkVersion 23 versionCode 1 versionName "1.0" } @@ -21,6 +23,6 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:22.2.0' + compile 'com.android.support:appcompat-v7:23.0.0' compile project(':library') } diff --git a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/CustomExample.java b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/CustomExample.java index 1404803e..344d74f1 100644 --- a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/CustomExample.java +++ b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/CustomExample.java @@ -1,7 +1,7 @@ package uk.co.deanwild.materialshowcaseviewsample; -import android.support.v7.app.ActionBarActivity; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -11,7 +11,7 @@ import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; -public class CustomExample extends ActionBarActivity implements View.OnClickListener { +public class CustomExample extends AppCompatActivity implements View.OnClickListener { private Button mButtonShow; private Button mButtonReset; @@ -32,6 +32,30 @@ protected void onCreate(Bundle savedInstanceState) { presentShowcaseView(1000); // one second delay } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.activity_custom_example, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + if (item.getItemId() == R.id.menu_sample_action) { + View view = findViewById(R.id.menu_sample_action); + new MaterialShowcaseView.Builder(this) + .setTarget(view) + .setShapePadding(96) + .setDismissText("GOT IT") + .setContentText("Example of how to setup a MaterialShowcaseView for menu items in action bar.") + .setContentTextColor(getResources().getColor(R.color.green)) + .setMaskColour(getResources().getColor(R.color.purple)) + .show(); + } + + return super.onOptionsItemSelected(item); + } + @Override public void onClick(View v) { @@ -50,8 +74,8 @@ public void onClick(View v) { private void presentShowcaseView(int withDelay) { new MaterialShowcaseView.Builder(this) .setTarget(mButtonShow) - .setDismissText("GOT IT") .setContentText("This is some amazing feature you should know about") + .setDismissOnTouch(true) .setContentTextColor(getResources().getColor(R.color.green)) .setMaskColour(getResources().getColor(R.color.purple)) .setDelay(withDelay) // optional but starting animations immediately in onCreate can make them choppy diff --git a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/MainActivity.java b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/MainActivity.java index 61c7842a..8f0a3ca8 100644 --- a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/MainActivity.java +++ b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/MainActivity.java @@ -3,14 +3,14 @@ import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.Toast; import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; -public class MainActivity extends ActionBarActivity implements View.OnClickListener { +public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SequenceExample.java b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SequenceExample.java index 29d2a52d..0e75436b 100644 --- a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SequenceExample.java +++ b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SequenceExample.java @@ -1,7 +1,7 @@ package uk.co.deanwild.materialshowcaseviewsample; -import android.support.v7.app.ActionBarActivity; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.Toast; @@ -11,7 +11,7 @@ import uk.co.deanwild.materialshowcaseview.ShowcaseConfig; -public class SequenceExample extends ActionBarActivity implements View.OnClickListener { +public class SequenceExample extends AppCompatActivity implements View.OnClickListener { private Button mButtonOne; private Button mButtonTwo; @@ -63,16 +63,34 @@ private void presentShowcaseSequence() { MaterialShowcaseSequence sequence = new MaterialShowcaseSequence(this, SHOWCASE_ID); - sequence.setConfig(config); - - sequence.addSequenceItem(mButtonOne, - "This is button one", "GOT IT"); + sequence.setOnItemShownListener(new MaterialShowcaseSequence.OnSequenceItemShownListener() { + @Override + public void onShow(MaterialShowcaseView itemView, int position) { + Toast.makeText(itemView.getContext(), "Item #" + position, Toast.LENGTH_SHORT).show(); + } + }); - sequence.addSequenceItem(mButtonTwo, - "This is button two", "GOT IT"); + sequence.setConfig(config); - sequence.addSequenceItem(mButtonThree, - "This is button three", "GOT IT"); + sequence.addSequenceItem(mButtonOne, "This is button one", "GOT IT"); + + sequence.addSequenceItem( + new MaterialShowcaseView.Builder(this) + .setTarget(mButtonTwo) + .setDismissText("GOT IT") + .setContentText("This is button two") + .withRectangleShape(true) + .build() + ); + + sequence.addSequenceItem( + new MaterialShowcaseView.Builder(this) + .setTarget(mButtonThree) + .setDismissText("GOT IT") + .setContentText("This is button three") + .withRectangleShape() + .build() + ); sequence.start(); diff --git a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SimpleSingleExample.java b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SimpleSingleExample.java index bca95d71..222c43b7 100644 --- a/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SimpleSingleExample.java +++ b/sample/src/main/java/uk/co/deanwild/materialshowcaseviewsample/SimpleSingleExample.java @@ -1,7 +1,7 @@ package uk.co.deanwild.materialshowcaseviewsample; -import android.support.v7.app.ActionBarActivity; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.Toast; @@ -9,7 +9,7 @@ import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; -public class SimpleSingleExample extends ActionBarActivity implements View.OnClickListener { +public class SimpleSingleExample extends AppCompatActivity implements View.OnClickListener { private Button mButtonShow; private Button mButtonReset; diff --git a/sample/src/main/res/drawable-xxhdpi/ic_android_white_24dp.png b/sample/src/main/res/drawable-xxhdpi/ic_android_white_24dp.png new file mode 100644 index 00000000..068248ed Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi/ic_android_white_24dp.png differ diff --git a/sample/src/main/res/menu/activity_custom_example.xml b/sample/src/main/res/menu/activity_custom_example.xml new file mode 100644 index 00000000..3540da6e --- /dev/null +++ b/sample/src/main/res/menu/activity_custom_example.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file