diff --git a/README.md b/README.md index 07c7b32..6af32d8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add below dependency in your **build.gradle** file. ```groovy dependencies { - compile 'co.lujun:androidtagview:1.0.3' + compile 'co.lujun:androidtagview:1.0.4' } ``` @@ -75,6 +75,9 @@ Now, you have successfully created some TagViews. The following will show some m | tag_clickable | boolean | Whether TagView can clickable(default unclickable) | tag_theme | enum | The TagView [theme](#themes) | tag_text_direction | enum | The TagView text [direction](#directions) +| tag_ripple_color | color | The ripple effect color(default #EEEEEE) +| tag_ripple_alpha | integer | The ripple effect color alpha(the value may between 0 - 255, default 128) +| tag_ripple_duration | integer | The ripple effect duration(In milliseconds, default 1000ms) **You can set these attributes in layout file, or use setters(each attribute has get and set method) to set them.** @@ -179,6 +182,10 @@ mTagContainerLayout.removeAllTags(); ``` ## Change logs +###1.0.4(2016-10-30) +- Support ripple effect(Call requires API level 11), like [Android CustomButton](https://github.com/whilu/AndroidSample/tree/master/CustomButton) +- fix bugs + ###1.0.3(2016-4-3) - add ```getTags()``` method to get the list for all tags - fixed bugs in ListView/RecyclerView diff --git a/androidtagview/build.gradle b/androidtagview/build.gradle index 8839da5..cb0154f 100644 --- a/androidtagview/build.gradle +++ b/androidtagview/build.gradle @@ -7,8 +7,8 @@ android { defaultConfig { minSdkVersion 9 targetSdkVersion 23 - versionCode 103 - versionName "1.0.3" + versionCode 104 + versionName "1.0.4" } buildTypes { release { diff --git a/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java b/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java index 9b5469a..7ca73bd 100644 --- a/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java +++ b/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java @@ -124,6 +124,15 @@ public class TagContainerLayout extends ViewGroup { /** Default tag min length*/ private static final int TAG_MIN_LENGTH = 3; + /** The ripple effect duration(In milliseconds, default 1000ms)*/ + private int mRippleDuration = 1000; + + /** The ripple effect color(default #EEEEEE)*/ + private int mRippleColor; + + /** The ripple effect color alpha(the value may between 0 - 255, default 128)*/ + private int mRippleAlpha = 128; + public TagContainerLayout(Context context) { this(context, null); } @@ -178,6 +187,9 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr){ mTagTextColor = attributes.getColor(R.styleable.AndroidTagView_tag_text_color, mTagTextColor); mTagTextDirection = attributes.getInt(R.styleable.AndroidTagView_tag_text_direction, mTagTextDirection); isTagViewClickable = attributes.getBoolean(R.styleable.AndroidTagView_tag_clickable, false); + mRippleColor = attributes.getColor(R.styleable.AndroidTagView_tag_ripple_color, Color.parseColor("#EEEEEE")); + mRippleAlpha = attributes.getInteger(R.styleable.AndroidTagView_tag_ripple_alpha, mRippleAlpha); + mRippleDuration = attributes.getInteger(R.styleable.AndroidTagView_tag_ripple_duration, mRippleDuration); attributes.recycle(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -399,6 +411,9 @@ private void initTagView(TagView tagView){ tagView.setIsViewClickable(isTagViewClickable); tagView.setBdDistance(mTagBdDistance); tagView.setOnTagClickListener(mOnTagClickListener); + tagView.setRippleAlpha(mRippleAlpha); + tagView.setRippleColor(mRippleColor); + tagView.setRippleDuration(mRippleDuration); } private void invalidateTags(){ @@ -1011,6 +1026,54 @@ public void setTagTextColor(int color) { this.mTagTextColor = color; } + /** + * Get the ripple effect color's alpha. + * @return + */ + public int getRippleAlpha() { + return mRippleAlpha; + } + + /** + * Set TagView ripple effect alpha, the value may between 0 to 255, default is 128. + * @param mRippleAlpha + */ + public void setRippleAlpha(int mRippleAlpha) { + this.mRippleAlpha = mRippleAlpha; + } + + /** + * Get the ripple effect color. + * @return + */ + public int getRippleColor() { + return mRippleColor; + } + + /** + * Set TagView ripple effect color. + * @param mRippleColor + */ + public void setRippleColor(int mRippleColor) { + this.mRippleColor = mRippleColor; + } + + /** + * Get the ripple effect duration. + * @return + */ + public int getRippleDuration() { + return mRippleDuration; + } + + /** + * Set TagView ripple effect duration, default is 1000ms. + * @param mRippleDuration + */ + public void setRippleDuration(int mRippleDuration) { + this.mRippleDuration = mRippleDuration; + } + public float dp2px(Context context, float dp) { final float scale = context.getResources().getDisplayMetrics().density; return dp * scale + 0.5f; diff --git a/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java b/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java index 2009be1..adedfdc 100644 --- a/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java +++ b/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java @@ -1,10 +1,15 @@ package co.lujun.androidtagview; +import android.animation.ValueAnimator; +import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.RectF; +import android.graphics.Region; import android.graphics.Typeface; +import android.os.Build; import android.support.v4.widget.ViewDragHelper; import android.text.TextUtils; import android.view.MotionEvent; @@ -64,7 +69,7 @@ public class TagView extends View { /** The distance between baseline and descent*/ private float bdDistance; - private Paint mPaint; + private Paint mPaint, mRipplePaint; private RectF mRectF; @@ -75,9 +80,24 @@ public class TagView extends View { private int mLastX, mLastY; private float fontH, fontW; + + private float mTouchX, mTouchY; + + /** The ripple effect duration(default 1000ms)*/ + private int mRippleDuration = 1000; + + private float mRippleRadius; + + private int mRippleColor; + + private int mRippleAlpha; + + private Path mPath; private Typeface mTypeface; + private ValueAnimator mRippleValueAnimator; + private Runnable mLongClickHandle = new Runnable() { @Override public void run() { @@ -98,7 +118,10 @@ public TagView(Context context, String text){ private void init(String text){ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mRipplePaint.setStyle(Paint.Style.FILL); mRectF = new RectF(); + mPath = new Path(); mOriginText = text == null ? "" : text; } @@ -162,6 +185,9 @@ protected void onDraw(Canvas canvas) { canvas.drawText(mAbstractText, getWidth() / 2 - fontW / 2, getHeight() / 2 + fontH / 2 - bdDistance, mPaint); } + + // draw ripple for TagView + drawRipple(canvas); } @Override @@ -192,6 +218,13 @@ public boolean dispatchTouchEvent(MotionEvent event) { @Override public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mRippleRadius = 0.0f; + mTouchX = event.getX(); + mTouchY = event.getY(); + splashRipple(); + } + if (isViewClickable && mOnTagClickListener != null){ int x = (int) event.getX(); int y = (int) event.getY(); @@ -227,6 +260,42 @@ public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void drawRipple(Canvas canvas){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && canvas != null){ + canvas.save(); + mPath.reset(); + + canvas.clipPath(mPath); + mPath.addRoundRect(mRectF, mBorderRadius, mBorderRadius, Path.Direction.CCW); + + canvas.clipPath(mPath, Region.Op.REPLACE); + canvas.drawCircle(mTouchX, mTouchY, mRippleRadius, mRipplePaint); + canvas.restore(); + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void splashRipple(){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && mTouchX > 0 && mTouchY > 0){ + mRipplePaint.setColor(mRippleColor); + mRipplePaint.setAlpha(mRippleAlpha); + final float maxDis = Math.max(Math.max(Math.max(mTouchX, mTouchY), + Math.abs(getMeasuredWidth() - mTouchX)), Math.abs(getMeasuredHeight() - mTouchY)); + + mRippleValueAnimator = ValueAnimator.ofFloat(0.0f, maxDis).setDuration(mRippleDuration); + mRippleValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float animValue = (float) animation.getAnimatedValue(); + mRippleRadius = animValue >= maxDis ? 0 : animValue; + postInvalidate(); + } + }); + mRippleValueAnimator.start(); + } + } + public String getText(){ return mOriginText; } @@ -299,6 +368,18 @@ public void setTypeface(Typeface typeface) { onDealText(); } + public void setRippleAlpha(int mRippleAlpha) { + this.mRippleAlpha = mRippleAlpha; + } + + public void setRippleColor(int mRippleColor) { + this.mRippleColor = mRippleColor; + } + + public void setRippleDuration(int mRippleDuration) { + this.mRippleDuration = mRippleDuration; + } + public void setBdDistance(float bdDistance) { this.bdDistance = bdDistance; } diff --git a/androidtagview/src/main/res/values/attrs.xml b/androidtagview/src/main/res/values/attrs.xml index c0f676a..9a41220 100644 --- a/androidtagview/src/main/res/values/attrs.xml +++ b/androidtagview/src/main/res/values/attrs.xml @@ -38,5 +38,9 @@ + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index c03d0ad..66aa056 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.5.0' - classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' + classpath 'com.android.tools.build:gradle:2.2.1' + classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6216523..c4e826c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Oct 21 11:34:03 PDT 2015 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip +#Sun Oct 30 18:08:28 CST 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/sample/src/main/res/layout/content_main.xml b/sample/src/main/res/layout/content_main.xml index 7be6c24..0a25e7f 100644 --- a/sample/src/main/res/layout/content_main.xml +++ b/sample/src/main/res/layout/content_main.xml @@ -111,6 +111,9 @@ app:container_gravity="center" app:horizontal_interval="10dp" app:tag_clickable="true" + app:tag_ripple_alpha="47" + app:tag_ripple_color="#000000" + app:tag_ripple_duration="2000" app:tag_theme="pure_teal" app:vertical_interval="10dp" />