├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mrj │ │ └── shoptagdialog │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── mrj │ │ │ └── shoptagdialog │ │ │ ├── MainActivity.java │ │ │ ├── ShopTagDiglog.java │ │ │ ├── TestFragment.java │ │ │ └── tabGround │ │ │ ├── ColorFactory.java │ │ │ ├── OneTagLabel.java │ │ │ ├── ScreenUtils.java │ │ │ ├── TagBean.java │ │ │ ├── TagContainerLayout.java │ │ │ ├── TagFactory.java │ │ │ ├── TagView.java │ │ │ └── TwoTagLabel.java │ └── res │ │ ├── anim │ │ ├── anim_interpolator.xml │ │ ├── slide_down.xml │ │ └── slide_up.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── shop_tab_dialog.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ ├── close.png │ │ ├── ic_launcher.png │ │ └── xiezi.jpg │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── mrj │ └── shoptagdialog │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── show1.gif └── show2.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | C:\Users\Administrator\AppData\Roaming\Subversion 48 | 49 | 50 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android ShopTagDialog 2 | 3 | 4 | --- 5 | 6 | ##### 高仿淘宝立即购买页面 标签选择 联动修改 7 | ##### 使用了百分比自适应布局,在任何手机上看效果都一样! 8 | ##### 使用了建造者模式 工厂模式 状态模式 适合新手学习 9 | 10 | ## 效果图有些失真 请下载Demo查看完整效果 11 | ![image](https://raw.githubusercontent.com/jj3341332/ShopTagDialog/master/images/show1.gif) 12 | ![image](https://raw.githubusercontent.com/jj3341332/ShopTagDialog/master/images/show2.gif) 13 | 14 | 15 | ### 联系方式 16 | ![image](https://raw.githubusercontent.com/jj3341332/RoundImageView/master/images/AndroidQQqun.png) 17 | 18 | # 如何使用? 19 | 下载代码后根据自己的项目作相应的修改,具体的功能点和数据结构代码已经实现 只需微调即可 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.mrj.shoptabdialog" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile 'com.android.support:appcompat-v7:25.1.0' 29 | testCompile 'junit:junit:4.12' 30 | compile 'com.zhy:percent-support-extends:1.1.1' 31 | compile 'com.github.jj3341332:RoundImageView:1.0' 32 | compile 'com.android.support:support-v4:25.+' 33 | compile 'org.greenrobot:eventbus:3.0.0' 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Administrator\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mrj/shoptagdialog/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.mrj.shoptabdialog", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog; 2 | 3 | import android.graphics.Color; 4 | import android.support.v4.content.ContextCompat; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.TextView; 10 | 11 | import com.mrj.shoptagdialog.tabGround.TagBean; 12 | import com.mrj.shoptagdialog.tabGround.TagContainerLayout; 13 | 14 | 15 | import org.greenrobot.eventbus.EventBus; 16 | import org.greenrobot.eventbus.Subscribe; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | /** 21 | * Author: mrj 22 | * github:https://github.com/jj3341332 23 | * blog:http://blog.csdn.net/jj3341332 24 | * Create Date: 2017/3/8 9:10 25 | */ 26 | 27 | public class MainActivity extends AppCompatActivity { 28 | 29 | 30 | private TextView text; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_main); 36 | // EventBus.getDefault().register(this);//订阅事件 37 | text = (TextView) findViewById(R.id.text); 38 | 39 | Button btn1= (Button)findViewById(R.id.btn1); 40 | btn1.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | List tagBeans=new ArrayList<>(); 44 | tagBeans.add(new TagBean("红色",222,1000)); 45 | tagBeans.add(new TagBean("蓝色",10,0)); 46 | tagBeans.add(new TagBean("紫色",20,555)); 47 | tagBeans.add(new TagBean("黄色",30,0)); 48 | tagBeans.add(new TagBean("青色",40,300)); 49 | tagBeans.add(new TagBean("黑色",50,0)); 50 | tagBeans.add(new TagBean("白色",60,400)); 51 | 52 | ShopTagDiglog.Builder builder= new ShopTagDiglog.Builder(MainActivity.this); 53 | builder 54 | .setBanViewColor(new TagContainerLayout.ViewColor()) 55 | .setDefaultViewColor(new TagContainerLayout.ViewColor(ContextCompat.getColor(MainActivity.this,R.color.backGroundColor),0,ContextCompat.getColor(MainActivity.this,R.color.textColor))) 56 | .setClickViewColor(new TagContainerLayout.ViewColor(ContextCompat.getColor(MainActivity.this,R.color.clickBackGroundColor),0,ContextCompat.getColor(MainActivity.this,R.color.clickTextColor))) 57 | .setTagBean(tagBeans) 58 | .create().show(); 59 | } 60 | }); 61 | 62 | 63 | Button btn2= (Button)findViewById(R.id.btn2); 64 | btn2.setOnClickListener(new View.OnClickListener() { 65 | @Override 66 | public void onClick(View v) { 67 | List tagBeans=new ArrayList<>(); 68 | tagBeans.add(new TagBean("30号",222,1000)); 69 | tagBeans.add(new TagBean("31号",10,0)); 70 | tagBeans.add(new TagBean("32号",20,555)); 71 | tagBeans.add(new TagBean("33号",30,0)); 72 | tagBeans.add(new TagBean("34号",40,300)); 73 | tagBeans.add(new TagBean("35号",50,0)); 74 | tagBeans.add(new TagBean("36号",60,400)); 75 | 76 | List tagBeans2=new ArrayList<>(); 77 | tagBeans2.add(new TagBean("30号",40,0)); 78 | tagBeans2.add(new TagBean("31号",50,0)); 79 | tagBeans2.add(new TagBean("32号",77,0)); 80 | tagBeans2.add(new TagBean("33号",99,34)); 81 | tagBeans2.add(new TagBean("34号",1000,300)); 82 | tagBeans2.add(new TagBean("35号",555,0)); 83 | tagBeans2.add(new TagBean("36号",4444,111)); 84 | 85 | List tagBeans3=new ArrayList<>(); 86 | tagBeans3.add(new TagBean("30号",7,0)); 87 | tagBeans3.add(new TagBean("31号",8,22)); 88 | tagBeans3.add(new TagBean("32号",9,44)); 89 | tagBeans3.add(new TagBean("33号",10,0)); 90 | tagBeans3.add(new TagBean("34号",11,100)); 91 | tagBeans3.add(new TagBean("35号",12,111)); 92 | tagBeans3.add(new TagBean("36号",13,0)); 93 | 94 | 95 | 96 | TagBean tagBean1=new TagBean(); 97 | tagBean1.setTitle("红色"); 98 | tagBean1.setTagBean(tagBeans); 99 | 100 | TagBean tagBean2=new TagBean(); 101 | tagBean2.setTitle("紫色"); 102 | tagBean2.setTagBean(tagBeans2); 103 | 104 | TagBean tagBean3=new TagBean(); 105 | tagBean3.setTitle("蓝色"); 106 | tagBean3.setTagBean(tagBeans3); 107 | 108 | TagBean tagBean4=new TagBean(); 109 | tagBean4.setTitle("金色"); 110 | tagBean4.setTagBean(tagBeans3); 111 | 112 | TagBean tagBean5=new TagBean(); 113 | tagBean5.setTitle("绿色"); 114 | tagBean5.setTagBean(tagBeans2); 115 | 116 | TagBean tagBean6=new TagBean(); 117 | tagBean6.setTitle("黄色"); 118 | tagBean6.setTagBean(tagBeans); 119 | 120 | 121 | 122 | List listTwo=new ArrayList<>(); 123 | listTwo.add(tagBean1); 124 | listTwo.add(tagBean2); 125 | listTwo.add(tagBean3); 126 | listTwo.add(tagBean4); 127 | listTwo.add(tagBean5); 128 | listTwo.add(tagBean6); 129 | 130 | 131 | ShopTagDiglog.Builder builder= new ShopTagDiglog.Builder(MainActivity.this); 132 | builder.setBanViewColor(new TagContainerLayout.ViewColor()) 133 | .setDefaultViewColor(new TagContainerLayout.ViewColor(ContextCompat.getColor(MainActivity.this,R.color.backGroundColor),0,ContextCompat.getColor(MainActivity.this,R.color.textColor))) 134 | .setClickViewColor(new TagContainerLayout.ViewColor(Color.parseColor("#F6A623"),Color.parseColor("#F20942"),ContextCompat.getColor(MainActivity.this,R.color.clickTextColor))) 135 | .setTagBean(listTwo) 136 | .create().show(); 137 | } 138 | }); 139 | 140 | 141 | 142 | 143 | 144 | } 145 | 146 | // @Subscribe 147 | // public void onClick(String text){ 148 | // this.text.setText(text); 149 | // } 150 | 151 | @Override 152 | protected void onDestroy() { 153 | super.onDestroy(); 154 | // EventBus.getDefault().unregister(this); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/ShopTagDiglog.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.view.Gravity; 6 | import android.view.View; 7 | import android.view.WindowManager; 8 | import android.widget.TextView; 9 | 10 | import com.mrj.shoptagdialog.tabGround.OneTagLabel; 11 | import com.mrj.shoptagdialog.tabGround.TagBean; 12 | 13 | import com.mrj.shoptagdialog.tabGround.TagContainerLayout; 14 | import com.mrj.shoptagdialog.tabGround.TagFactory; 15 | import com.mrj.shoptagdialog.tabGround.TagView; 16 | import com.mrj.shoptagdialog.tabGround.TwoTagLabel; 17 | 18 | import org.greenrobot.eventbus.EventBus; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import static com.mrj.shoptagdialog.tabGround.TagContainerLayout.*; 24 | 25 | /** 26 | * Author: mrj 27 | * github:https://github.com/jj3341332 28 | * blog:http://blog.csdn.net/jj3341332 29 | * Create Date: 2017/3/7 9:14 30 | */ 31 | 32 | public class ShopTagDiglog extends Dialog { 33 | 34 | private ViewColor mBanViewColor=new ViewColor(); 35 | private ViewColor mDefaultViewColor=new ViewColor(); 36 | private ViewColor mClickViewColor=new ViewColor(); 37 | private List mTagBean=null; 38 | 39 | private TagFactory tagFactory; 40 | private TextView priceTextView; 41 | private TextView amountTextView; 42 | private TextView chooseTextView; 43 | private TagContainerLayout colorTagContainer; 44 | private TagContainerLayout sizeTagContainer; 45 | private int colorPosition=-1; 46 | private int sizePosition=-1; 47 | private TextView sizeLabel; 48 | 49 | 50 | private ShopTagDiglog(Context context) { 51 | super(context,R.style.ShopTabDialog); 52 | } 53 | 54 | protected ShopTagDiglog(Context context, int themeResId) { 55 | super(context, themeResId); 56 | } 57 | 58 | protected ShopTagDiglog(Context context, boolean cancelable, OnCancelListener cancelListener) { 59 | super(context, cancelable, cancelListener); 60 | } 61 | 62 | private void init(){ 63 | initDialog(); 64 | if (mTagBean==null){ 65 | throw new RuntimeException("NullPointer exception!"); 66 | } 67 | 68 | if (mTagBean.get(0).getTagBean()==null) { 69 | initOneTag(); 70 | }else { 71 | sizeLabel.setVisibility(View.VISIBLE); 72 | sizeTagContainer.setVisibility(View.VISIBLE); 73 | initTwoTag(); 74 | } 75 | 76 | 77 | } 78 | 79 | private void initOneTag() { 80 | chooseTextView.setText("请选择 颜色分类"); 81 | List titles = new ArrayList(); 82 | for (TagBean tagBean :mTagBean) { 83 | titles.add(tagBean.getTitle()); 84 | } 85 | colorTagContainer.setTitles(titles); 86 | tagFactory=new OneTagLabel(mTagBean,colorTagContainer.getAllChildViews(),mBanViewColor,mDefaultViewColor,mClickViewColor); 87 | colorTagContainer.setOnTagClickListener(new TagView.OnTagClickListener(){ 88 | @Override 89 | public void onTagClick(TagView view, int position, String text) { 90 | TagFactory.ClickStatus clickStatus =tagFactory.onColorTagClick(position); 91 | if (clickStatus== TagFactory.ClickStatus.CLICK){ 92 | priceTextView.setText(mTagBean.get(position).getPrice()+""); 93 | amountTextView.setText("库存"+mTagBean.get(position).getAmount()+"件"); 94 | chooseTextView.setText("已选择 "+mTagBean.get(position).getTitle()); 95 | }else if(clickStatus== TagFactory.ClickStatus.UNCLICK) { 96 | chooseTextView.setText("请选择 颜色分类"); 97 | } 98 | // EventBus.getDefault().post(chooseTextView.getText()); 99 | } 100 | 101 | @Override 102 | public void onTagLongClick(int position, String text) { 103 | 104 | } 105 | 106 | @Override 107 | public void onTagCrossClick(int position) { 108 | 109 | } 110 | }); 111 | } 112 | 113 | private void initTwoTag() { 114 | chooseTextView.setText("请选择 颜色分类 尺码"); 115 | List colorTitles = new ArrayList(); 116 | List sizeTitles=new ArrayList(); 117 | for (TagBean colorTagBean :mTagBean) { 118 | colorTitles.add(colorTagBean.getTitle()); 119 | } 120 | for (TagBean sizeTagBean :mTagBean.get(0).getTagBean()) { 121 | sizeTitles.add(sizeTagBean.getTitle()); 122 | } 123 | 124 | colorTagContainer.setTitles(colorTitles); 125 | sizeTagContainer.setTitles(sizeTitles); 126 | tagFactory=new TwoTagLabel(mTagBean, colorTagContainer.getAllChildViews(), sizeTagContainer.getAllChildViews(),mBanViewColor,mDefaultViewColor,mClickViewColor); 127 | colorTagContainer.setOnTagClickListener(new TagView.OnTagClickListener(){ 128 | @Override 129 | public void onTagClick(TagView view, int position, String text) { 130 | TagFactory.ClickStatus clickStatus =tagFactory.onColorTagClick(position); 131 | if (clickStatus==TagFactory.ClickStatus.CLICK){ 132 | colorPosition=position; 133 | if (sizePosition==-1){ 134 | chooseTextView.setText("已选择 "+mTagBean.get(position).getTitle()+" 请选择尺码"); 135 | }else{ 136 | priceTextView.setText(mTagBean.get(position).getTagBean().get(sizePosition).getPrice()+""); 137 | amountTextView.setText("库存"+mTagBean.get(position).getTagBean().get(sizePosition).getAmount()+"件"); 138 | chooseTextView.setText("已选择 "+mTagBean.get(position).getTitle()+" "+mTagBean.get(position).getTagBean().get(sizePosition).getTitle()); 139 | } 140 | }else if(clickStatus==TagFactory.ClickStatus.UNCLICK){ 141 | colorPosition=-1; 142 | if (sizePosition==-1){ 143 | chooseTextView.setText("请选择 颜色分类 尺码"); 144 | }else{ 145 | chooseTextView.setText("已选择 "+mTagBean.get(position).getTagBean().get(sizePosition).getTitle()+ " 请选择颜色分类"); 146 | } 147 | } 148 | // EventBus.getDefault().post(chooseTextView.getText()); 149 | } 150 | 151 | @Override 152 | public void onTagLongClick(int position, String text) { 153 | 154 | } 155 | 156 | @Override 157 | public void onTagCrossClick(int position) { 158 | 159 | } 160 | }); 161 | 162 | 163 | sizeTagContainer.setOnTagClickListener(new TagView.OnTagClickListener(){ 164 | @Override 165 | public void onTagClick(TagView view, int position, String text) { 166 | TagFactory.ClickStatus clickStatus =tagFactory.onSizeTagClick(position); 167 | if (clickStatus==TagFactory.ClickStatus.CLICK){ 168 | sizePosition=position; 169 | if (colorPosition==-1){ 170 | chooseTextView.setText("已选择 "+mTagBean.get(0).getTagBean().get(position).getTitle()+" 请选择颜色分类"); 171 | 172 | }else{ 173 | priceTextView.setText(mTagBean.get(colorPosition).getTagBean().get(position).getPrice()+""); 174 | amountTextView.setText("库存"+mTagBean.get(colorPosition).getTagBean().get(position).getAmount()+"件"); 175 | chooseTextView.setText("已选择 "+mTagBean.get(colorPosition).getTitle()+" "+mTagBean.get(colorPosition).getTagBean().get(position).getTitle()); 176 | } 177 | }else if(clickStatus==TagFactory.ClickStatus.UNCLICK){ 178 | sizePosition=-1; 179 | if (colorPosition==-1){ 180 | chooseTextView.setText("请选择 颜色分类 尺码"); 181 | }else{ 182 | chooseTextView.setText("已选择 "+mTagBean.get(colorPosition).getTitle()+ " 请选择尺码"); 183 | } 184 | } 185 | // EventBus.getDefault().post(chooseTextView.getText()); 186 | } 187 | 188 | @Override 189 | public void onTagLongClick(int position, String text) { 190 | 191 | } 192 | 193 | @Override 194 | public void onTagCrossClick(int position) { 195 | 196 | } 197 | }); 198 | 199 | } 200 | 201 | 202 | private void initDialog() { 203 | setContentView(R.layout.shop_tab_dialog); 204 | //设置返回键可撤销 205 | setCancelable(true); 206 | //设置点击非Dialog区可撤销 207 | setCanceledOnTouchOutside(true); 208 | getWindow().setGravity(Gravity.BOTTOM); 209 | getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); 210 | priceTextView = (TextView) findViewById(R.id.price); 211 | amountTextView = (TextView) findViewById(R.id.amount); 212 | chooseTextView = (TextView) findViewById(R.id.choose); 213 | colorTagContainer = (TagContainerLayout) findViewById(R.id.color_tag_container); 214 | sizeTagContainer = (TagContainerLayout) findViewById(R.id.size_tag_container); 215 | sizeLabel = (TextView) findViewById(R.id.size_label); 216 | findViewById(R.id.close).setOnClickListener(new View.OnClickListener() { 217 | @Override 218 | public void onClick(View v) { 219 | dismiss(); 220 | } 221 | }); 222 | 223 | } 224 | 225 | 226 | public static class Builder{ 227 | private ShopTagDiglog shopTagDiglog; 228 | public Builder(Context context){ 229 | shopTagDiglog=new ShopTagDiglog(context); 230 | } 231 | public Builder setBanViewColor(ViewColor viewColor){ 232 | shopTagDiglog.mBanViewColor=viewColor; 233 | return this; 234 | } 235 | public Builder setDefaultViewColor(ViewColor viewColor){ 236 | shopTagDiglog.mDefaultViewColor=viewColor; 237 | return this; 238 | } 239 | public Builder setClickViewColor(ViewColor viewColor){ 240 | shopTagDiglog.mClickViewColor=viewColor; 241 | return this; 242 | } 243 | public Builder setTagBean(List tagBean){ 244 | shopTagDiglog.mTagBean=tagBean; 245 | return this; 246 | } 247 | 248 | 249 | 250 | public ShopTagDiglog create(){ 251 | shopTagDiglog.init(); 252 | return shopTagDiglog; 253 | } 254 | 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/TestFragment.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/java/com/mrj/shoptagdialog/TestFragment.java -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/tabGround/ColorFactory.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog.tabGround; 2 | 3 | import android.graphics.Color; 4 | 5 | /** 6 | * Author: mrj 7 | * github:https://github.com/jj3341332 8 | * blog:http://blog.csdn.net/jj3341332 9 | * Create Date: 2017/3/7 9:16 10 | */ 11 | public class ColorFactory { 12 | 13 | /** 14 | * ============= --border color 15 | * background color---||- Text --||--text color 16 | * ============= 17 | */ 18 | 19 | public static final String BG_COLOR_ALPHA = "33"; 20 | public static final String BD_COLOR_ALPHA = "88"; 21 | 22 | public static final String RED = "F44336"; 23 | public static final String LIGHTBLUE = "03A9F4"; 24 | public static final String AMBER = "FFC107"; 25 | public static final String ORANGE = "FF9800"; 26 | public static final String YELLOW = "FFEB3B"; 27 | public static final String LIME = "CDDC39"; 28 | public static final String BLUE = "2196F3"; 29 | public static final String INDIGO = "3F51B5"; 30 | public static final String LIGHTGREEN = "8BC34A"; 31 | public static final String GREY = "9E9E9E"; 32 | public static final String DEEPPURPLE = "673AB7"; 33 | public static final String TEAL = "009688"; 34 | public static final String CYAN = "00BCD4"; 35 | 36 | public enum PURE_COLOR{CYAN, TEAL} 37 | 38 | public static final int NONE = -1; 39 | public static final int RANDOM = 0; 40 | public static final int PURE_CYAN = 1; 41 | public static final int PURE_TEAL = 2; 42 | 43 | public static final int SHARP666666 = Color.parseColor("#FF666666"); 44 | public static final int SHARP727272 = Color.parseColor("#FF727272"); 45 | 46 | private static final String[] COLORS = new String[]{RED, LIGHTBLUE, AMBER, ORANGE, YELLOW, 47 | LIME, BLUE, INDIGO, LIGHTGREEN, GREY, DEEPPURPLE, TEAL, CYAN}; 48 | 49 | public static int[] onRandomBuild(){ 50 | int random = (int)(Math.random() * COLORS.length); 51 | int bgColor = Color.parseColor("#" + BG_COLOR_ALPHA + COLORS[random]); 52 | int bdColor = Color.parseColor("#" + BD_COLOR_ALPHA + COLORS[random]); 53 | int tColor = SHARP666666; 54 | return new int[]{bgColor, bdColor, tColor}; 55 | } 56 | 57 | public static int[] onPureBuild(PURE_COLOR type){ 58 | String color = type == PURE_COLOR.CYAN ? CYAN : TEAL; 59 | int bgColor = Color.parseColor("#" + BG_COLOR_ALPHA + color); 60 | int bdColor = Color.parseColor("#" + BD_COLOR_ALPHA + color); 61 | int tColor = SHARP727272; 62 | return new int[]{bgColor, bdColor, tColor}; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/tabGround/OneTagLabel.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog.tabGround; 2 | import android.view.SoundEffectConstants; 3 | 4 | import java.util.List; 5 | import static com.mrj.shoptagdialog.tabGround.TagContainerLayout.*; 6 | 7 | /** 8 | * Author: mrj 9 | * github:https://github.com/jj3341332 10 | * blog:http://blog.csdn.net/jj3341332 11 | * Create Date: 2017/3/8 9:36 12 | */ 13 | public class OneTagLabel extends TagFactory { 14 | private final List mTagBean; 15 | private final List mChildViews; 16 | private final ViewColor mBanViewColor; 17 | private final ViewColor mDefaultViewColor; 18 | private final ViewColor mClickViewColor; 19 | 20 | 21 | public OneTagLabel(List tagBean, List allChildViews, ViewColor banViewColor,ViewColor defaultViewColor,ViewColor clickViewColor){ 22 | 23 | this.mChildViews=allChildViews; 24 | this.mBanViewColor=banViewColor; 25 | this.mDefaultViewColor=defaultViewColor; 26 | this.mClickViewColor=clickViewColor; 27 | this.mTagBean =tagBean; 28 | initTags(); 29 | } 30 | 31 | private void initTags() { 32 | for (int i=0;i tagBean=null; 17 | 18 | public TagBean(){} 19 | public TagBean(String title ,double price,int amount){ 20 | this.title=title; 21 | this.price=price; 22 | this.amount=amount; 23 | } 24 | 25 | public String getTitle() { 26 | return title; 27 | } 28 | 29 | public void setTitle(String title) { 30 | this.title = title; 31 | } 32 | 33 | public double getPrice() { 34 | return price; 35 | } 36 | 37 | public void setPrice(double price) { 38 | this.price = price; 39 | } 40 | 41 | public int getAmount() { 42 | return amount; 43 | } 44 | 45 | public void setAmount(int amount) { 46 | this.amount = amount; 47 | } 48 | 49 | public void setTagBean(List tagBean) { 50 | this.tagBean = tagBean; 51 | } 52 | public List getTagBean(){ 53 | return tagBean; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/tabGround/TagContainerLayout.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog.tabGround; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.graphics.Typeface; 10 | import android.support.v4.widget.ViewDragHelper; 11 | import android.util.AttributeSet; 12 | import android.view.Gravity; 13 | import android.view.MotionEvent; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | 17 | import com.mrj.shoptagdialog.R; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Arrays; 21 | import java.util.List; 22 | 23 | import static com.mrj.shoptagdialog.tabGround.ScreenUtils.dp2px; 24 | import static com.mrj.shoptagdialog.tabGround.ScreenUtils.sp2px; 25 | 26 | 27 | /** 28 | * Author: mrj 29 | * github:https://github.com/jj3341332 30 | * blog:http://blog.csdn.net/jj3341332 31 | * Create Date: 2017/3/9 9:40 32 | */ 33 | 34 | public class TagContainerLayout extends ViewGroup { 35 | 36 | 37 | 38 | /** Vertical interval, default 5(dp)*/ 39 | private int mVerticalInterval; 40 | 41 | /** Horizontal interval, default 5(dp)*/ 42 | private int mHorizontalInterval; 43 | 44 | /** TagContainerLayout border width(default 0.5dp)*/ 45 | private float mBorderWidth = 0.5f; 46 | 47 | /** TagContainerLayout border radius(default 10.0dp)*/ 48 | private float mBorderRadius = 10.0f; 49 | 50 | /** The sensitive of the ViewDragHelper(default 1.0f, normal)*/ 51 | private float mSensitivity = 1.0f; 52 | 53 | /** TagView average height*/ 54 | private int mChildHeight; 55 | 56 | /** TagContainerLayout border color(default #22FF0000)*/ 57 | private int mBorderColor = Color.parseColor("#22FF0000"); 58 | 59 | /** TagContainerLayout background color(default #11FF0000)*/ 60 | private int mBackgroundColor = Color.parseColor("#11FF0000"); 61 | 62 | /** The container layout gravity(default left)*/ 63 | private int mGravity = Gravity.LEFT; 64 | 65 | /** The max line count of TagContainerLayout */ 66 | private int mMaxLines = 0; 67 | 68 | /** The max length for TagView(default max length 23)*/ 69 | private int mTagMaxLength = 23; 70 | 71 | /** TagView Border width(default 0.5dp)*/ 72 | private float mTagBorderWidth = 0.5f; 73 | 74 | /** TagView Border radius(default 15.0dp)*/ 75 | private float mTagBorderRadius = 15.0f; 76 | 77 | /** TagView Text size(default 14sp)*/ 78 | private float mTagTextSize = 14; 79 | 80 | /** Text direction(support:TEXT_DIRECTION_RTL & TEXT_DIRECTION_LTR, default TEXT_DIRECTION_LTR)*/ 81 | private int mTagTextDirection = View.TEXT_DIRECTION_LTR; 82 | 83 | /** Horizontal padding for TagView, include left & right padding(left & right padding are equal, default 10dp)*/ 84 | private int mTagHorizontalPadding = 10; 85 | 86 | /** Vertical padding for TagView, include top & bottom padding(top & bottom padding are equal, default 8dp)*/ 87 | private int mTagVerticalPadding = 8; 88 | 89 | /** TagView border color(default #88F44336)*/ 90 | private int mTagBorderColor = Color.parseColor("#88F44336"); 91 | 92 | /** TagView background color(default #33F44336)*/ 93 | private int mTagBackgroundColor = Color.parseColor("#33F44336"); 94 | 95 | /** TagView text color(default #FF666666)*/ 96 | private int mTagTextColor = Color.parseColor("#FF666666"); 97 | 98 | /** TagView typeface*/ 99 | private Typeface mTagTypeface = Typeface.DEFAULT; 100 | 101 | /** Whether TagView can clickable(default unclickable)*/ 102 | private boolean isTagViewClickable; 103 | 104 | /** Tags*/ 105 | private List mTags; 106 | 107 | 108 | /** Can drag TagView(default false)*/ 109 | private boolean mDragEnable; 110 | 111 | /** TagView drag state(default STATE_IDLE)*/ 112 | private int mTagViewState = ViewDragHelper.STATE_IDLE; 113 | 114 | /** The distance between baseline and descent(default 2.75dp)*/ 115 | private float mTagBdDistance = 2.75f; 116 | 117 | /** OnTagClickListener for TagView*/ 118 | private TagView.OnTagClickListener mOnTagClickListener; 119 | 120 | private Paint mPaint; 121 | 122 | private RectF mRectF; 123 | 124 | private ViewDragHelper mViewDragHelper; 125 | 126 | private List mChildViews; 127 | 128 | private int[] mViewPos; 129 | 130 | /** View theme(default PURE_CYAN)*/ 131 | private int mTheme = ColorFactory.PURE_CYAN; 132 | 133 | /** Default interval(dp)*/ 134 | private static final float DEFAULT_INTERVAL = 5; 135 | 136 | /** Default tag min length*/ 137 | private static final int TAG_MIN_LENGTH = 3; 138 | 139 | /** The ripple effect duration(In milliseconds, default 1000ms)*/ 140 | private int mRippleDuration = 1000; 141 | 142 | /** The ripple effect color(default #EEEEEE)*/ 143 | private int mRippleColor; 144 | 145 | /** The ripple effect color alpha(the value may between 0 - 255, default 128)*/ 146 | private int mRippleAlpha = 128; 147 | 148 | /** Enable draw cross icon(default false) */ 149 | private boolean mEnableCross = false; 150 | 151 | /** The cross area width(your cross click area, default equal to the TagView's height) */ 152 | private float mCrossAreaWidth = 0.0f; 153 | 154 | /** The padding of the cross area(default 10dp)*/ 155 | private float mCrossAreaPadding = 10.0f; 156 | 157 | /** The cross icon color(default Color.BLACK)*/ 158 | private int mCrossColor = Color.BLACK; 159 | 160 | /** The cross line width(default 1dp)*/ 161 | private float mCrossLineWidth = 1.0f; 162 | 163 | 164 | public TagContainerLayout(Context context) { 165 | this(context, null); 166 | } 167 | 168 | public TagContainerLayout(Context context, AttributeSet attrs) { 169 | this(context, attrs, 0); 170 | } 171 | 172 | public TagContainerLayout(Context context, AttributeSet attrs, int defStyleAttr){ 173 | super(context, attrs, defStyleAttr); 174 | init(context, attrs, defStyleAttr); 175 | } 176 | 177 | private void init(Context context, AttributeSet attrs, int defStyleAttr){ 178 | TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.AndroidTagView, 179 | defStyleAttr, 0); 180 | mVerticalInterval = (int)attributes.getDimension(R.styleable.AndroidTagView_vertical_interval, 181 | dp2px(context, DEFAULT_INTERVAL)); 182 | mHorizontalInterval = (int)attributes.getDimension(R.styleable.AndroidTagView_horizontal_interval, 183 | dp2px(context, DEFAULT_INTERVAL)); 184 | mBorderWidth = attributes.getDimension(R.styleable.AndroidTagView_container_border_width, 185 | dp2px(context, mBorderWidth)); 186 | mBorderRadius = attributes.getDimension(R.styleable.AndroidTagView_container_border_radius, 187 | dp2px(context, mBorderRadius)); 188 | mTagBdDistance = attributes.getDimension(R.styleable.AndroidTagView_tag_bd_distance, 189 | dp2px(context, mTagBdDistance)); 190 | mBorderColor = attributes.getColor(R.styleable.AndroidTagView_container_border_color, 191 | mBorderColor); 192 | mBackgroundColor = attributes.getColor(R.styleable.AndroidTagView_container_background_color, 193 | mBackgroundColor); 194 | mDragEnable = attributes.getBoolean(R.styleable.AndroidTagView_container_enable_drag, false); 195 | mSensitivity = attributes.getFloat(R.styleable.AndroidTagView_container_drag_sensitivity, 196 | mSensitivity); 197 | mGravity = attributes.getInt(R.styleable.AndroidTagView_container_gravity, mGravity); 198 | mMaxLines = attributes.getInt(R.styleable.AndroidTagView_container_max_lines, mMaxLines); 199 | mTagMaxLength = attributes.getInt(R.styleable.AndroidTagView_tag_max_length, mTagMaxLength); 200 | mTheme = attributes.getInt(R.styleable.AndroidTagView_tag_theme, mTheme); 201 | mTagBorderWidth = attributes.getDimension(R.styleable.AndroidTagView_tag_border_width, 202 | dp2px(context, mTagBorderWidth)); 203 | mTagBorderRadius = attributes.getDimension( 204 | R.styleable.AndroidTagView_tag_corner_radius, dp2px(context, mTagBorderRadius)); 205 | mTagHorizontalPadding = (int) attributes.getDimension( 206 | R.styleable.AndroidTagView_tag_horizontal_padding, 207 | dp2px(context, mTagHorizontalPadding)); 208 | mTagVerticalPadding = (int) attributes.getDimension( 209 | R.styleable.AndroidTagView_tag_vertical_padding, dp2px(context, mTagVerticalPadding)); 210 | mTagTextSize = attributes.getDimension(R.styleable.AndroidTagView_tag_text_size, 211 | sp2px(context, mTagTextSize)); 212 | mTagBorderColor = attributes.getColor(R.styleable.AndroidTagView_tag_border_color, 213 | mTagBorderColor); 214 | mTagBackgroundColor = attributes.getColor(R.styleable.AndroidTagView_tag_background_color, 215 | mTagBackgroundColor); 216 | mTagTextColor = attributes.getColor(R.styleable.AndroidTagView_tag_text_color, mTagTextColor); 217 | mTagTextDirection = attributes.getInt(R.styleable.AndroidTagView_tag_text_direction, mTagTextDirection); 218 | isTagViewClickable = attributes.getBoolean(R.styleable.AndroidTagView_tag_clickable, false); 219 | mRippleColor = attributes.getColor(R.styleable.AndroidTagView_tag_ripple_color, Color.parseColor("#EEEEEE")); 220 | mRippleAlpha = attributes.getInteger(R.styleable.AndroidTagView_tag_ripple_alpha, mRippleAlpha); 221 | mRippleDuration = attributes.getInteger(R.styleable.AndroidTagView_tag_ripple_duration, mRippleDuration); 222 | mEnableCross = attributes.getBoolean(R.styleable.AndroidTagView_tag_enable_cross, mEnableCross); 223 | mCrossAreaWidth = attributes.getDimension(R.styleable.AndroidTagView_tag_cross_width, 224 | dp2px(context, mCrossAreaWidth)); 225 | mCrossAreaPadding = attributes.getDimension(R.styleable.AndroidTagView_tag_cross_area_padding, 226 | dp2px(context, mCrossAreaPadding)); 227 | mCrossColor = attributes.getColor(R.styleable.AndroidTagView_tag_cross_color, mCrossColor); 228 | mCrossLineWidth = attributes.getDimension(R.styleable.AndroidTagView_tag_cross_line_width, 229 | dp2px(context, mCrossLineWidth)); 230 | attributes.recycle(); 231 | 232 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 233 | mRectF = new RectF(); 234 | mChildViews = new ArrayList(); 235 | mViewDragHelper = ViewDragHelper.create(this, mSensitivity, new DragHelperCallBack()); 236 | setWillNotDraw(false); 237 | setTagMaxLength(mTagMaxLength); 238 | setTagHorizontalPadding(mTagHorizontalPadding); 239 | setTagVerticalPadding(mTagVerticalPadding); 240 | 241 | if (isInEditMode()) { 242 | addTag("sample tag"); 243 | } 244 | } 245 | 246 | @Override 247 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 248 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 249 | 250 | measureChildren(widthMeasureSpec, heightMeasureSpec); 251 | final int childCount = getChildCount(); 252 | int lines = childCount == 0 ? 0 : getChildLines(childCount); 253 | int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 254 | // int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 255 | int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 256 | int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 257 | 258 | if (childCount == 0){ 259 | setMeasuredDimension(0, 0); 260 | }else if (heightSpecMode == MeasureSpec.AT_MOST 261 | || heightSpecMode == MeasureSpec.UNSPECIFIED) { 262 | setMeasuredDimension(widthSpecSize, (mVerticalInterval + mChildHeight) * lines 263 | - mVerticalInterval + getPaddingTop() + getPaddingBottom()); 264 | }else { 265 | setMeasuredDimension(widthSpecSize, heightSpecSize); 266 | } 267 | } 268 | 269 | @Override 270 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 271 | super.onSizeChanged(w, h, oldw, oldh); 272 | mRectF.set(0, 0, w, h); 273 | } 274 | 275 | @Override 276 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 277 | int childCount; 278 | if ((childCount = getChildCount()) <= 0){ 279 | return; 280 | } 281 | int availableW = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); 282 | int curRight = getMeasuredWidth() - getPaddingRight(); 283 | int curTop = getPaddingTop(); 284 | int curLeft = getPaddingLeft(); 285 | int sPos = 0; 286 | mViewPos = new int[childCount * 2]; 287 | 288 | for (int i = 0; i < childCount; i++) { 289 | final View childView = getChildAt(i); 290 | if (childView.getVisibility() != GONE) { 291 | int width = childView.getMeasuredWidth(); 292 | if (mGravity == Gravity.RIGHT){ 293 | if (curRight - width < getPaddingLeft()){ 294 | curRight = getMeasuredWidth() - getPaddingRight(); 295 | curTop += mChildHeight + mVerticalInterval; 296 | } 297 | mViewPos[i * 2] = curRight - width; 298 | mViewPos[i * 2 + 1] = curTop; 299 | curRight -= width + mHorizontalInterval; 300 | }else if (mGravity == Gravity.CENTER){ 301 | if (curLeft + width - getPaddingLeft() > availableW){ 302 | int leftW = getMeasuredWidth() - mViewPos[(i - 1) * 2] 303 | - getChildAt(i - 1).getMeasuredWidth() - getPaddingRight(); 304 | for (int j = sPos; j < i; j++) { 305 | mViewPos[j * 2] = mViewPos[j * 2] + leftW / 2; 306 | } 307 | sPos = i; 308 | curLeft = getPaddingLeft(); 309 | curTop += mChildHeight + mVerticalInterval; 310 | } 311 | mViewPos[i * 2] = curLeft; 312 | mViewPos[i * 2 + 1] = curTop; 313 | curLeft += width + mHorizontalInterval; 314 | 315 | if (i == childCount - 1){ 316 | int leftW = getMeasuredWidth() - mViewPos[i * 2] 317 | - childView.getMeasuredWidth() - getPaddingRight(); 318 | for (int j = sPos; j < childCount; j++) { 319 | mViewPos[j * 2] = mViewPos[j * 2] + leftW / 2; 320 | } 321 | } 322 | }else { 323 | if (curLeft + width - getPaddingLeft() > availableW){ 324 | curLeft = getPaddingLeft(); 325 | curTop += mChildHeight + mVerticalInterval; 326 | } 327 | mViewPos[i * 2] = curLeft; 328 | mViewPos[i * 2 + 1] = curTop; 329 | curLeft += width + mHorizontalInterval; 330 | } 331 | } 332 | } 333 | 334 | // layout all child views 335 | for (int i = 0; i < mViewPos.length / 2; i++) { 336 | View childView = getChildAt(i); 337 | childView.layout(mViewPos[i * 2], mViewPos[i * 2 + 1], 338 | mViewPos[i * 2] + childView.getMeasuredWidth(), 339 | mViewPos[i * 2 + 1] + mChildHeight); 340 | } 341 | } 342 | 343 | @Override 344 | protected void onDraw(Canvas canvas) { 345 | super.onDraw(canvas); 346 | 347 | mPaint.setStyle(Paint.Style.FILL); 348 | mPaint.setColor(mBackgroundColor); 349 | canvas.drawRoundRect(mRectF, mBorderRadius, mBorderRadius, mPaint); 350 | 351 | mPaint.setStyle(Paint.Style.STROKE); 352 | mPaint.setStrokeWidth(mBorderWidth); 353 | mPaint.setColor(mBorderColor); 354 | canvas.drawRoundRect(mRectF, mBorderRadius, mBorderRadius, mPaint); 355 | } 356 | 357 | @Override 358 | public boolean onInterceptTouchEvent(MotionEvent ev) { 359 | return mViewDragHelper.shouldInterceptTouchEvent(ev); 360 | } 361 | 362 | @Override 363 | public boolean onTouchEvent(MotionEvent event) { 364 | mViewDragHelper.processTouchEvent(event); 365 | return true; 366 | } 367 | 368 | @Override 369 | public void computeScroll() { 370 | super.computeScroll(); 371 | if (mViewDragHelper.continueSettling(true)){ 372 | requestLayout(); 373 | } 374 | } 375 | 376 | private int getChildLines(int childCount){ 377 | int availableW = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); 378 | int lines = 1; 379 | for (int i = 0, curLineW = 0; i < childCount; i++) { 380 | View childView = getChildAt(i); 381 | int dis = childView.getMeasuredWidth() + mHorizontalInterval; 382 | int height = childView.getMeasuredHeight(); 383 | mChildHeight = i == 0 ? height : Math.min(mChildHeight, height); 384 | curLineW += dis; 385 | if (curLineW - mHorizontalInterval > availableW){ 386 | lines++; 387 | curLineW = dis; 388 | } 389 | } 390 | 391 | return mMaxLines <= 0 ? lines : mMaxLines; 392 | } 393 | 394 | private int[] onUpdateColorFactory(){ 395 | int[] colors; 396 | if (mTheme == ColorFactory.RANDOM){ 397 | colors = ColorFactory.onRandomBuild(); 398 | }else if (mTheme == ColorFactory.PURE_TEAL){ 399 | colors = ColorFactory.onPureBuild(ColorFactory.PURE_COLOR.TEAL); 400 | }else if (mTheme == ColorFactory.PURE_CYAN){ 401 | colors = ColorFactory.onPureBuild(ColorFactory.PURE_COLOR.CYAN); 402 | }else { 403 | colors = new int[]{mTagBackgroundColor, mTagBorderColor, mTagTextColor}; 404 | } 405 | return colors; 406 | } 407 | 408 | // private void onSetTag(){ 409 | // if (mTags == null){ 410 | // throw new RuntimeException("NullPointer exception!"); 411 | // } 412 | // removeAllTags(); 413 | // if (mTags.size() == 0){ 414 | // return; 415 | // } 416 | // for (int i = 0; i < mTags.size(); i++) { 417 | // onAddTag(mTags.get(i), mChildViews.size()); 418 | // } 419 | // postInvalidate(); 420 | // } 421 | 422 | private void onSetTag(){ 423 | if (mTags == null){ 424 | throw new RuntimeException("NullPointer exception!"); 425 | } 426 | removeAllTags(); 427 | if (mTags.size() == 0){ 428 | return; 429 | } 430 | for (int i = 0; i < mTags.size(); i++) { 431 | onAddTag(mTags.get(i), mChildViews.size()); 432 | } 433 | postInvalidate(); 434 | } 435 | 436 | 437 | 438 | 439 | private void onAddTag(String text, int position) { 440 | if (position < 0 || position > mChildViews.size()){ 441 | throw new RuntimeException("Illegal position!"); 442 | } 443 | TagView tagView = new TagView(getContext(), text); 444 | initTagView(tagView); 445 | mChildViews.add(position, tagView); 446 | if (position < mChildViews.size()){ 447 | for (int i = position; i < mChildViews.size(); i++) { 448 | mChildViews.get(i).setTag(i); 449 | } 450 | }else { 451 | tagView.setTag(position); 452 | } 453 | addView(tagView, position); 454 | } 455 | 456 | 457 | private void initTagView(TagView tagView){ 458 | int[] colors = onUpdateColorFactory(); 459 | tagView.setTagBackgroundColor(colors[0]); 460 | tagView.setTagBorderColor(colors[1]); 461 | tagView.setTagTextColor(colors[2]); 462 | tagView.setTagMaxLength(mTagMaxLength); 463 | tagView.setTextDirection(mTagTextDirection); 464 | tagView.setTypeface(mTagTypeface); 465 | tagView.setBorderWidth(mTagBorderWidth); 466 | tagView.setBorderRadius(mTagBorderRadius); 467 | tagView.setTextSize(mTagTextSize); 468 | tagView.setHorizontalPadding(mTagHorizontalPadding); 469 | tagView.setVerticalPadding(mTagVerticalPadding); 470 | tagView.setIsViewClickable(isTagViewClickable); 471 | tagView.setBdDistance(mTagBdDistance); 472 | tagView.setOnTagClickListener(mOnTagClickListener); 473 | tagView.setRippleAlpha(mRippleAlpha); 474 | tagView.setRippleColor(mRippleColor); 475 | tagView.setRippleDuration(mRippleDuration); 476 | tagView.setEnableCross(mEnableCross); 477 | tagView.setCrossAreaWidth(mCrossAreaWidth); 478 | tagView.setCrossAreaPadding(mCrossAreaPadding); 479 | tagView.setCrossColor(mCrossColor); 480 | tagView.setCrossLineWidth(mCrossLineWidth); 481 | } 482 | 483 | 484 | 485 | 486 | private void invalidateTags(){ 487 | for (View view : mChildViews) { 488 | final TagView tagView = (TagView) view; 489 | tagView.setOnTagClickListener(mOnTagClickListener); 490 | } 491 | } 492 | 493 | private void onRemoveTag(int position){ 494 | if (position < 0 || position >= mChildViews.size()){ 495 | throw new RuntimeException("Illegal position!"); 496 | } 497 | mChildViews.remove(position); 498 | removeViewAt(position); 499 | for (int i = position; i < mChildViews.size(); i++) { 500 | mChildViews.get(i).setTag(i); 501 | } 502 | // TODO, make removed view null? 503 | } 504 | 505 | private int[] onGetNewPosition(View view){ 506 | int left = view.getLeft(); 507 | int top = view.getTop(); 508 | int bestMatchLeft = mViewPos[(int)view.getTag() * 2]; 509 | int bestMatchTop = mViewPos[(int)view.getTag() * 2 + 1]; 510 | int tmpTopDis = Math.abs(top - bestMatchTop); 511 | for (int i = 0; i < mViewPos.length / 2; i++) { 512 | if (Math.abs(top - mViewPos[i * 2 +1]) < tmpTopDis){ 513 | bestMatchTop = mViewPos[i * 2 +1]; 514 | tmpTopDis = Math.abs(top - mViewPos[i * 2 +1]); 515 | } 516 | } 517 | int rowChildCount = 0; 518 | int tmpLeftDis = 0; 519 | for (int i = 0; i < mViewPos.length / 2; i++) { 520 | if (mViewPos[i * 2 + 1] == bestMatchTop){ 521 | if (rowChildCount == 0){ 522 | bestMatchLeft = mViewPos[i * 2]; 523 | tmpLeftDis = Math.abs(left - bestMatchLeft); 524 | }else { 525 | if (Math.abs(left - mViewPos[i * 2]) < tmpLeftDis){ 526 | bestMatchLeft = mViewPos[i * 2]; 527 | tmpLeftDis = Math.abs(left - bestMatchLeft); 528 | } 529 | } 530 | rowChildCount++; 531 | } 532 | } 533 | return new int[]{bestMatchLeft, bestMatchTop}; 534 | } 535 | 536 | private int onGetCoordinateReferPos(int left, int top){ 537 | int pos = 0; 538 | for (int i = 0; i < mViewPos.length / 2; i++) { 539 | if (left == mViewPos[i * 2] && top == mViewPos[i * 2 + 1]){ 540 | pos = i; 541 | } 542 | } 543 | return pos; 544 | } 545 | 546 | private void onChangeView(View view, int newPos, int originPos){ 547 | mChildViews.remove(originPos); 548 | mChildViews.add(newPos, (TagView) view); 549 | for (View child : mChildViews) { 550 | child.setTag(mChildViews.indexOf(child)); 551 | } 552 | removeViewAt(originPos); 553 | addView(view, newPos); 554 | } 555 | 556 | private int ceilTagBorderWidth(){ 557 | return (int)Math.ceil(mTagBorderWidth); 558 | } 559 | 560 | 561 | 562 | 563 | 564 | private class DragHelperCallBack extends ViewDragHelper.Callback{ 565 | 566 | @Override 567 | public void onViewDragStateChanged(int state) { 568 | super.onViewDragStateChanged(state); 569 | mTagViewState = state; 570 | } 571 | 572 | @Override 573 | public boolean tryCaptureView(View child, int pointerId) { 574 | requestDisallowInterceptTouchEvent(true); 575 | return mDragEnable; 576 | } 577 | 578 | @Override 579 | public int clampViewPositionHorizontal(View child, int left, int dx) { 580 | final int leftX = getPaddingLeft(); 581 | final int rightX = getWidth() - child.getWidth() - getPaddingRight(); 582 | return Math.min(Math.max(left, leftX), rightX); 583 | } 584 | 585 | @Override 586 | public int clampViewPositionVertical(View child, int top, int dy) { 587 | final int topY = getPaddingTop(); 588 | final int bottomY = getHeight() - child.getHeight() - getPaddingBottom(); 589 | return Math.min(Math.max(top, topY), bottomY); 590 | } 591 | 592 | @Override 593 | public int getViewHorizontalDragRange(View child) { 594 | return getMeasuredWidth() - child.getMeasuredWidth(); 595 | } 596 | 597 | @Override 598 | public int getViewVerticalDragRange(View child) { 599 | return getMeasuredHeight() - child.getMeasuredHeight(); 600 | } 601 | 602 | @Override 603 | public void onViewReleased(View releasedChild, float xvel, float yvel) { 604 | super.onViewReleased(releasedChild, xvel, yvel); 605 | requestDisallowInterceptTouchEvent(false); 606 | int[] pos = onGetNewPosition(releasedChild); 607 | int posRefer = onGetCoordinateReferPos(pos[0], pos[1]); 608 | onChangeView(releasedChild, posRefer, (int) releasedChild.getTag()); 609 | mViewDragHelper.settleCapturedViewAt(pos[0], pos[1]); 610 | invalidate(); 611 | } 612 | } 613 | 614 | /** 615 | * Get current drag view state. 616 | * @return 617 | */ 618 | public int getTagViewState(){ 619 | return mTagViewState; 620 | } 621 | 622 | /** 623 | * Get TagView text baseline and descent distance. 624 | * @return 625 | */ 626 | public float getTagBdDistance() { 627 | return mTagBdDistance; 628 | } 629 | 630 | /** 631 | * Set TagView text baseline and descent distance. 632 | * @param tagBdDistance 633 | */ 634 | public void setTagBdDistance(float tagBdDistance) { 635 | this.mTagBdDistance = dp2px(getContext(), tagBdDistance); 636 | } 637 | 638 | /** 639 | * Set tags 640 | * @param tags 641 | */ 642 | public void setTags(List tags){ 643 | mTags = tags; 644 | onSetTag(); 645 | } 646 | 647 | 648 | /** 649 | * Set tags 650 | * @param tags 651 | */ 652 | public void setTitles(List tags){ 653 | mTags = tags; 654 | onSetTag(); 655 | } 656 | 657 | 658 | /** 659 | * Set tags 660 | * @param tags 661 | */ 662 | public void setTags(String... tags){ 663 | mTags = Arrays.asList(tags); 664 | onSetTag(); 665 | } 666 | 667 | 668 | 669 | /** 670 | * 671 | */ 672 | 673 | public List getAllChildViews(){ 674 | return mChildViews; 675 | } 676 | 677 | /** 678 | * Inserts the specified TagView into this ContainerLayout at the end. 679 | * @param text 680 | */ 681 | public void addTag(String text){ 682 | addTag(text, mChildViews.size()); 683 | } 684 | 685 | /** 686 | * Inserts the specified TagView into this ContainerLayout at the specified location. 687 | * The TagView is inserted before the current element at the specified location. 688 | * @param text 689 | * @param position 690 | */ 691 | public void addTag(String text, int position){ 692 | onAddTag(text, position); 693 | postInvalidate(); 694 | } 695 | 696 | /** 697 | * Remove a TagView in specified position. 698 | * @param position 699 | */ 700 | public void removeTag(int position){ 701 | onRemoveTag(position); 702 | postInvalidate(); 703 | } 704 | 705 | /** 706 | * Remove all TagViews. 707 | */ 708 | public void removeAllTags(){ 709 | mChildViews.clear(); 710 | removeAllViews(); 711 | postInvalidate(); 712 | } 713 | 714 | /** 715 | * Set OnTagClickListener for TagView. 716 | * @param listener 717 | */ 718 | public void setOnTagClickListener(TagView.OnTagClickListener listener){ 719 | mOnTagClickListener = listener; 720 | invalidateTags(); 721 | } 722 | 723 | /** 724 | * Get TagView text. 725 | * @param position 726 | * @return 727 | */ 728 | public String getTagText(int position){ 729 | return ((TagView)mChildViews.get(position)).getText(); 730 | } 731 | 732 | /** 733 | * Get a string list for all tags in TagContainerLayout. 734 | * @return 735 | */ 736 | public List getTags(){ 737 | List tmpList = new ArrayList(); 738 | for (View view : mChildViews){ 739 | if (view instanceof TagView){ 740 | tmpList.add(((TagView) view).getText()); 741 | } 742 | } 743 | return tmpList; 744 | } 745 | 746 | /** 747 | * Set whether the child view can be dragged. 748 | * @param enable 749 | */ 750 | public void setDragEnable(boolean enable){ 751 | this.mDragEnable = enable; 752 | } 753 | 754 | /** 755 | * Get current view is drag enable attribute. 756 | * @return 757 | */ 758 | public boolean getDragEnable(){ 759 | return mDragEnable; 760 | } 761 | 762 | /** 763 | * Set vertical interval 764 | * @param interval 765 | */ 766 | public void setVerticalInterval(float interval){ 767 | mVerticalInterval = (int) dp2px(getContext(), interval); 768 | postInvalidate(); 769 | } 770 | 771 | /** 772 | * Get vertical interval in this view. 773 | * @return 774 | */ 775 | public int getVerticalInterval(){ 776 | return mVerticalInterval; 777 | } 778 | 779 | /** 780 | * Set horizontal interval. 781 | * @param interval 782 | */ 783 | public void setHorizontalInterval(float interval){ 784 | mHorizontalInterval = (int)dp2px(getContext(), interval); 785 | postInvalidate(); 786 | } 787 | 788 | /** 789 | * Get horizontal interval in this view. 790 | * @return 791 | */ 792 | public int getHorizontalInterval(){ 793 | return mHorizontalInterval; 794 | } 795 | 796 | /** 797 | * Get TagContainerLayout border width. 798 | * @return 799 | */ 800 | public float getBorderWidth() { 801 | return mBorderWidth; 802 | } 803 | 804 | /** 805 | * Set TagContainerLayout border width. 806 | * @param width 807 | */ 808 | public void setBorderWidth(float width) { 809 | this.mBorderWidth = width; 810 | } 811 | 812 | /** 813 | * Get TagContainerLayout border radius. 814 | * @return 815 | */ 816 | public float getBorderRadius() { 817 | return mBorderRadius; 818 | } 819 | 820 | /** 821 | * Set TagContainerLayout border radius. 822 | * @param radius 823 | */ 824 | public void setBorderRadius(float radius) { 825 | this.mBorderRadius = radius; 826 | } 827 | 828 | /** 829 | * Get TagContainerLayout border color. 830 | * @return 831 | */ 832 | public int getBorderColor() { 833 | return mBorderColor; 834 | } 835 | 836 | /** 837 | * Set TagContainerLayout border color. 838 | * @param color 839 | */ 840 | public void setBorderColor(int color) { 841 | this.mBorderColor = color; 842 | } 843 | 844 | /** 845 | * Get TagContainerLayout background color. 846 | * @return 847 | */ 848 | public int getBackgroundColor() { 849 | return mBackgroundColor; 850 | } 851 | 852 | /** 853 | * Set TagContainerLayout background color. 854 | * @param color 855 | */ 856 | public void setBackgroundColor(int color) { 857 | this.mBackgroundColor = color; 858 | } 859 | 860 | /** 861 | * Get container layout gravity. 862 | * @return 863 | */ 864 | public int getGravity() { 865 | return mGravity; 866 | } 867 | 868 | /** 869 | * Set container layout gravity. 870 | * @param gravity 871 | */ 872 | public void setGravity(int gravity) { 873 | this.mGravity = gravity; 874 | } 875 | 876 | /** 877 | * Get TagContainerLayout ViewDragHelper sensitivity. 878 | * @return 879 | */ 880 | public float getSensitivity() { 881 | return mSensitivity; 882 | } 883 | 884 | /** 885 | * Set TagContainerLayout ViewDragHelper sensitivity. 886 | * @param sensitivity 887 | */ 888 | public void setSensitivity(float sensitivity) { 889 | this.mSensitivity = sensitivity; 890 | } 891 | 892 | /** 893 | * Set max line count for TagContainerLayout 894 | * @param maxLines max line count 895 | */ 896 | public void setMaxLines(int maxLines) { 897 | mMaxLines = maxLines; 898 | postInvalidate(); 899 | } 900 | 901 | /** 902 | * Get TagContainerLayout's max lines 903 | * @return maxLines 904 | */ 905 | public int getMaxLines(){ 906 | return mMaxLines; 907 | } 908 | 909 | /** 910 | * Set the TagView text max length(must greater or equal to 3). 911 | * @param maxLength 912 | */ 913 | public void setTagMaxLength(int maxLength){ 914 | mTagMaxLength = maxLength < TAG_MIN_LENGTH ? TAG_MIN_LENGTH : maxLength; 915 | } 916 | 917 | /** 918 | * Get TagView max length. 919 | * @return 920 | */ 921 | public int getTagMaxLength(){ 922 | return mTagMaxLength; 923 | } 924 | 925 | /** 926 | * Set TagView theme. 927 | * @param theme 928 | */ 929 | public void setTheme(int theme){ 930 | mTheme = theme; 931 | } 932 | 933 | /** 934 | * Get TagView theme. 935 | * @return 936 | */ 937 | public int getTheme(){ 938 | return mTheme; 939 | } 940 | 941 | /** 942 | * Get TagView is clickable. 943 | * @return 944 | */ 945 | public boolean getIsTagViewClickable() { 946 | return isTagViewClickable; 947 | } 948 | 949 | /** 950 | * Set TagView is clickable 951 | * @param clickable 952 | */ 953 | public void setIsTagViewClickable(boolean clickable) { 954 | this.isTagViewClickable = clickable; 955 | } 956 | 957 | /** 958 | * Get TagView border width. 959 | * @return 960 | */ 961 | public float getTagBorderWidth() { 962 | return mTagBorderWidth; 963 | } 964 | 965 | /** 966 | * Set TagView border width. 967 | * @param width 968 | */ 969 | public void setTagBorderWidth(float width) { 970 | this.mTagBorderWidth = width; 971 | } 972 | 973 | /** 974 | * Get TagView border radius. 975 | * @return 976 | */ 977 | public float getTagBorderRadius() { 978 | return mTagBorderRadius; 979 | } 980 | 981 | /** 982 | * Set TagView border radius. 983 | * @param radius 984 | */ 985 | public void setTagBorderRadius(float radius) { 986 | this.mTagBorderRadius = radius; 987 | } 988 | 989 | /** 990 | * Get TagView text size. 991 | * @return 992 | */ 993 | public float getTagTextSize() { 994 | return mTagTextSize; 995 | } 996 | 997 | /** 998 | * Set TagView text size. 999 | * @param size 1000 | */ 1001 | public void setTagTextSize(float size) { 1002 | this.mTagTextSize = size; 1003 | } 1004 | 1005 | /** 1006 | * Get TagView horizontal padding. 1007 | * @return 1008 | */ 1009 | public int getTagHorizontalPadding() { 1010 | return mTagHorizontalPadding; 1011 | } 1012 | 1013 | /** 1014 | * Set TagView horizontal padding. 1015 | * @param padding 1016 | */ 1017 | public void setTagHorizontalPadding(int padding) { 1018 | int ceilWidth = ceilTagBorderWidth(); 1019 | this.mTagHorizontalPadding = padding < ceilWidth ? ceilWidth : padding; 1020 | } 1021 | 1022 | /** 1023 | * Get TagView vertical padding. 1024 | * @return 1025 | */ 1026 | public int getTagVerticalPadding() { 1027 | return mTagVerticalPadding; 1028 | } 1029 | 1030 | /** 1031 | * Set TagView vertical padding. 1032 | * @param padding 1033 | */ 1034 | public void setTagVerticalPadding(int padding) { 1035 | int ceilWidth = ceilTagBorderWidth(); 1036 | this.mTagVerticalPadding = padding < ceilWidth ? ceilWidth : padding; 1037 | } 1038 | 1039 | /** 1040 | * Get TagView border color. 1041 | * @return 1042 | */ 1043 | public int getTagBorderColor() { 1044 | return mTagBorderColor; 1045 | } 1046 | 1047 | /** 1048 | * Set TagView border color. 1049 | * @param color 1050 | */ 1051 | public void setTagBorderColor(int color) { 1052 | this.mTagBorderColor = color; 1053 | } 1054 | 1055 | /** 1056 | * Get TagView background color. 1057 | * @return 1058 | */ 1059 | public int getTagBackgroundColor() { 1060 | return mTagBackgroundColor; 1061 | } 1062 | 1063 | /** 1064 | * Set TagView background color. 1065 | * @param color 1066 | */ 1067 | public void setTagBackgroundColor(int color) { 1068 | this.mTagBackgroundColor = color; 1069 | } 1070 | 1071 | /** 1072 | * Get TagView text color. 1073 | * @return 1074 | */ 1075 | public int getTagTextColor() { 1076 | return mTagTextColor; 1077 | } 1078 | 1079 | /** 1080 | * Set tag text direction, support:View.TEXT_DIRECTION_RTL and View.TEXT_DIRECTION_LTR, 1081 | * default View.TEXT_DIRECTION_LTR 1082 | * @param textDirection 1083 | */ 1084 | public void setTagTextDirection(int textDirection) { 1085 | this.mTagTextDirection = textDirection; 1086 | } 1087 | 1088 | /** 1089 | * Get TagView typeface. 1090 | * @return 1091 | */ 1092 | public Typeface getTagTypeface() { 1093 | return mTagTypeface; 1094 | } 1095 | 1096 | /** 1097 | * Set TagView typeface. 1098 | * @param typeface 1099 | */ 1100 | public void setTagTypeface(Typeface typeface) { 1101 | this.mTagTypeface = typeface; 1102 | } 1103 | 1104 | /** 1105 | * Get tag text direction 1106 | * @return 1107 | */ 1108 | public int getTagTextDirection() { 1109 | return mTagTextDirection; 1110 | } 1111 | 1112 | /** 1113 | * Set TagView text color. 1114 | * @param color 1115 | */ 1116 | public void setTagTextColor(int color) { 1117 | this.mTagTextColor = color; 1118 | } 1119 | 1120 | /** 1121 | * Get the ripple effect color's alpha. 1122 | * @return 1123 | */ 1124 | public int getRippleAlpha() { 1125 | return mRippleAlpha; 1126 | } 1127 | 1128 | /** 1129 | * Set TagView ripple effect alpha, the value may between 0 to 255, default is 128. 1130 | * @param mRippleAlpha 1131 | */ 1132 | public void setRippleAlpha(int mRippleAlpha) { 1133 | this.mRippleAlpha = mRippleAlpha; 1134 | } 1135 | 1136 | /** 1137 | * Get the ripple effect color. 1138 | * @return 1139 | */ 1140 | public int getRippleColor() { 1141 | return mRippleColor; 1142 | } 1143 | 1144 | /** 1145 | * Set TagView ripple effect color. 1146 | * @param mRippleColor 1147 | */ 1148 | public void setRippleColor(int mRippleColor) { 1149 | this.mRippleColor = mRippleColor; 1150 | } 1151 | 1152 | /** 1153 | * Get the ripple effect duration. 1154 | * @return 1155 | */ 1156 | public int getRippleDuration() { 1157 | return mRippleDuration; 1158 | } 1159 | 1160 | /** 1161 | * Set TagView ripple effect duration, default is 1000ms. 1162 | * @param mRippleDuration 1163 | */ 1164 | public void setRippleDuration(int mRippleDuration) { 1165 | this.mRippleDuration = mRippleDuration; 1166 | } 1167 | 1168 | /** 1169 | * Set TagView cross color. 1170 | * @return 1171 | */ 1172 | public int getCrossColor() { 1173 | return mCrossColor; 1174 | } 1175 | 1176 | /** 1177 | * Set TagView cross color, default Color.BLACK. 1178 | * @param mCrossColor 1179 | */ 1180 | public void setCrossColor(int mCrossColor) { 1181 | this.mCrossColor = mCrossColor; 1182 | } 1183 | 1184 | /** 1185 | * Get agView cross area's padding. 1186 | * @return 1187 | */ 1188 | public float getCrossAreaPadding() { 1189 | return mCrossAreaPadding; 1190 | } 1191 | 1192 | /** 1193 | * Set TagView cross area padding, default 10dp. 1194 | * @param mCrossAreaPadding 1195 | */ 1196 | public void setCrossAreaPadding(float mCrossAreaPadding) { 1197 | this.mCrossAreaPadding = mCrossAreaPadding; 1198 | } 1199 | 1200 | /** 1201 | * Get is the TagView's cross enable, default false. 1202 | * @return 1203 | */ 1204 | public boolean isEnableCross() { 1205 | return mEnableCross; 1206 | } 1207 | 1208 | /** 1209 | * Enable or disable the TagView's cross. 1210 | * @param mEnableCross 1211 | */ 1212 | public void setEnableCross(boolean mEnableCross) { 1213 | this.mEnableCross = mEnableCross; 1214 | } 1215 | 1216 | /** 1217 | * Get TagView cross area width. 1218 | * @return 1219 | */ 1220 | public float getCrossAreaWidth() { 1221 | return mCrossAreaWidth; 1222 | } 1223 | 1224 | /** 1225 | * Set TagView area width. 1226 | * @param mCrossAreaWidth 1227 | */ 1228 | public void setCrossAreaWidth(float mCrossAreaWidth) { 1229 | this.mCrossAreaWidth = mCrossAreaWidth; 1230 | } 1231 | 1232 | /** 1233 | * Get TagView cross line width. 1234 | * @return 1235 | */ 1236 | public float getCrossLineWidth() { 1237 | return mCrossLineWidth; 1238 | } 1239 | 1240 | /** 1241 | * Set TagView cross line width, default 1dp. 1242 | * @param mCrossLineWidth 1243 | */ 1244 | public void setCrossLineWidth(float mCrossLineWidth) { 1245 | this.mCrossLineWidth = mCrossLineWidth; 1246 | } 1247 | 1248 | static public class ViewColor { 1249 | /** 1250 | * backgroundColor : 11 1251 | * borderColor : 11 1252 | * textColor : 11 1253 | */ 1254 | private int backgroundColor=Color.parseColor("#F5F5F5"); 1255 | private int borderColor; 1256 | private int textColor=Color.parseColor("#999999"); 1257 | 1258 | public ViewColor(int backgroundColor, int borderColor,int textColor){ 1259 | this.backgroundColor=backgroundColor; 1260 | this.borderColor=borderColor; 1261 | this.textColor=textColor; 1262 | } 1263 | public ViewColor(){} 1264 | 1265 | 1266 | 1267 | public int getBackgroundColor() { 1268 | return backgroundColor; 1269 | } 1270 | 1271 | public void setBackgroundColor(int backgroundColor) { 1272 | this.backgroundColor = backgroundColor; 1273 | } 1274 | 1275 | public int getBorderColor() { 1276 | return borderColor; 1277 | } 1278 | 1279 | public void setBorderColor(int borderColor) { 1280 | this.borderColor = borderColor; 1281 | } 1282 | 1283 | public int getTextColor() { 1284 | return textColor; 1285 | } 1286 | 1287 | public void setTextColor(int textColor) { 1288 | this.textColor = textColor; 1289 | } 1290 | } 1291 | 1292 | } 1293 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/tabGround/TagFactory.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog.tabGround; 2 | /** 3 | * Author: mrj 4 | * github:https://github.com/jj3341332 5 | * blog:http://blog.csdn.net/jj3341332 6 | * Create Date: 2017/3/8 9:33 7 | */ 8 | public abstract class TagFactory { 9 | public enum ClickStatus{ 10 | BAN,CLICK,UNCLICK 11 | } 12 | public abstract ClickStatus onColorTagClick(int position); 13 | public abstract ClickStatus onSizeTagClick(int position); 14 | public abstract T getClickObject(); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/tabGround/TagView.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog.tabGround; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.annotation.TargetApi; 5 | import android.content.Context; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.RectF; 10 | import android.graphics.Region; 11 | import android.graphics.Typeface; 12 | import android.os.Build; 13 | import android.support.v4.widget.ViewDragHelper; 14 | import android.text.TextUtils; 15 | import android.view.MotionEvent; 16 | import android.view.View; 17 | 18 | import static com.mrj.shoptagdialog.tabGround.ScreenUtils.dp2px; 19 | 20 | 21 | /** 22 | * Author: mrj 23 | * github:https://github.com/jj3341332 24 | * blog:http://blog.csdn.net/jj3341332 25 | * Create Date: 2017/3/8 9:30 26 | */ 27 | public class TagView extends View { 28 | /** Enabled*/ 29 | private boolean mEnabled=true; 30 | 31 | /** Border width*/ 32 | private float mBorderWidth; 33 | 34 | /** Border radius*/ 35 | private float mBorderRadius; 36 | 37 | /** Text size*/ 38 | private float mTextSize; 39 | 40 | /** Horizontal padding for this view, include left & right padding(left & right padding are equal*/ 41 | private int mHorizontalPadding; 42 | 43 | /** Vertical padding for this view, include top & bottom padding(top & bottom padding are equal)*/ 44 | private int mVerticalPadding; 45 | 46 | /** TagView border color*/ 47 | private int mBorderColor; 48 | 49 | /** TagView background color*/ 50 | private int mBackgroundColor; 51 | 52 | /** TagView text color*/ 53 | private int mTextColor; 54 | 55 | /** Whether this view clickable*/ 56 | private boolean isViewClickable; 57 | 58 | /** The max length for this tag view*/ 59 | private int mTagMaxLength; 60 | 61 | /** OnTagClickListener for click action*/ 62 | private OnTagClickListener mOnTagClickListener; 63 | 64 | /** Move slop(default 5dp)*/ 65 | private int mMoveSlop = 5; 66 | 67 | /** Scroll slop threshold 4dp*/ 68 | private int mSlopThreshold = 4; 69 | 70 | /** How long trigger long click callback(default 500ms)*/ 71 | private int mLongPressTime = 500; 72 | 73 | /** Text direction(support:TEXT_DIRECTION_RTL & TEXT_DIRECTION_LTR, default TEXT_DIRECTION_LTR)*/ 74 | private int mTextDirection = View.TEXT_DIRECTION_LTR; 75 | 76 | /** The distance between baseline and descent*/ 77 | private float bdDistance; 78 | 79 | private Paint mPaint, mRipplePaint; 80 | 81 | private RectF mRectF; 82 | 83 | private String mAbstractText, mOriginText; 84 | 85 | private boolean isUp, isMoved, isExecLongClick; 86 | 87 | private int mLastX, mLastY; 88 | 89 | private float fontH, fontW; 90 | 91 | private float mTouchX, mTouchY; 92 | 93 | /** The ripple effect duration(default 1000ms)*/ 94 | private int mRippleDuration = 1000; 95 | 96 | private float mRippleRadius; 97 | 98 | private int mRippleColor; 99 | 100 | private int mRippleAlpha; 101 | 102 | private Path mPath; 103 | 104 | private Typeface mTypeface; 105 | 106 | private ValueAnimator mRippleValueAnimator; 107 | 108 | private boolean mEnableCross; 109 | 110 | private float mCrossAreaWidth; 111 | 112 | private float mCrossAreaPadding; 113 | 114 | private int mCrossColor; 115 | 116 | private float mCrossLineWidth; 117 | 118 | private boolean mIsClick=false; 119 | 120 | private Runnable mLongClickHandle = new Runnable() { 121 | @Override 122 | public void run() { 123 | if (!isMoved && !isUp){ 124 | int state = ((TagContainerLayout)getParent()).getTagViewState(); 125 | if (state == ViewDragHelper.STATE_IDLE){ 126 | isExecLongClick = true; 127 | mOnTagClickListener.onTagLongClick((int) getTag(), getText()); 128 | } 129 | } 130 | } 131 | }; 132 | 133 | 134 | 135 | public TagView(Context context, String text){ 136 | super(context); 137 | init(context, text); 138 | } 139 | 140 | public void init(Context context, String text){ 141 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 142 | mRipplePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 143 | mRipplePaint.setStyle(Paint.Style.FILL); 144 | mRectF = new RectF(); 145 | mPath = new Path(); 146 | mOriginText = text == null ? "" : text; 147 | mMoveSlop = (int) dp2px(context, mMoveSlop); 148 | mSlopThreshold = (int) dp2px(context, mSlopThreshold); 149 | } 150 | 151 | private void onDealText(){ 152 | if(!TextUtils.isEmpty(mOriginText)) { 153 | mAbstractText = mOriginText.length() <= mTagMaxLength ? mOriginText 154 | : mOriginText.substring(0, mTagMaxLength - 3) + "..."; 155 | }else { 156 | mAbstractText = ""; 157 | } 158 | mPaint.setTypeface(mTypeface); 159 | mPaint.setTextSize(mTextSize); 160 | final Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); 161 | fontH = fontMetrics.descent - fontMetrics.ascent; 162 | if (mTextDirection == View.TEXT_DIRECTION_RTL){ 163 | fontW = 0; 164 | for (char c : mAbstractText.toCharArray()) { 165 | String sc = String.valueOf(c); 166 | fontW += mPaint.measureText(sc); 167 | } 168 | }else { 169 | fontW = mPaint.measureText(mAbstractText); 170 | } 171 | } 172 | 173 | @Override 174 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 175 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 176 | int height = mVerticalPadding * 2 + (int) fontH; 177 | int width = mHorizontalPadding * 2 + (int) fontW + (isEnableCross() ? height : 0); 178 | mCrossAreaWidth = Math.min(Math.max(mCrossAreaWidth, height), width); 179 | setMeasuredDimension(width, height); 180 | } 181 | 182 | @Override 183 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 184 | super.onSizeChanged(w, h, oldw, oldh); 185 | mRectF.set(mBorderWidth, mBorderWidth, w - mBorderWidth, h - mBorderWidth); 186 | } 187 | 188 | @Override 189 | protected void onDraw(Canvas canvas) { 190 | // draw background 191 | mPaint.setStyle(Paint.Style.FILL); 192 | mPaint.setColor(mBackgroundColor); 193 | canvas.drawRoundRect(mRectF, mBorderRadius, mBorderRadius, mPaint); 194 | 195 | // draw border 196 | mPaint.setStyle(Paint.Style.STROKE); 197 | mPaint.setStrokeWidth(mBorderWidth); 198 | mPaint.setColor(mBorderColor); 199 | canvas.drawRoundRect(mRectF, mBorderRadius, mBorderRadius, mPaint); 200 | 201 | // draw ripple for TagView 202 | // drawRipple(canvas); 203 | 204 | // draw text 205 | mPaint.setStyle(Paint.Style.FILL); 206 | mPaint.setColor(mTextColor); 207 | 208 | if (mTextDirection == View.TEXT_DIRECTION_RTL){ 209 | float tmpX = (isEnableCross() ? getWidth() + getHeight() : getWidth()) / 2 + fontW / 2; 210 | for (char c : mAbstractText.toCharArray()) { 211 | String sc = String.valueOf(c); 212 | tmpX -= mPaint.measureText(sc); 213 | canvas.drawText(sc, tmpX, getHeight() / 2 + fontH / 2 - bdDistance, mPaint); 214 | } 215 | }else { 216 | canvas.drawText(mAbstractText, 217 | (isEnableCross() ? getWidth() - getHeight() : getWidth()) / 2 - fontW / 2, 218 | getHeight() / 2 + fontH / 2 - bdDistance, mPaint); 219 | } 220 | 221 | // draw cross 222 | drawCross(canvas); 223 | } 224 | 225 | @Override 226 | public boolean dispatchTouchEvent(MotionEvent event) { 227 | if (isViewClickable){ 228 | int y = (int) event.getY(); 229 | int x = (int) event.getX(); 230 | int action = event.getAction(); 231 | switch (action){ 232 | case MotionEvent.ACTION_DOWN: 233 | if (getParent() != null) { 234 | getParent().requestDisallowInterceptTouchEvent(true); 235 | } 236 | mLastY = y; 237 | mLastX = x; 238 | break; 239 | 240 | case MotionEvent.ACTION_MOVE: 241 | if (Math.abs(mLastY - y) > mSlopThreshold 242 | || Math.abs(mLastX - x) > mSlopThreshold){ 243 | if (getParent() != null) { 244 | getParent().requestDisallowInterceptTouchEvent(false); 245 | } 246 | isMoved = true; 247 | return false; 248 | } 249 | break; 250 | } 251 | } 252 | return super.dispatchTouchEvent(event); 253 | } 254 | 255 | @Override 256 | public boolean onTouchEvent(MotionEvent event) { 257 | 258 | int action = event.getAction(); 259 | 260 | if (action == MotionEvent.ACTION_DOWN) { 261 | mRippleRadius = 0.0f; 262 | mTouchX = event.getX(); 263 | mTouchY = event.getY(); 264 | splashRipple(); 265 | } 266 | if (isEnableCross() && isClickCrossArea(event) && mOnTagClickListener != null){ 267 | if (action == MotionEvent.ACTION_DOWN) { 268 | mOnTagClickListener.onTagCrossClick((int) getTag()); 269 | } 270 | return true; 271 | }else if (isViewClickable && mOnTagClickListener != null){ 272 | int x = (int) event.getX(); 273 | int y = (int) event.getY(); 274 | switch (action){ 275 | case MotionEvent.ACTION_DOWN: 276 | mLastY = y; 277 | mLastX = x; 278 | isMoved = false; 279 | isUp = false; 280 | isExecLongClick = false; 281 | postDelayed(mLongClickHandle, mLongPressTime); 282 | break; 283 | 284 | case MotionEvent.ACTION_MOVE: 285 | if (isMoved){ 286 | break; 287 | } 288 | if (Math.abs(mLastX - x) > mMoveSlop || Math.abs(mLastY - y) > mMoveSlop){ 289 | isMoved = true; 290 | } 291 | break; 292 | 293 | case MotionEvent.ACTION_UP: 294 | 295 | if (!isExecLongClick && !isMoved) { 296 | mOnTagClickListener.onTagClick(this,(int) getTag(), getText()); 297 | 298 | } 299 | isUp = true; 300 | break; 301 | } 302 | return true; 303 | } 304 | return super.onTouchEvent(event); 305 | } 306 | 307 | private boolean isClickCrossArea(MotionEvent event){ 308 | if (mTextDirection == View.TEXT_DIRECTION_RTL){ 309 | return event.getX() <= mCrossAreaWidth; 310 | } 311 | return event.getX() >= getWidth() - mCrossAreaWidth; 312 | } 313 | 314 | private void drawCross(Canvas canvas){ 315 | if (isEnableCross()){ 316 | mCrossAreaPadding = mCrossAreaPadding > getHeight() / 2 ? getHeight() / 2 : 317 | mCrossAreaPadding; 318 | int ltX, ltY, rbX, rbY, lbX, lbY, rtX, rtY; 319 | ltX = mTextDirection == View.TEXT_DIRECTION_RTL ? (int)(mCrossAreaPadding) : 320 | (int)(getWidth() - getHeight() + mCrossAreaPadding); 321 | ltY = mTextDirection == View.TEXT_DIRECTION_RTL ? (int)(mCrossAreaPadding) : 322 | (int)(mCrossAreaPadding); 323 | lbX = mTextDirection == View.TEXT_DIRECTION_RTL ? (int)(mCrossAreaPadding) : 324 | (int)(getWidth() - getHeight() + mCrossAreaPadding); 325 | lbY = mTextDirection == View.TEXT_DIRECTION_RTL ? 326 | (int)(getHeight() - mCrossAreaPadding) : (int)(getHeight() - mCrossAreaPadding); 327 | rtX = mTextDirection == View.TEXT_DIRECTION_RTL ? 328 | (int)(getHeight() - mCrossAreaPadding) : (int)(getWidth() - mCrossAreaPadding); 329 | rtY = mTextDirection == View.TEXT_DIRECTION_RTL ? (int)(mCrossAreaPadding) : 330 | (int)(mCrossAreaPadding); 331 | rbX = mTextDirection == View.TEXT_DIRECTION_RTL ? 332 | (int)(getHeight() - mCrossAreaPadding) : (int)(getWidth() - mCrossAreaPadding); 333 | rbY = mTextDirection == View.TEXT_DIRECTION_RTL ? 334 | (int)(getHeight() - mCrossAreaPadding) : (int)(getHeight() - mCrossAreaPadding); 335 | 336 | mPaint.setStyle(Paint.Style.STROKE); 337 | mPaint.setColor(mCrossColor); 338 | mPaint.setStrokeWidth(mCrossLineWidth); 339 | canvas.drawLine(ltX, ltY, rbX, rbY, mPaint); 340 | canvas.drawLine(lbX, lbY, rtX, rtY, mPaint); 341 | } 342 | } 343 | 344 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 345 | private void drawRipple(Canvas canvas){ 346 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && canvas != null){ 347 | canvas.save(); 348 | mPath.reset(); 349 | 350 | canvas.clipPath(mPath); 351 | mPath.addRoundRect(mRectF, mBorderRadius, mBorderRadius, Path.Direction.CCW); 352 | 353 | canvas.clipPath(mPath, Region.Op.REPLACE); 354 | canvas.drawCircle(mTouchX, mTouchY, mRippleRadius, mRipplePaint); 355 | canvas.restore(); 356 | } 357 | } 358 | 359 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 360 | private void splashRipple(){ 361 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && mTouchX > 0 && mTouchY > 0){ 362 | mRipplePaint.setColor(mRippleColor); 363 | mRipplePaint.setAlpha(mRippleAlpha); 364 | final float maxDis = Math.max(Math.max(Math.max(mTouchX, mTouchY), 365 | Math.abs(getMeasuredWidth() - mTouchX)), Math.abs(getMeasuredHeight() - mTouchY)); 366 | 367 | mRippleValueAnimator = ValueAnimator.ofFloat(0.0f, maxDis).setDuration(mRippleDuration); 368 | mRippleValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 369 | @Override 370 | public void onAnimationUpdate(ValueAnimator animation) { 371 | float animValue = (float) animation.getAnimatedValue(); 372 | mRippleRadius = animValue >= maxDis ? 0 : animValue; 373 | postInvalidate(); 374 | } 375 | }); 376 | mRippleValueAnimator.start(); 377 | } 378 | } 379 | 380 | public String getText(){ 381 | return mOriginText; 382 | } 383 | 384 | public boolean getIsViewClickable(){ 385 | return isViewClickable; 386 | } 387 | 388 | public void setTagMaxLength(int maxLength){ 389 | this.mTagMaxLength = maxLength; 390 | onDealText(); 391 | } 392 | 393 | public void setOnTagClickListener(OnTagClickListener listener){ 394 | this.mOnTagClickListener = listener; 395 | } 396 | 397 | public void setTagBackgroundColor(int color){ 398 | this.mBackgroundColor = color; 399 | } 400 | public int getTagBackgroundColor(){ 401 | return mBackgroundColor; 402 | } 403 | 404 | public void setTagBorderColor(int color){ 405 | this.mBorderColor = color; 406 | } 407 | 408 | public void setTagTextColor(int color){ 409 | this.mTextColor = color; 410 | } 411 | 412 | public void setBorderWidth(float width) { 413 | this.mBorderWidth = width; 414 | } 415 | 416 | public void setBorderRadius(float radius) { 417 | this.mBorderRadius = radius; 418 | } 419 | 420 | public void setTextSize(float size) { 421 | this.mTextSize = size; 422 | onDealText(); 423 | } 424 | 425 | public void setHorizontalPadding(int padding) { 426 | this.mHorizontalPadding = padding; 427 | } 428 | 429 | public void setVerticalPadding(int padding) { 430 | this.mVerticalPadding = padding; 431 | } 432 | 433 | public void setIsViewClickable(boolean clickable) { 434 | this.isViewClickable = clickable; 435 | } 436 | 437 | 438 | 439 | public interface OnTagClickListener{ 440 | void onTagClick(TagView view, int position, String text); 441 | void onTagLongClick(int position, String text); 442 | void onTagCrossClick(int position); 443 | } 444 | 445 | public int getTextDirection() { 446 | return mTextDirection; 447 | } 448 | 449 | public void setTextDirection(int textDirection) { 450 | this.mTextDirection = textDirection; 451 | } 452 | public void setText(String text){ 453 | 454 | this.mOriginText=text; 455 | onDealText(); 456 | 457 | } 458 | 459 | public void setTypeface(Typeface typeface) { 460 | this.mTypeface = typeface; 461 | onDealText(); 462 | } 463 | 464 | public void setRippleAlpha(int mRippleAlpha) { 465 | this.mRippleAlpha = mRippleAlpha; 466 | } 467 | 468 | public void setRippleColor(int mRippleColor) { 469 | this.mRippleColor = mRippleColor; 470 | } 471 | 472 | public void setRippleDuration(int mRippleDuration) { 473 | this.mRippleDuration = mRippleDuration; 474 | } 475 | 476 | public void setBdDistance(float bdDistance) { 477 | this.bdDistance = bdDistance; 478 | } 479 | 480 | public boolean isEnableCross() { 481 | return mEnableCross; 482 | } 483 | 484 | public void setEnableCross(boolean mEnableCross) { 485 | this.mEnableCross = mEnableCross; 486 | } 487 | 488 | public float getCrossAreaWidth() { 489 | return mCrossAreaWidth; 490 | } 491 | 492 | public void setCrossAreaWidth(float mCrossAreaWidth) { 493 | this.mCrossAreaWidth = mCrossAreaWidth; 494 | } 495 | 496 | public float getCrossLineWidth() { 497 | return mCrossLineWidth; 498 | } 499 | 500 | public void setCrossLineWidth(float mCrossLineWidth) { 501 | this.mCrossLineWidth = mCrossLineWidth; 502 | } 503 | 504 | public float getCrossAreaPadding() { 505 | return mCrossAreaPadding; 506 | } 507 | 508 | public void setCrossAreaPadding(float mCrossAreaPadding) { 509 | this.mCrossAreaPadding = mCrossAreaPadding; 510 | } 511 | 512 | public int getCrossColor() { 513 | return mCrossColor; 514 | } 515 | 516 | public void setCrossColor(int mCrossColor) { 517 | this.mCrossColor = mCrossColor; 518 | } 519 | 520 | public void setTagViewColor(TagContainerLayout.ViewColor viewColor){ 521 | this.setTagBackgroundColor(viewColor.getBackgroundColor()); 522 | this.setTagBorderColor(viewColor.getBorderColor()); 523 | this.setTagTextColor(viewColor.getTextColor()); 524 | postInvalidate(); 525 | } 526 | public void setEnabled(boolean enabled){ 527 | this.mEnabled=enabled; 528 | } 529 | 530 | public boolean getEnabled(){ 531 | return this.mEnabled; 532 | } 533 | public void setIsClick(boolean isClick){ 534 | this.mIsClick =isClick; 535 | } 536 | 537 | public boolean getIsClick(){ 538 | return this.mIsClick ; 539 | } 540 | 541 | } 542 | -------------------------------------------------------------------------------- /app/src/main/java/com/mrj/shoptagdialog/tabGround/TwoTagLabel.java: -------------------------------------------------------------------------------- 1 | package com.mrj.shoptagdialog.tabGround; 2 | 3 | import android.view.SoundEffectConstants; 4 | 5 | import java.util.List; 6 | 7 | import static com.mrj.shoptagdialog.tabGround.TagContainerLayout.*; 8 | 9 | 10 | /** 11 | * Author: mrj 12 | * github:https://github.com/jj3341332 13 | * blog:http://blog.csdn.net/jj3341332 14 | * Create Date: 2017/3/8 11:16 15 | */ 16 | public class TwoTagLabel extends TagFactory { 17 | private List mTwoTagBean; 18 | private List mColorAllChildViews; 19 | private List mSizeAllChildViews; 20 | private ViewColor mBanViewColor; 21 | private ViewColor mDefaultViewColor; 22 | private ViewColor mClickViewColor; 23 | private TwoTagLabel(){} 24 | 25 | public TwoTagLabel(List twoTagBean,List colorAllChildViews, List sizeAllChildViews, ViewColor banViewColor, ViewColor defaultViewColor, ViewColor clickViewColor) { 26 | this.mTwoTagBean=twoTagBean; 27 | this.mColorAllChildViews=colorAllChildViews; 28 | this.mSizeAllChildViews=sizeAllChildViews; 29 | this.mBanViewColor=banViewColor; 30 | this.mDefaultViewColor=defaultViewColor; 31 | this.mClickViewColor=clickViewColor; 32 | initTags(); 33 | 34 | } 35 | 36 | private void initTags() { 37 | for (int i=0;i 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_down.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 28 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_up.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 32 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 19 | 20 |