diff --git a/build.gradle b/build.gradle index cd74ded..f61bf88 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:3.0.1' } } @@ -15,5 +16,6 @@ allprojects { repositories { jcenter() + google() } } \ No newline at end of file diff --git a/demo/build.gradle b/demo/build.gradle index 8b3ed8d..5948a6e 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 21 - buildToolsVersion '21.1.1' + compileSdkVersion 27 + buildToolsVersion '26.0.2' defaultConfig { applicationId 'me.gujun.android.taggroup.demo' - minSdkVersion 8 - targetSdkVersion 21 + minSdkVersion 19 + targetSdkVersion 27 versionName project.VERSION_NAME versionCode Integer.parseInt(project.VERSION_CODE) } @@ -22,5 +22,6 @@ android { dependencies { compile project(':library') - compile 'com.android.support:appcompat-v7:21.0.3' + compile 'com.android.support:appcompat-v7:27.0.2' + } \ No newline at end of file diff --git a/demo/src/main/assets/font/Lobster-Regular.ttf b/demo/src/main/assets/font/Lobster-Regular.ttf new file mode 100755 index 0000000..5e848bb Binary files /dev/null and b/demo/src/main/assets/font/Lobster-Regular.ttf differ diff --git a/demo/src/main/java/me/gujun/android/taggroup/demo/MainActivity.java b/demo/src/main/java/me/gujun/android/taggroup/demo/MainActivity.java index 872bf9f..8664e17 100644 --- a/demo/src/main/java/me/gujun/android/taggroup/demo/MainActivity.java +++ b/demo/src/main/java/me/gujun/android/taggroup/demo/MainActivity.java @@ -1,6 +1,7 @@ package me.gujun.android.taggroup.demo; import android.content.Intent; +import android.graphics.Typeface; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; @@ -9,6 +10,10 @@ import android.widget.TextView; import android.widget.Toast; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import me.gujun.android.taggroup.TagGroup; import me.gujun.android.taggroup.demo.db.TagsManager; @@ -36,10 +41,14 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTagsManager = TagsManager.getInstance(getApplicationContext()); - String[] tags = mTagsManager.getTags(); + List tags = new ArrayList<>(); + tags.add(new TagData(0L, "hello")); + tags.add(new TagData(0L, "how")); + tags.add(new TagData(0L, "are")); + tags.add(new TagData(0L, "you")); mPromptText = (TextView) findViewById(R.id.tv_prompt); - mPromptText.setVisibility((tags == null || tags.length == 0) ? View.VISIBLE : View.GONE); + mPromptText.setVisibility((tags == null || tags.size() == 0) ? View.VISIBLE : View.GONE); mPromptText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -52,7 +61,10 @@ public void onClick(View v) { mLargeTagGroup = (TagGroup) findViewById(R.id.tag_group_large); mBeautyTagGroup = (TagGroup) findViewById(R.id.tag_group_beauty); mBeautyInverseTagGroup = (TagGroup) findViewById(R.id.tag_group_beauty_inverse); - if (tags != null && tags.length > 0) { +// font/Lobster-Regular.ttf + mLargeTagGroup.setCustomTypeface(Typeface.createFromAsset(getAssets(), "font/Lobster-Regular.ttf")); + mBeautyInverseTagGroup.showDeleteBtn(R.drawable.letter_x); + if (tags != null && tags.size() > 0) { mDefaultTagGroup.setTags(tags); mSmallTagGroup.setTags(tags); mLargeTagGroup.setTags(tags); @@ -78,8 +90,13 @@ public void onClick(View v) { @Override protected void onResume() { super.onResume(); - String[] tags = mTagsManager.getTags(); - mPromptText.setVisibility((tags == null || tags.length == 0) ? View.VISIBLE : View.GONE); + + List tags = new ArrayList<>(); + tags.add(new TagData(0L, "hello")); + tags.add(new TagData(0L, "how")); + tags.add(new TagData(0L, "are")); + tags.add(new TagData(0L, "you")); + mPromptText.setVisibility((tags == null || tags.size() == 0) ? View.VISIBLE : View.GONE); mDefaultTagGroup.setTags(tags); mSmallTagGroup.setTags(tags); mLargeTagGroup.setTags(tags); diff --git a/demo/src/main/java/me/gujun/android/taggroup/demo/TagData.java b/demo/src/main/java/me/gujun/android/taggroup/demo/TagData.java new file mode 100644 index 0000000..43b852c --- /dev/null +++ b/demo/src/main/java/me/gujun/android/taggroup/demo/TagData.java @@ -0,0 +1,69 @@ +package me.gujun.android.taggroup.demo; + +import android.os.Parcel; +import android.os.Parcelable; + +public class TagData implements Parcelable { + + + public TagData(Long id, String name) { + this.id = id; + this.name = name; + } + + private Long id; + private String name; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeValue(this.id); + dest.writeString(this.name); + } + + public TagData() { + } + + protected TagData(Parcel in) { + this.id = (Long) in.readValue(Long.class.getClassLoader()); + this.name = in.readString(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public TagData createFromParcel(Parcel source) { + return new TagData(source); + } + + @Override + public TagData[] newArray(int size) { + return new TagData[size]; + } + }; +} diff --git a/demo/src/main/java/me/gujun/android/taggroup/demo/TagEditorActivity.java b/demo/src/main/java/me/gujun/android/taggroup/demo/TagEditorActivity.java index 27d2ea1..0f8fe40 100644 --- a/demo/src/main/java/me/gujun/android/taggroup/demo/TagEditorActivity.java +++ b/demo/src/main/java/me/gujun/android/taggroup/demo/TagEditorActivity.java @@ -5,6 +5,9 @@ import android.view.Menu; import android.view.MenuItem; +import java.util.Arrays; +import java.util.List; + import me.gujun.android.taggroup.TagGroup; import me.gujun.android.taggroup.demo.db.TagsManager; @@ -19,7 +22,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_tag_editor); mTagsManager = TagsManager.getInstance(getApplicationContext()); - String[] tags = mTagsManager.getTags(); + List tags = Arrays.asList(mTagsManager.getTags()); mTagGroup = (TagGroup) findViewById(R.id.tag_group); mTagGroup.setTags(tags); @@ -34,7 +37,7 @@ public boolean onCreateOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { - mTagsManager.updateTags(mTagGroup.getTags()); +// mTagsManager.updateTags(mTagGroup.getTags()); finish(); return true; } else if (item.getItemId() == R.id.action_submit) { @@ -46,7 +49,7 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override public void onBackPressed() { - mTagsManager.updateTags(mTagGroup.getTags()); +// mTagsManager.updateTags(mTagGroup.getTags()); super.onBackPressed(); } } \ No newline at end of file diff --git a/demo/src/main/res/drawable-xxxhdpi/letter_x.png b/demo/src/main/res/drawable-xxxhdpi/letter_x.png new file mode 100644 index 0000000..f9275da Binary files /dev/null and b/demo/src/main/res/drawable-xxxhdpi/letter_x.png differ diff --git a/gradle.properties b/gradle.properties index e61bff9..0af6bb9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -VERSION_NAME=1.4 +VERSION_NAME=1.5 VERSION_CODE=14 GROUP=me.gujun.android.taggroup diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0c71e76..000902d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Apr 10 15:27:10 PDT 2013 +#Mon Oct 30 12:02:15 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/library/build.gradle b/library/build.gradle index 87bfd43..d9398af 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,10 +1,10 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 21 - buildToolsVersion '21.1.1' + compileSdkVersion 27 + buildToolsVersion '26.0.2' defaultConfig { - minSdkVersion 8 - targetSdkVersion 21 + minSdkVersion 18 + targetSdkVersion 27 } lintOptions { abortOnError false diff --git a/library/src/main/java/me/gujun/android/taggroup/TagGroup.java b/library/src/main/java/me/gujun/android/taggroup/TagGroup.java index 5f2ae99..79d8079 100644 --- a/library/src/main/java/me/gujun/android/taggroup/TagGroup.java +++ b/library/src/main/java/me/gujun/android/taggroup/TagGroup.java @@ -10,6 +10,7 @@ import android.graphics.PathEffect; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Typeface; import android.os.Parcel; import android.os.Parcelable; import android.text.Editable; @@ -49,7 +50,7 @@ * @version 2.0 * @since 2015-2-3 14:16:32 */ -public class TagGroup extends ViewGroup { +public class TagGroup extends ViewGroup { private final int default_border_color = Color.rgb(0x49, 0xC1, 0x20); private final int default_text_color = Color.rgb(0x49, 0xC1, 0x20); private final int default_background_color = Color.WHITE; @@ -68,72 +69,122 @@ public class TagGroup extends ViewGroup { private final float default_horizontal_padding; private final float default_vertical_padding; - /** Indicates whether this TagGroup is set up to APPEND mode or DISPLAY mode. Default is false. */ + /** + * Indicates whether this TagGroup is set up to APPEND mode or DISPLAY mode. Default is false. + */ private boolean isAppendMode; - /** The text to be displayed when the text of the INPUT tag is empty. */ + /** + * The text to be displayed when the text of the INPUT tag is empty. + */ private CharSequence inputHint; - /** The tag outline border color. */ + /** + * The tag outline border color. + */ private int borderColor; - /** The tag text color. */ + /** + * The tag text color. + */ private int textColor; - /** The tag background color. */ + /** + * The tag background color. + */ private int backgroundColor; - /** The dash outline border color. */ + /** + * The dash outline border color. + */ private int dashBorderColor; - /** The input tag hint text color. */ + /** + * The input tag hint text color. + */ private int inputHintColor; - /** The input tag type text color. */ + /** + * The input tag type text color. + */ private int inputTextColor; - /** The checked tag outline border color. */ + /** + * The checked tag outline border color. + */ private int checkedBorderColor; - /** The check text color */ + /** + * The check text color + */ private int checkedTextColor; - /** The checked marker color. */ + /** + * The checked marker color. + */ private int checkedMarkerColor; - /** The checked tag background color. */ + /** + * The checked tag background color. + */ private int checkedBackgroundColor; - /** The tag background color, when the tag is being pressed. */ + /** + * The tag background color, when the tag is being pressed. + */ private int pressedBackgroundColor; - /** The tag outline border stroke width, default is 0.5dp. */ + /** + * The tag outline border stroke width, default is 0.5dp. + */ private float borderStrokeWidth; - /** The tag text size, default is 13sp. */ + /** + * The tag text size, default is 13sp. + */ private float textSize; - /** The horizontal tag spacing, default is 8.0dp. */ + /** + * The horizontal tag spacing, default is 8.0dp. + */ private int horizontalSpacing; - /** The vertical tag spacing, default is 4.0dp. */ + /** + * The vertical tag spacing, default is 4.0dp. + */ private int verticalSpacing; - /** The horizontal tag padding, default is 12.0dp. */ + /** + * The horizontal tag padding, default is 12.0dp. + */ private int horizontalPadding; - /** The vertical tag padding, default is 3.0dp. */ + /** + * The vertical tag padding, default is 3.0dp. + */ private int verticalPadding; - /** Listener used to dispatch tag change event. */ + /** + * Listener used to dispatch tag change event. + */ private OnTagChangeListener mOnTagChangeListener; - /** Listener used to dispatch tag click event. */ + /** + * Listener used to dispatch tag click event. + */ private OnTagClickListener mOnTagClickListener; - /** Listener used to handle tag click event. */ + /** + * Listener used to handle tag click event. + */ private InternalTagClickListener mInternalTagClickListener = new InternalTagClickListener(); + private Typeface mCustomTypeface; + + private Integer mDeleteResources; + + private List mTags; + public TagGroup(Context context) { this(context, null); } @@ -372,34 +423,20 @@ protected TagView getLastNormalTagView() { * * @return the tag array. */ - public String[] getTags() { - final int count = getChildCount(); - final List tagList = new ArrayList<>(); - for (int i = 0; i < count; i++) { - final TagView tagView = getTagAt(i); - if (tagView.mState == TagView.STATE_NORMAL) { - tagList.add(tagView.getText().toString()); - } - } - - return tagList.toArray(new String[tagList.size()]); + public List getTags() { + return mTags; } - /** - * @see #setTags(String...) - */ - public void setTags(List tagList) { - setTags(tagList.toArray(new String[tagList.size()])); + + public void setTags(List tagList) { + this.mTags = tagList != null ? tagList : new ArrayList(); + updateTags(); } - /** - * Set the tags. It will remove all previous tags first. - * - * @param tags the tag list to set. - */ - public void setTags(String... tags) { + + private void updateTags() { removeAllViews(); - for (final String tag : tags) { + for (final E tag : mTags) { appendTag(tag); } @@ -408,6 +445,14 @@ public void setTags(String... tags) { } } + public void setCustomTypeface(Typeface customTypeface) { + this.mCustomTypeface = customTypeface; + } + + public void showDeleteBtn(Integer deleteResources) { + this.mDeleteResources = deleteResources; + } + /** * Returns the tag view at the specified position in the group. * @@ -475,7 +520,9 @@ protected void appendInputTag(String tag) { throw new IllegalStateException("Already has a INPUT tag in group."); } - final TagView newInputTag = new TagView(getContext(), TagView.STATE_INPUT, tag); + final TagView newInputTag = mCustomTypeface != null ? new TagView(getContext(), TagView.STATE_INPUT, tag, mCustomTypeface) : new TagView(getContext(), TagView.STATE_INPUT, tag); + if (mDeleteResources != null) + newInputTag.setDeleteButtonResId(mDeleteResources); newInputTag.setOnClickListener(mInternalTagClickListener); addView(newInputTag); } @@ -485,8 +532,10 @@ protected void appendInputTag(String tag) { * * @param tag the tag to append. */ - protected void appendTag(CharSequence tag) { - final TagView newTag = new TagView(getContext(), TagView.STATE_NORMAL, tag); + protected void appendTag(E tag) { + final TagView newTag = mCustomTypeface != null ? new TagView(getContext(), TagView.STATE_NORMAL, tag.toString(), mCustomTypeface) : new TagView(getContext(), TagView.STATE_NORMAL, tag.toString()); + if (mDeleteResources != null) + newTag.setDeleteButtonResId(mDeleteResources); newTag.setOnClickListener(mInternalTagClickListener); addView(newTag); } @@ -569,27 +618,35 @@ public LayoutParams(int width, int height) { /** * For {@link TagGroup} save and restore state. */ - static class SavedState extends BaseSavedState { - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } + static class SavedState extends BaseSavedState { + public static final Creator CREATOR = new Creator() { + @Override + public SavedState createFromParcel(Parcel source) { + return new SavedState(source); + } - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; int tagCount; - String[] tags; + List tags; int checkedPosition; String input; public SavedState(Parcel source) { super(source); tagCount = source.readInt(); - tags = new String[tagCount]; - source.readStringArray(tags); + if (tagCount == 0) + tags = new ArrayList<>(); + else { + + Class type = (Class) source.readSerializable(); + + tags = new ArrayList(tagCount); + source.readList(tags, type.getClassLoader()); + } checkedPosition = source.readInt(); input = source.readString(); } @@ -601,9 +658,9 @@ public SavedState(Parcelable superState) { @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); - tagCount = tags.length; + tagCount = tags.size(); dest.writeInt(tagCount); - dest.writeStringArray(tags); + dest.writeTypedList(tags); dest.writeInt(checkedPosition); dest.writeString(input); } @@ -648,23 +705,35 @@ public void onClick(View v) { /** * The tag view which has two states can be either NORMAL or INPUT. */ - class TagView extends TextView { + class TagView extends TextView { public static final int STATE_NORMAL = 1; public static final int STATE_INPUT = 2; - /** The offset to the text. */ + private static final int DEFAULT_COMPOUND_PADDING = 50; + + /** + * The offset to the text. + */ private static final int CHECKED_MARKER_OFFSET = 3; - /** The stroke width of the checked marker */ + /** + * The stroke width of the checked marker + */ private static final int CHECKED_MARKER_STROKE_WIDTH = 4; - /** The current state. */ + /** + * The current state. + */ private int mState; - /** Indicates the tag if checked. */ + /** + * Indicates the tag if checked. + */ private boolean isChecked = false; - /** Indicates the tag if pressed. */ + /** + * Indicates the tag if pressed. + */ private boolean isPressed = false; private Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -673,30 +742,48 @@ class TagView extends TextView { private Paint mCheckedMarkerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - /** The rect for the tag's left corner drawing. */ + /** + * The rect for the tag's left corner drawing. + */ private RectF mLeftCornerRectF = new RectF(); - /** The rect for the tag's right corner drawing. */ + /** + * The rect for the tag's right corner drawing. + */ private RectF mRightCornerRectF = new RectF(); - /** The rect for the tag's horizontal blank fill area. */ + /** + * The rect for the tag's horizontal blank fill area. + */ private RectF mHorizontalBlankFillRectF = new RectF(); - /** The rect for the tag's vertical blank fill area. */ + /** + * The rect for the tag's vertical blank fill area. + */ private RectF mVerticalBlankFillRectF = new RectF(); - /** The rect for the checked mark draw bound. */ + /** + * The rect for the checked mark draw bound. + */ private RectF mCheckedMarkerBound = new RectF(); - /** Used to detect the touch event. */ + /** + * Used to detect the touch event. + */ private Rect mOutRect = new Rect(); - /** The path for draw the tag's outline border. */ + /** + * The path for draw the tag's outline border. + */ private Path mBorderPath = new Path(); - /** The path effect provide draw the dash border. */ + /** + * The path effect provide draw the dash border. + */ private PathEffect mPathEffect = new DashPathEffect(new float[]{10, 5}, 0); + private Integer mDeleteResources; + { mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setStrokeWidth(borderStrokeWidth); @@ -706,6 +793,23 @@ class TagView extends TextView { mCheckedMarkerPaint.setColor(checkedMarkerColor); } + public TagView(Context context, final int state, CharSequence text, Typeface customTypeface) { + this(context, state, text); + setTypeface(customTypeface); + } + + public TagView(Context context, final int state, CharSequence text, int deleteResources) { + this(context, state, text); + mDeleteResources = deleteResources; + setCompoundResources(); + } + + public TagView(Context context, final int state, CharSequence text, Typeface customTypeface, int deleteResources) { + this(context, state, text); + mDeleteResources = deleteResources; + setTypeface(customTypeface); + setCompoundResources(); + } public TagView(Context context, final int state, CharSequence text) { super(context); @@ -1021,5 +1125,15 @@ public boolean deleteSurroundingText(int beforeLength, int afterLength) { return super.deleteSurroundingText(beforeLength, afterLength); } } + + public void setDeleteButtonResId(Integer deleteResources) { + this.mDeleteResources = deleteResources; + setCompoundResources(); + } + + private void setCompoundResources() { + setCompoundDrawablesWithIntrinsicBounds(0, 0, mDeleteResources, 0); + setCompoundDrawablePadding(DEFAULT_COMPOUND_PADDING); + } } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 462ba77..d8f14a1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':demo', ':library' +include ':library'