├── .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 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | C:\Users\Administrator\AppData\Roaming\Subversion
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
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 |
5 |
6 |
7 |
8 |
9 |
10 |
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 | 
12 | 
13 |
14 |
15 | ### 联系方式
16 | 
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 |
26 |
27 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/shop_tab_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
41 |
50 |
59 |
69 |
79 |
88 |
89 |
90 |
91 |
92 |
99 |
102 |
105 |
112 |
113 |
130 |
138 |
139 |
148 |
149 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
184 |
185 |
186 |
187 |
188 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-mdpi/close.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/xiezi.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-mdpi/xiezi.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #fff4511e
7 | #666666
8 | #333333
9 | #F5F5F5
10 | #FFFFFF
11 | #FF5000
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ShopTabDialog-master-mrj
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
22 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/test/java/com/mrj/shoptagdialog/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.mrj.shoptagdialog;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | maven { url 'https://jitpack.io' }
18 | jcenter()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/images/show1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/images/show1.gif
--------------------------------------------------------------------------------
/images/show2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jj3341332/ShopTagDialog/deeb78054d999232d2240cba35402d28b581f8b2/images/show2.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------