diff --git a/.travis.yml b/.travis.yml index 20bba8e..a3a152b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,32 @@ language: android -android: - components: - # Uncomment the lines below if you want to - # use the latest revision of Android SDK Tools - # - platform-tools - # - tools - - # The BuildTools version used by your project - - build-tools-25.0.0 +jdk: oraclejdk8 - # The SDK version used to compile your project - - android-25 +env: + global: + - ANDROID_ABI=armeabi-v7a - # Additional components - - extra-google-google_play_services - - extra-google-m2repository +android: + components: + - tools + - android-22 + - android-28 + - sys-img-armeabi-v7a-android-22 - extra-android-m2repository - - addon-google_apis-google-19 + - extra-android-support + - extra + licenses: + - android-sdk-license-.+ + +before_install: + - mkdir "$ANDROID_HOME/licenses" || true + - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - # Specify at least one system image, - # if you need to run emulator(s) during your tests - - sys-img-armeabi-v7a-android-19 - - sys-img-x86-android-17 +before_script: + - chmod +x gradlew + - echo no | android create avd --force -n test -t android-22 --abi $ANDROID_ABI + - emulator -avd test -no-window & + - android-wait-for-emulator + - adb shell input keyevent 82 & -script: ./gradlew assembleDebug \ No newline at end of file +script: + - ./gradlew clean connectedAndroidTest \ No newline at end of file diff --git a/README.md b/README.md index 10cd713..6acc61b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Add below dependency in your **build.gradle** file. ```groovy dependencies { - compile 'co.lujun:androidtagview:1.1.4' + implementation 'co.lujun:androidtagview:1.1.7' + implementation 'androidx.appcompat:appcompat:1.0.1' } ``` @@ -72,7 +73,8 @@ Now, you have successfully created some TagViews. The following will show some m | tag_border_color | color | TagView border color(default #88F44336) | tag_background_color | color | TagView background color(default #33F44336) | tag_max_length | integer | The max length for TagView(default max length 23) -| tag_clickable | boolean | Whether TagView can clickable(default unclickable) +| tag_clickable | boolean | Whether TagView can clickable(default false) +| tag_selectable | boolean | Whether TagView can be selectable(default false) | 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) @@ -92,7 +94,7 @@ Now, you have successfully created some TagViews. The following will show some m |theme|code|value|description |:---:|:---:|:---:|:---:| -| none | ColorFactory.NONE | -1 | If you customize TagView with your way, set this theme +| none | ColorFactory.NONE | -1 | **If you customize TagView with your way, set this theme** | random | ColorFactory.RANDOM | 0 | Create each TagView using random color | pure_cyan | ColorFactory.PURE_CYAN | 1 | All TagView created by pure cyan color | pure_teal | ColorFactory.PURE_TEAL | 2 | All TagView created by pure teal color @@ -127,6 +129,11 @@ mTagContainerLayout.setOnTagClickListener(new TagView.OnTagClickListener() { public void onTagLongClick(final int position, String text) { // ... } + + @Override + public void onSelectedTagDrag(int position, String text){ + // ... + } @Override public void onTagCrossClick(int position) { @@ -199,9 +206,9 @@ mTagContainerLayout.getTagView(int position); * Set color for each TagView. ```java List colors = new ArrayList(); -//int[] color = {TagBackgroundColor, TabBorderColor, TagTextColor} -int[] color1 = {Color.RED, Color.BLACK, Color.WHITE}; -int[] color2 = {Color.BLUE, Color.BLACK, Color.WHITE}; +//int[] color = {TagBackgroundColor, TabBorderColor, TagTextColor, TagSelectedBackgroundColor} +int[] color1 = {Color.RED, Color.BLACK, Color.WHITE, Color.YELLOW}; +int[] color2 = {Color.BLUE, Color.BLACK, Color.WHITE, Color.YELLOW}; colors.add(color1); colors.add(color2); mTagcontainerLayout.setTags(tags, colors); @@ -209,6 +216,15 @@ mTagcontainerLayout.setTags(tags, colors); ## Change logs +### 1.1.7(2019-01-21) +- Fix bugs + +### 1.1.6(2018-12-1) +- Support tag selectable + +### 1.1.5(2018-8-20) +- Allow images on tags (in LTR languages). + ### 1.1.4(2017-6-1) - Add attribute for TagView background. diff --git a/androidtagview/build.gradle b/androidtagview/build.gradle index b819a0e..a04e40a 100644 --- a/androidtagview/build.gradle +++ b/androidtagview/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 25 - buildToolsVersion "25.0.0" + compileSdkVersion 28 defaultConfig { - minSdkVersion 9 - targetSdkVersion 25 - versionCode 114 - versionName "1.1.4" + minSdkVersion 14 + targetSdkVersion 28 + versionCode 117 + versionName "1.1.7" } buildTypes { release { @@ -19,8 +18,8 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:25.0.1' + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.12' + implementation 'androidx.appcompat:appcompat:1.0.1' } apply from: 'https://raw.githubusercontent.com/whilu/AndroidPublishLibrary/master/project/library/bintray_publish.gradle' \ No newline at end of file diff --git a/androidtagview/project.properties b/androidtagview/project.properties new file mode 100644 index 0000000..1a8d96f --- /dev/null +++ b/androidtagview/project.properties @@ -0,0 +1,10 @@ +#project +project.name=AndroidTagView +project.groupId=co.lujun +project.artifactId=androidtagview +project.packaging=aar +project.siteUrl=https://github.com/whilu/AndroidTagView +project.gitUrl=https://github.com/whilu/AndroidTagView.git + +#javadoc +javadoc.name=AndroidTagView \ No newline at end of file diff --git a/androidtagview/src/main/java/co/lujun/androidtagview/ColorFactory.java b/androidtagview/src/main/java/co/lujun/androidtagview/ColorFactory.java index 943813d..f7871b7 100644 --- a/androidtagview/src/main/java/co/lujun/androidtagview/ColorFactory.java +++ b/androidtagview/src/main/java/co/lujun/androidtagview/ColorFactory.java @@ -65,7 +65,8 @@ public static int[] onRandomBuild(){ int bgColor = Color.parseColor("#" + BG_COLOR_ALPHA + COLORS[random]); int bdColor = Color.parseColor("#" + BD_COLOR_ALPHA + COLORS[random]); int tColor = SHARP666666; - return new int[]{bgColor, bdColor, tColor}; + int tColor2 = SHARP727272; + return new int[]{bgColor, bdColor, tColor, tColor2}; } public static int[] onPureBuild(PURE_COLOR type){ @@ -73,7 +74,8 @@ public static int[] onPureBuild(PURE_COLOR type){ int bgColor = Color.parseColor("#" + BG_COLOR_ALPHA + color); int bdColor = Color.parseColor("#" + BD_COLOR_ALPHA + color); int tColor = SHARP727272; - return new int[]{bgColor, bdColor, tColor}; + int tColor2 = SHARP666666; + return new int[]{bgColor, bdColor, tColor, tColor2}; } } diff --git a/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java b/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java index 54ee53e..e36dccf 100644 --- a/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java +++ b/androidtagview/src/main/java/co/lujun/androidtagview/TagContainerLayout.java @@ -23,8 +23,6 @@ import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Typeface; -import android.support.annotation.DrawableRes; -import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.Gravity; import android.view.MotionEvent; @@ -33,8 +31,12 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import androidx.annotation.DrawableRes; +import androidx.customview.widget.ViewDragHelper; + import static co.lujun.androidtagview.Utils.dp2px; import static co.lujun.androidtagview.Utils.sp2px; @@ -144,6 +146,11 @@ public class TagContainerLayout extends ViewGroup { */ private int mTagBackgroundColor = Color.parseColor("#33F44336"); + /** + * Selected TagView background color(default #33FF7669) + */ + private int mSelectedTagBackgroundColor = Color.parseColor("#33FF7669"); + /** * TagView text color(default #FF666666) */ @@ -159,11 +166,21 @@ public class TagContainerLayout extends ViewGroup { */ private boolean isTagViewClickable; + /** + * Whether TagView can selectable(default unselectable) + */ + private boolean isTagViewSelectable; + /** * Tags */ private List mTags; + /** + * Default image for new tags + */ + private int mDefaultImageDrawableID = -1; + /** * Can drag TagView(default false) */ @@ -314,6 +331,7 @@ 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); + isTagViewSelectable = attributes.getBoolean(R.styleable.AndroidTagView_tag_selectable, 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); @@ -502,7 +520,7 @@ private int[] onUpdateColorFactory() { } else if (mTheme == ColorFactory.PURE_CYAN) { colors = ColorFactory.onPureBuild(ColorFactory.PURE_COLOR.CYAN); } else { - colors = new int[]{mTagBackgroundColor, mTagBorderColor, mTagTextColor}; + colors = new int[]{mTagBackgroundColor, mTagBorderColor, mTagTextColor, mSelectedTagBackgroundColor}; } return colors; } @@ -525,7 +543,12 @@ private void onAddTag(String text, int position) { if (position < 0 || position > mChildViews.size()) { throw new RuntimeException("Illegal position!"); } - TagView tagView = new TagView(getContext(), text); + TagView tagView; + if (mDefaultImageDrawableID != -1) { + tagView = new TagView(getContext(), text, mDefaultImageDrawableID); + } else { + tagView = new TagView(getContext(), text); + } initTagView(tagView, position); mChildViews.add(position, tagView); if (position < mChildViews.size()) { @@ -542,7 +565,7 @@ private void initTagView(TagView tagView, int position) { int[] colors; if (mColorArrayList != null && mColorArrayList.size() > 0) { if (mColorArrayList.size() == mTags.size() && - mColorArrayList.get(position).length >= 3) { + mColorArrayList.get(position).length >= 4) { colors = mColorArrayList.get(position); } else { throw new RuntimeException("Illegal color list!"); @@ -554,6 +577,7 @@ private void initTagView(TagView tagView, int position) { tagView.setTagBackgroundColor(colors[0]); tagView.setTagBorderColor(colors[1]); tagView.setTagTextColor(colors[2]); + tagView.setTagSelectedBackgroundColor(colors[3]); tagView.setTagMaxLength(mTagMaxLength); tagView.setTextDirection(mTagTextDirection); tagView.setTypeface(mTagTypeface); @@ -563,6 +587,7 @@ private void initTagView(TagView tagView, int position) { tagView.setHorizontalPadding(mTagHorizontalPadding); tagView.setVerticalPadding(mTagVerticalPadding); tagView.setIsViewClickable(isTagViewClickable); + tagView.setIsViewSelectable(isTagViewSelectable); tagView.setBdDistance(mTagBdDistance); tagView.setOnTagClickListener(mOnTagClickListener); tagView.setRippleAlpha(mRippleAlpha); @@ -596,6 +621,21 @@ private void onRemoveTag(int position) { // TODO, make removed view null? } + private void onRemoveConsecutiveTags(List positions) { + int smallestPosition = Collections.min(positions); + for (int position : positions) { + if (position < 0 || position >= mChildViews.size()) { + throw new RuntimeException("Illegal position!"); + } + mChildViews.remove(smallestPosition); + removeViewAt(smallestPosition); + } + for (int i = smallestPosition; i < mChildViews.size(); i++) { + mChildViews.get(i).setTag(i); + } + // TODO, make removed view null? + } + private int[] onGetNewPosition(View view) { int left = view.getLeft(); int top = view.getTop(); @@ -792,6 +832,16 @@ public void removeTag(int position) { postInvalidate(); } + /** + * Remove TagView in multiple consecutive positions. + * + * + */ + public void removeConsecutiveTags(List positions) { + onRemoveConsecutiveTags(positions); + postInvalidate(); + } + /** * Remove all TagViews. */ @@ -811,6 +861,82 @@ public void setOnTagClickListener(TagView.OnTagClickListener listener) { invalidateTags(); } + /** + * Toggle select a tag + * + * @param position + */ + public void toggleSelectTagView(int position) { + if (isTagViewSelectable){ + TagView tagView = ((TagView)mChildViews.get(position)); + if (tagView.getIsViewSelected()){ + tagView.deselectView(); + } else { + tagView.selectView(); + } + } + } + + /** + * Select a tag + * + * @param position + */ + public void selectTagView(int position) { + if (isTagViewSelectable) + ((TagView)mChildViews.get(position)).selectView(); + } + + /** + * Deselect a tag + * + * @param position + */ + public void deselectTagView(int position) { + if (isTagViewSelectable) + ((TagView)mChildViews.get(position)).deselectView(); + } + + /** + * Return selected TagView positions + * + * @return list of selected positions + */ + public List getSelectedTagViewPositions() { + List selectedPositions = new ArrayList<>(); + for (int i = 0; i < mChildViews.size(); i++){ + if (((TagView)mChildViews.get(i)).getIsViewSelected()){ + selectedPositions.add(i); + } + } + return selectedPositions; + } + + /** + * Return selected TagView text + * + * @return list of selected tag text + */ + public List getSelectedTagViewText() { + List selectedTagText = new ArrayList<>(); + for (int i = 0; i < mChildViews.size(); i++){ + TagView tagView = (TagView)mChildViews.get(i); + if ((tagView.getIsViewSelected())){ + selectedTagText.add(tagView.getText()); + } + } + return selectedTagText; + } + + /** + * Return number of child tags + * + * @return size + */ + public int size() { + return mChildViews.size(); + } + /** * Get TagView text. * @@ -1000,6 +1126,24 @@ public void setSensitivity(float sensitivity) { this.mSensitivity = sensitivity; } + /** + * Get default tag image + * + * @return + */ + public int getDefaultImageDrawableID() { + return mDefaultImageDrawableID; + } + + /** + * Set default image for tags. + * + * @param imageID + */ + public void setDefaultImageDrawableID(int imageID) { + this.mDefaultImageDrawableID = imageID; + } + /** * Set max line count for TagContainerLayout * @@ -1073,6 +1217,24 @@ public void setIsTagViewClickable(boolean clickable) { this.isTagViewClickable = clickable; } + /** + * Get TagView is selectable. + * + * @return + */ + public boolean getIsTagViewSelectable() { + return isTagViewSelectable; + } + + /** + * Set TagView is selectable + * + * @param selectable + */ + public void setIsTagViewSelectable(boolean selectable) { + this.isTagViewSelectable= selectable; + } + /** * Get TagView border width. * diff --git a/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java b/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java index 9afd66d..1a93975 100644 --- a/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java +++ b/androidtagview/src/main/java/co/lujun/androidtagview/TagView.java @@ -19,18 +19,23 @@ import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.Region; +import android.graphics.Shader; import android.graphics.Typeface; import android.os.Build; -import android.support.v4.widget.ViewDragHelper; import android.text.TextUtils; import android.view.MotionEvent; import android.view.View; +import androidx.customview.widget.ViewDragHelper; + import static co.lujun.androidtagview.Utils.dp2px; /** @@ -60,12 +65,21 @@ public class TagView extends View { /** TagView background color*/ private int mBackgroundColor; + /** TagView background color*/ + private int mSelectedBackgroundColor; + /** TagView text color*/ private int mTextColor; /** Whether this view clickable*/ private boolean isViewClickable; + /** Whether this view selectable*/ + private boolean isViewSelectable; + + /** Whether this view selected*/ + private boolean isViewSelected; + /** The max length for this tag view*/ private int mTagMaxLength; @@ -119,6 +133,8 @@ public class TagView extends View { private ValueAnimator mRippleValueAnimator; + private Bitmap mBitmapImage; + private boolean mEnableCross; private float mCrossAreaWidth; @@ -149,6 +165,12 @@ public TagView(Context context, String text){ init(context, text); } + public TagView(Context context, String text, int defaultImageID){ + super(context); + init(context, text); + mBitmapImage = BitmapFactory.decodeResource(getResources(), defaultImageID); + } + private void init(Context context, String text){ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -186,7 +208,7 @@ private void onDealText(){ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int height = mVerticalPadding * 2 + (int) fontH; - int width = mHorizontalPadding * 2 + (int) fontW + (isEnableCross() ? height : 0); + int width = mHorizontalPadding * 2 + (int) fontW + (isEnableCross() ? height : 0) + (isEnableImage() ? height : 0); mCrossAreaWidth = Math.min(Math.max(mCrossAreaWidth, height), width); setMeasuredDimension(width, height); } @@ -201,7 +223,7 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { protected void onDraw(Canvas canvas) { // draw background mPaint.setStyle(Paint.Style.FILL); - mPaint.setColor(mBackgroundColor); + mPaint.setColor(getIsViewSelected() ? mSelectedBackgroundColor : mBackgroundColor); canvas.drawRoundRect(mRectF, mBorderRadius, mBorderRadius, mPaint); // draw border @@ -233,12 +255,15 @@ protected void onDraw(Canvas canvas) { } } else { canvas.drawText(mAbstractText, - (isEnableCross() ? getWidth() - getHeight() : getWidth()) / 2 - fontW / 2, + (isEnableCross() ? getWidth() - getHeight() : getWidth()) / 2 - fontW / 2 + (isEnableImage() ? getHeight() / 2 : 0), getHeight() / 2 + fontH / 2 - bdDistance, mPaint); } // draw cross drawCross(canvas); + + // draw image + drawImage(canvas); } @Override @@ -257,8 +282,8 @@ public boolean dispatchTouchEvent(MotionEvent event) { break; case MotionEvent.ACTION_MOVE: - if (Math.abs(mLastY - y) > mSlopThreshold - || Math.abs(mLastX - x) > mSlopThreshold){ + if (!isViewSelected && (Math.abs(mLastY - y) > mSlopThreshold + || Math.abs(mLastX - x) > mSlopThreshold)){ if (getParent() != null) { getParent().requestDisallowInterceptTouchEvent(false); } @@ -304,6 +329,9 @@ public boolean onTouchEvent(MotionEvent event) { } if (Math.abs(mLastX - x) > mMoveSlop || Math.abs(mLastY - y) > mMoveSlop){ isMoved = true; + if (isViewSelected){ + mOnTagClickListener.onSelectedTagDrag((int) getTag(), getText()); + } } break; @@ -326,6 +354,18 @@ private boolean isClickCrossArea(MotionEvent event){ return event.getX() >= getWidth() - mCrossAreaWidth; } + private void drawImage(Canvas canvas){ + if (isEnableImage()) { + Bitmap scaledImageBitmap = Bitmap.createScaledBitmap(mBitmapImage, Math.round(getHeight() - mBorderWidth), Math.round(getHeight() - mBorderWidth), false); + + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setShader(new BitmapShader(scaledImageBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + RectF rect = new RectF(mBorderWidth, mBorderWidth, getHeight() - mBorderWidth, getHeight() - mBorderWidth); + canvas.drawRoundRect(rect, rect.height()/2, rect.height()/2, paint); + } + } + private void drawCross(Canvas canvas){ if (isEnableCross()){ mCrossAreaPadding = mCrossAreaPadding > getHeight() / 2 ? getHeight() / 2 : @@ -372,7 +412,13 @@ private void drawRipple(Canvas canvas){ canvas.clipPath(mPath); mPath.addRoundRect(mRectF, mBorderRadius, mBorderRadius, Path.Direction.CCW); - canvas.clipPath(mPath, Region.Op.REPLACE); +// bug: https://github.com/whilu/AndroidTagView/issues/88 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + canvas.clipPath(mPath); + } else { + canvas.clipPath(mPath, Region.Op.REPLACE); + } + canvas.drawCircle(mTouchX, mTouchY, mRippleRadius, mRipplePaint); canvas.restore(); }catch (UnsupportedOperationException e){ @@ -410,6 +456,10 @@ public boolean getIsViewClickable(){ return isViewClickable; } + public boolean getIsViewSelected(){ + return isViewSelected; + } + public void setTagMaxLength(int maxLength){ this.mTagMaxLength = maxLength; onDealText(); @@ -419,10 +469,22 @@ public void setOnTagClickListener(OnTagClickListener listener){ this.mOnTagClickListener = listener; } + public int getTagBackgroundColor(){ + return mBackgroundColor; + } + + public int getTagSelectedBackgroundColor(){ + return mSelectedBackgroundColor; + } + public void setTagBackgroundColor(int color){ this.mBackgroundColor = color; } + public void setTagSelectedBackgroundColor(int color){ + this.mSelectedBackgroundColor = color; + } + public void setTagBorderColor(int color){ this.mBorderColor = color; } @@ -456,9 +518,34 @@ public void setIsViewClickable(boolean clickable) { this.isViewClickable = clickable; } + public void setImage(Bitmap newImage) { + this.mBitmapImage = newImage; + this.invalidate(); + } + + public void setIsViewSelectable(boolean viewSelectable) { + isViewSelectable = viewSelectable; + } + + //TODO change background color + public void selectView() { + if (isViewSelectable && !getIsViewSelected()) { + this.isViewSelected = true; + postInvalidate(); + } + } + + public void deselectView() { + if (isViewSelectable && getIsViewSelected()) { + this.isViewSelected = false; + postInvalidate(); + } + } + public interface OnTagClickListener{ void onTagClick(int position, String text); void onTagLongClick(int position, String text); + void onSelectedTagDrag(int position, String text); void onTagCrossClick(int position); } @@ -491,6 +578,8 @@ public void setBdDistance(float bdDistance) { this.bdDistance = bdDistance; } + public boolean isEnableImage() { return mBitmapImage != null && mTextDirection != View.TEXT_DIRECTION_RTL; } + public boolean isEnableCross() { return mEnableCross; } diff --git a/androidtagview/src/main/java/co/lujun/androidtagview/Utils.java b/androidtagview/src/main/java/co/lujun/androidtagview/Utils.java index 6691bcf..c2b68de 100644 --- a/androidtagview/src/main/java/co/lujun/androidtagview/Utils.java +++ b/androidtagview/src/main/java/co/lujun/androidtagview/Utils.java @@ -17,6 +17,7 @@ package co.lujun.androidtagview; import android.content.Context; +import android.graphics.Color; /** * Author: lujun(http://blog.lujun.co) @@ -34,4 +35,31 @@ public static float sp2px(Context context, float sp) { final float scale = context.getResources().getDisplayMetrics().scaledDensity; return sp * scale; } + + /** + * If the color is Dark, make it lighter and vice versa + * + * @param color in int, + * @param factor The factor greater than 0.0 and smaller than 1.0 + * @return int + */ + public static int manipulateColorBrightness(int color, float factor) { + int a = Color.alpha(color); + int r = Color.red(color); + int g = Color.green(color); + int b = Color.blue(color); +// if (r + b + g < 128 * 3) factor = 1 / factor;// check if the color is bright or dark +// r = Math.round(r * factor); +// b = Math.round(b * factor); +// g = Math.round(g * factor); + if (r > 127) r = 255 - Math.round((255 - r) * factor); + if (g > 127) g = 255 - Math.round((255 - g) * factor); + if (b > 127) b = 255 - Math.round((255 - b) * factor); + + return Color.argb(a, + Math.min(r, 255), + Math.min(g, 255), + Math.min(b, 255) + ); + } } diff --git a/androidtagview/src/main/res/values/attrs.xml b/androidtagview/src/main/res/values/attrs.xml index 6821af5..098f9a9 100644 --- a/androidtagview/src/main/res/values/attrs.xml +++ b/androidtagview/src/main/res/values/attrs.xml @@ -28,6 +28,7 @@ + diff --git a/build.gradle b/build.gradle index 45efda8..a115e91 100644 --- a/build.gradle +++ b/build.gradle @@ -3,11 +3,12 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.2' + classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -17,6 +18,7 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle.properties b/gradle.properties index 629cc7b..a565221 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,3 +13,5 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sun Jan 24 18:50:31 CST 2016 +android.useAndroidX=true +android.enableJetifier=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c4e826c..1be1c62 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Oct 30 18:08:28 CST 2016 +#Thu Jun 14 09:04:10 ICT 2018 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 +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip diff --git a/sample/build.gradle b/sample/build.gradle index 9435b08..db7ac6a 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,13 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.0" + compileSdkVersion 28 defaultConfig { applicationId "co.lujun.sample" - minSdkVersion 9 - targetSdkVersion 25 + minSdkVersion 14 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -19,10 +18,16 @@ android { } } +repositories { + mavenCentral() + maven { url 'https://maven.google.com' } +} + dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile project(':androidtagview') - testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:25.0.1' - compile 'com.android.support:design:25.0.1' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':androidtagview') + testImplementation 'junit:junit:4.12' + implementation 'androidx.appcompat:appcompat:1.0.1' + implementation 'com.google.android.material:material:1.0.0' + implementation 'com.github.bumptech.glide:glide:4.1.1' } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index b96d3e8..e56e5f9 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -19,5 +19,5 @@ - + diff --git a/sample/src/main/java/co/lujun/sample/MainActivity.java b/sample/src/main/java/co/lujun/sample/MainActivity.java index 3253051..9399ad4 100644 --- a/sample/src/main/java/co/lujun/sample/MainActivity.java +++ b/sample/src/main/java/co/lujun/sample/MainActivity.java @@ -1,13 +1,12 @@ package co.lujun.sample; import android.app.AlertDialog; +import android.content.ClipData; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,9 +14,17 @@ import android.widget.EditText; import android.widget.Toast; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; + import java.util.ArrayList; import java.util.List; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.RecyclerView; import co.lujun.androidtagview.TagContainerLayout; import co.lujun.androidtagview.TagView; @@ -73,6 +80,8 @@ protected void onCreate(Bundle savedInstanceState) { mTagContainerLayout4 = (TagContainerLayout) findViewById(R.id.tagcontainerLayout4); mTagcontainerLayout5 = (TagContainerLayout) findViewById(R.id.tagcontainerLayout5); + mTagContainerLayout1.setDefaultImageDrawableID(R.drawable.yellow_avatar); + // Set custom click listener mTagContainerLayout1.setOnTagClickListener(new TagView.OnTagClickListener() { @Override @@ -104,6 +113,9 @@ public void onClick(DialogInterface dialog, int which) { dialog.show(); } + @Override + public void onSelectedTagDrag(int position, String text) {} + @Override public void onTagCrossClick(int position) { // mTagContainerLayout1.removeTag(position); @@ -112,6 +124,45 @@ public void onTagCrossClick(int position) { } }); + mTagContainerLayout3.setOnTagClickListener(new TagView.OnTagClickListener() { + @Override + public void onTagClick(int position, String text) { + List selectedPositions = mTagContainerLayout3.getSelectedTagViewPositions(); + //deselect all tags when click on an unselected tag. Otherwise show toast. + if (selectedPositions.isEmpty() || selectedPositions.contains(position)) { + Toast.makeText(MainActivity.this, "click-position:" + position + ", text:" + text, + Toast.LENGTH_SHORT).show(); + } else { + //deselect all tags + for (int i : selectedPositions) { + mTagContainerLayout3.deselectTagView(i); + } + } + + } + + @Override + public void onTagLongClick(final int position, String text) { + mTagContainerLayout3.toggleSelectTagView(position); + + List selectedPositions = mTagContainerLayout3.getSelectedTagViewPositions(); + Toast.makeText(MainActivity.this, "selected-positions:" + selectedPositions.toString(), + Toast.LENGTH_SHORT).show(); + } + + @Override + public void onSelectedTagDrag(int position, String text) { + ClipData clip = ClipData.newPlainText("Text", text); + View view = mTagContainerLayout3.getTagView(position); + View.DragShadowBuilder shadow = new View.DragShadowBuilder(view); + view.startDrag(clip, shadow, Boolean.TRUE, 0); + } + + @Override + public void onTagCrossClick(int position) { + } + }); + // Custom settings // mTagContainerLayout1.setTagMaxLength(4); @@ -132,14 +183,15 @@ public void onTagCrossClick(int position) { // After you set your own attributes for TagView, then set tag(s) or add tag(s) mTagContainerLayout1.setTags(list1); + loadImages(list1); mTagContainerLayout2.setTags(list2); mTagContainerLayout3.setTags(list3); mTagContainerLayout4.setTags(list4); List colors = new ArrayList(); - //int[]color = {backgroundColor, tagBorderColor, tagTextColor} - int[] col1 = {Color.parseColor("#ff0000"), Color.parseColor("#000000"), Color.parseColor("#ffffff")}; - int[] col2 = {Color.parseColor("#0000ff"), Color.parseColor("#000000"), Color.parseColor("#ffffff")}; + //int[]color = {backgroundColor, tagBorderColor, tagTextColor, tagSelectedBackgroundColor} + int[] col1 = {Color.parseColor("#ff0000"), Color.parseColor("#000000"), Color.parseColor("#ffffff"), Color.parseColor("#999999")}; + int[] col2 = {Color.parseColor("#0000ff"), Color.parseColor("#000000"), Color.parseColor("#ffffff"), Color.parseColor("#999999")}; colors.add(col1); colors.add(col2); @@ -172,6 +224,31 @@ public void onClick(View v) { // recyclerView.setAdapter(adapter); } + private void loadImages(List list) { + String[] avatars = new String[]{"https://forums.oneplus.com/data/avatars/m/231/231279.jpg", + "https://d1marr3m5x4iac.cloudfront.net/images/block/movies/17214/17214_aa.jpg", + "https://lh3.googleusercontent.com/-KSI1bJ1aVS4/AAAAAAAAAAI/AAAAAAAAB9c/Vrgt6WyS5OU/il/photo.jpg"}; + + for (int i=0; i() { + @Override + public void onResourceReady(Bitmap resource, Transition transition) { + mTagContainerLayout1.getTagView(index).setImage(resource); + } + }); + try { + Thread.sleep(50); + } catch (InterruptedException e) { + System.err.println(e.getMessage()); + } + } + } + public class TagRecyclerViewAdapter extends RecyclerView.Adapter { diff --git a/sample/src/main/res/drawable/yellow_avatar.png b/sample/src/main/res/drawable/yellow_avatar.png new file mode 100644 index 0000000..605a8e7 Binary files /dev/null and b/sample/src/main/res/drawable/yellow_avatar.png differ diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index a440a0b..12311a8 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - - - + - + diff --git a/sample/src/main/res/layout/content_main.xml b/sample/src/main/res/layout/content_main.xml index 70c532b..bb89e68 100644 --- a/sample/src/main/res/layout/content_main.xml +++ b/sample/src/main/res/layout/content_main.xml @@ -13,12 +13,11 @@ tools:context="co.lujun.sample.MainActivity" tools:showIn="@layout/activity_main"> - + android:visibility="gone" />