Repository: Kaka252/FlexboxUtils
Branch: master
Commit: e3fb54ae490f
Files: 41
Total size: 43.1 KB
Directory structure:
gitextract_7e674wrr/
├── .gitignore
├── .idea/
│ ├── copyright/
│ │ └── profiles_settings.xml
│ ├── gradle.xml
│ └── runConfigurations.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── zhouyou/
│ │ └── flexbox/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── zhouyou/
│ │ │ └── flexbox/
│ │ │ ├── MainActivity.java
│ │ │ ├── StringTagAdapter.java
│ │ │ └── StringTagView.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ ├── bg_flow_divider.xml
│ │ │ ├── bg_flow_selected.xml
│ │ │ └── bg_flow_unselect.xml
│ │ ├── layout/
│ │ │ └── activity_main.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── com/
│ └── zhouyou/
│ └── flexbox/
│ └── ExampleUnitTest.java
├── build.gradle
├── flexbox/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── zhouyou/
│ │ └── flexbox/
│ │ └── ExampleInstrumentedTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── zhouyou/
│ │ │ └── flexbox/
│ │ │ ├── adapter/
│ │ │ │ └── TagAdapter.java
│ │ │ ├── interfaces/
│ │ │ │ ├── OnFlexboxSubscribeListener.java
│ │ │ │ └── TagWithListener.java
│ │ │ └── widget/
│ │ │ ├── BaseTagView.java
│ │ │ └── TagFlowLayout.java
│ │ └── res/
│ │ └── values/
│ │ ├── attrs.xml
│ │ └── strings.xml
│ └── test/
│ └── java/
│ └── zhouyou/
│ └── flexbox/
│ └── ExampleUnitTest.java
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.idea/misc.xml
.idea/encodings.xml
.idea/modules.xml
.idea/compiler.xml
.idea/vcs.xml
.idea/markdown-navigator
.idea/markdown-navigator.xml
.DS_Store
/build
/captures
.externalNativeBuild
app/libs/
flexbox/libs/
flexbox/src/main/res/drawable/
================================================
FILE: .idea/copyright/profiles_settings.xml
================================================
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/runConfigurations.xml
================================================
================================================
FILE: README.md
================================================
# FlexboxUtils
Google在之前发布了一个叫做FlexboxLayout的控件,完全能够适配平时我们业务中自定义的布局流控件,而且有过之而无不及。因此在这个基础上我又针对这个控件进行了进一步的封装,基本能够满足平时大部分的业务需求,先上图

# 继承BaseTagView
定义一个TagView,继承BaseTagView,由于每一个tag的数据类型不确定,因此需要传入一个固定的数据类型满足实际需求
```
public class StringTagView extends BaseTagView {
public StringTagView(Context context) {
this(context, null);
}
public StringTagView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs, 0);
}
public StringTagView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setItem(String item) {
super.setItem(item);
textView.setText(item);
}
}
```
# 继承TagAdapter
定义一个Adapter,继承TagAdapter,并实现相应的方法
```
public class StringTagAdapter extends TagAdapter {
StringTagAdapter(Context context, List data) {
this(context, data, null);
}
StringTagAdapter(Context context, List data, List selectItems) {
super(context, data, selectItems);
}
/**
* 检查item和所选item是否一样
*
* @param view
* @param item
* @return
*/
@Override
protected boolean checkIsItemSame(StringTagView view, String item) {
return TextUtils.equals(view.getItem(), item);
}
/**
* 检查item是否是空指针
*
* @return
*/
@Override
protected boolean checkIsItemNull(String item) {
return TextUtils.isEmpty(item);
}
/**
* 添加标签
*
* @param item
* @return
*/
@Override
protected StringTagView addTag(String item) {
StringTagView tagView = new StringTagView(getContext());
tagView.setPadding(20, 20, 20, 20);
TextView textView = tagView.getTextView();
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setGravity(Gravity.CENTER);
tagView.setItemDefaultDrawable(itemDefaultDrawable);
tagView.setItemSelectDrawable(itemSelectDrawable);
tagView.setItemDefaultTextColor(itemDefaultTextColor);
tagView.setItemSelectTextColor(itemSelectTextColor);
tagView.setItem(item);
return tagView;
}
}
```
# 使用
在xml中,你可以使用如下配置:
```
// 是否选中高亮
// 默认标签背景
// 选中标签背景
// 默认标签文字颜色
// 选中标签文字颜色
// 单选或者多选
// 默认多选
// 单选
```
```
```
也可以使用Java代码进行属性配置
```
TagFlowLayout flowLayout = (TagFlowLayout) findViewById(R.id.flow_layout);
flowLayout.setShowHighlight(false);
flowLayout.setItemDefaultDrawable(R.drawable.bg_flow_unselect);
flowLayout.setItemSelectDrawable(R.drawable.bg_flow_selected);
flowLayout.setItemDefaultTextColor(ContextCompat.getColor(this, R.color.app_green));
flowLayout.setItemSelectTextColor(Color.WHITE);
flowLayout.setMode(TagFlowLayout.MODE_SINGLE_SELECT);
```
# 回调
可以使用如下回调来获取最终所选择的项目列表
```
...
adapter.setOnSubscribeListener(new OnFlexboxSubscribeListener() {
@Override
public void onSubscribe(List selectedItem) {
}
});
```
# 操作模式
可以通过设置模式来控制标签的单选与多选操作
```
...
flowLayout.setMode(TagFlowLayout.MODE_SINGLE_SELECT);
```
# 选中高亮效果
可以设置是否选中高亮,默认为选中高亮
```
...
flowLayout.setShowHighlight(false);
```
# 绑定数据到控件
通过声明TagFlowLayout,并且调用setAdapter()方法来接收之前定义好的adapter即可
```
...
flowLayout.setAdapter(adapter);
```
# 切换、刷新数据
在声明的adapter基础上,重新设置数据源和已选项,notifyDataSetChanged()方法即可完成数据刷新操作
```
...
adapter.setSource(data);
adapter.setSelectItems(selectItems);
adapter.notifyDataSetChanged();
```
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.zhouyou.flexbox"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
testCompile 'junit:junit:4.12'
compile project(path: ':flexbox')
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\DESKTOP\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app/src/androidTest/java/com/zhouyou/flexbox/ExampleInstrumentedTest.java
================================================
package com.zhouyou.flexbox;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see Testing documentation
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.zhouyou.flexbox", appContext.getPackageName());
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/java/com/zhouyou/flexbox/MainActivity.java
================================================
package com.zhouyou.flexbox;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import java.util.ArrayList;
import java.util.List;
import zhouyou.flexbox.interfaces.OnFlexboxSubscribeListener;
import zhouyou.flexbox.widget.TagFlowLayout;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnCount;
private StringTagAdapter adapter;
private List sourceData;
private List selectItems;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initViews();
}
private void initData() {
sourceData = new ArrayList<>();
sourceData.add("程序员");
sourceData.add("设计师");
sourceData.add("产品经理");
sourceData.add("运营");
sourceData.add("商务");
sourceData.add("人事经理");
sourceData.add("项目经理");
sourceData.add("客户代表");
sourceData.add("技术主管");
sourceData.add("测试工程师");
sourceData.add("前端工程师");
sourceData.add("Java工程师");
sourceData.add("Android工程师");
sourceData.add("iOS工程师");
selectItems = new ArrayList<>();
selectItems.add("客户代表");
selectItems.add("Java工程师");
}
private void initViews() {
TagFlowLayout flowLayout = (TagFlowLayout) findViewById(R.id.flow_layout);
btnCount = (Button) findViewById(R.id.btn_get_count);
adapter = new StringTagAdapter(this, sourceData, selectItems);
adapter.setOnSubscribeListener(new OnFlexboxSubscribeListener() {
@Override
public void onSubscribe(List selectedItem) {
btnCount.setText("已选择" + selectedItem.size() + "个");
}
});
flowLayout.setAdapter(adapter);
btnCount.setText("已选择" + adapter.getSelectedList().size() + "个");
findViewById(R.id.btn_switch_data).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_switch_data:
List data = new ArrayList<>();
data.add("客户代表");
data.add("Java工程师");
List selectList = new ArrayList<>();
selectList.add("客户代表");
adapter.setSource(data);
adapter.setSelectItems(selectList);
adapter.notifyDataSetChanged();
break;
default:
break;
}
}
}
================================================
FILE: app/src/main/java/com/zhouyou/flexbox/StringTagAdapter.java
================================================
package com.zhouyou.flexbox;
import android.content.Context;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.widget.TextView;
import java.util.List;
import zhouyou.flexbox.adapter.TagAdapter;
/**
* 作者:ZhouYou
* 日期:2017/3/27
*/
public class StringTagAdapter extends TagAdapter {
StringTagAdapter(Context context, List data) {
this(context, data, null);
}
StringTagAdapter(Context context, List data, List selectItems) {
super(context, data, selectItems);
}
/**
* 检查item和所选item是否一样
*
* @param view
* @param item
* @return
*/
@Override
protected boolean checkIsItemSame(StringTagView view, String item) {
return TextUtils.equals(view.getItem(), item);
}
/**
* 检查item是否是空指针
*
* @return
*/
@Override
protected boolean checkIsItemNull(String item) {
return TextUtils.isEmpty(item);
}
/**
* 添加标签
*
* @param item
* @return
*/
@Override
protected StringTagView addTag(String item) {
StringTagView tagView = new StringTagView(getContext());
tagView.setPadding(20, 20, 20, 20);
TextView textView = tagView.getTextView();
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
textView.setGravity(Gravity.CENTER);
tagView.setItemDefaultDrawable(itemDefaultDrawable);
tagView.setItemSelectDrawable(itemSelectDrawable);
tagView.setItemDefaultTextColor(itemDefaultTextColor);
tagView.setItemSelectTextColor(itemSelectTextColor);
tagView.setItem(item);
return tagView;
}
}
================================================
FILE: app/src/main/java/com/zhouyou/flexbox/StringTagView.java
================================================
package com.zhouyou.flexbox;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import zhouyou.flexbox.widget.BaseTagView;
/**
* 作者:ZhouYou
* 日期:2017/3/25.
*/
public class StringTagView extends BaseTagView {
public StringTagView(Context context) {
this(context, null);
}
public StringTagView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs, 0);
}
public StringTagView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setItem(String item) {
super.setItem(item);
textView.setText(item);
}
}
================================================
FILE: app/src/main/res/drawable/bg_flow_divider.xml
================================================
================================================
FILE: app/src/main/res/drawable/bg_flow_selected.xml
================================================
================================================
FILE: app/src/main/res/drawable/bg_flow_unselect.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: app/src/main/res/values/colors.xml
================================================
#3F51B5
#303F9F
#FF4081
#53CAC3
================================================
FILE: app/src/main/res/values/strings.xml
================================================
FlexboxDemo
================================================
FILE: app/src/main/res/values/styles.xml
================================================
================================================
FILE: app/src/test/java/com/zhouyou/flexbox/ExampleUnitTest.java
================================================
package com.zhouyou.flexbox;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see Testing documentation
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: flexbox/.gitignore
================================================
/build
================================================
FILE: flexbox/build.gradle
================================================
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
compile 'com.google.android:flexbox:0.2.6'
}
================================================
FILE: flexbox/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\DESKTOP\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: flexbox/src/androidTest/java/zhouyou/flexbox/ExampleInstrumentedTest.java
================================================
package zhouyou.flexbox;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see Testing documentation
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("zhouyou.flexbox.test", appContext.getPackageName());
}
}
================================================
FILE: flexbox/src/main/AndroidManifest.xml
================================================
================================================
FILE: flexbox/src/main/java/zhouyou/flexbox/adapter/TagAdapter.java
================================================
package zhouyou.flexbox.adapter;
import android.content.Context;
import android.support.v4.util.ArrayMap;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import zhouyou.flexbox.widget.BaseTagView;
import zhouyou.flexbox.interfaces.OnFlexboxSubscribeListener;
import zhouyou.flexbox.widget.TagFlowLayout;
import zhouyou.flexbox.interfaces.TagWithListener;
/**
* 作者:ZhouYou
* 日期:2017/3/27.
*/
public abstract class TagAdapter, T> {
private Context context;
/**
* 根布局
*/
private TagFlowLayout rootView;
/**
* 数据源
*/
private List source;
/**
* 已选项目
*/
private List selectItems;
/*view和tag的对应关系*/
private Map viewMap;
/*标签选择操作的订阅接口*/
private OnFlexboxSubscribeListener onSubscribeListener;
/*是否展示选中效果*/
private boolean isShowHighlight = true;
/*可选标签的最大数量*/
private int maxSelection;
/*默认和已选的背景*/
protected int itemDefaultDrawable;
protected int itemSelectDrawable;
/*默认和已选的文字颜色*/
protected int itemDefaultTextColor;
protected int itemSelectTextColor;
/*操作模式 0 - 多选 | 1 - 单选*/
private int mode;
public void setOnSubscribeListener(OnFlexboxSubscribeListener onSubscribeListener) {
this.onSubscribeListener = onSubscribeListener;
}
public void setSource(List source) {
this.source = source;
}
public void setSelectItems(List selectItems) {
this.selectItems = selectItems;
}
public List getSelectItems() {
return selectItems;
}
public TagAdapter(Context context, List source) {
this.context = context;
this.source = source;
viewMap = new ArrayMap<>();
}
public TagAdapter(Context context, List source, List selectItems) {
this.context = context;
this.source = source;
this.selectItems = selectItems;
viewMap = new ArrayMap<>();
}
public Context getContext() {
return context;
}
public List getData() {
return source;
}
/**
* 绑定控件
*
* @param rootView
*/
public void bindView(TagFlowLayout rootView) {
if (rootView == null) {
throw new NullPointerException("未初始化TagFlowLayout");
}
this.rootView = rootView;
isShowHighlight = rootView.isShowHighlight();
itemDefaultDrawable = rootView.getItemDefaultDrawable();
itemSelectDrawable = rootView.getItemSelectDrawable();
itemDefaultTextColor = rootView.getItemDefaultTextColor();
itemSelectTextColor = rootView.getItemSelectTextColor();
maxSelection = rootView.getMaxSelection();
mode = rootView.getMode();
}
/**
* 设置标签组
*/
public void addTags() {
if (source == null || source.size() <= 0) return;
rootView.removeAllViews();
for (T item : source) {
if (item == null) continue;
final BaseTagView view = addTag(item);
initSelectedViews((V) view);
// 单个item的点击监控
view.setListener(new TagWithListener() {
@Override
public void onItemSelect(T item) {
if (mode == TagFlowLayout.MODE_SINGLE_SELECT) {
if (isShowHighlight) view.selectItemChangeColorState();
singleSelectMode(item);
} else {
List selectList = getSelectedList();
if ((maxSelection <= selectList.size() && maxSelection > 0) && !view.isItemSelected()) {
Toast.makeText(getContext(), "最多选择" + maxSelection + "个标签", Toast.LENGTH_SHORT).show();
return;
}
if (isShowHighlight) view.selectItemChangeColorState();
}
if (onSubscribeListener != null) {
onSubscribeListener.onSubscribe(getSelectedList());
}
}
});
viewMap.put((V) view, item);
rootView.addView(view);
}
}
/**
* 设置在初始化时所选中的View
*
* @param view
*/
private void initSelectedViews(V view) {
if (!isShowHighlight) return;
if (selectItems == null || selectItems.size() <= 0) return;
for (T select : selectItems) {
if (checkIsItemNull(select)) continue;
if (checkIsItemSame(view, select)) {
view.setItemSelected(true);
break;
}
}
}
/**
* 单选操作模式
*/
private void singleSelectMode(T item) {
if (!isShowHighlight) return;
for (BaseTagView view : viewMap.keySet()) {
if (checkIsItemSame((V) view, item)) {
view.setItemSelected(true);
} else {
view.setItemSelected(false);
}
}
}
/**
* 刷新数据
*/
public void notifyDataSetChanged() {
addTags();
}
/**
* 对于相同item的判断条件
*
* @param view
* @param item
* @return
*/
protected abstract boolean checkIsItemSame(V view, T item);
/**
* 检查item是否是空指针
*
* @param item
* @return
*/
protected abstract boolean checkIsItemNull(T item);
/**
* 添加单个标签
*
* @param item
* @return
*/
protected abstract BaseTagView addTag(T item);
/**
* 获取所有item的数量
*/
protected int getCount() {
if (source == null) return 0;
return source.size();
}
/**
* 得到已选项目的列表
*
* @return
*/
@SuppressWarnings("SuspiciousMethodCalls")
public List getSelectedList() {
List selectedList = new ArrayList<>();
for (BaseTagView view : viewMap.keySet()) {
if (view.isItemSelected()) {
T item = viewMap.get(view);
selectedList.add(item);
}
}
return selectedList;
}
}
================================================
FILE: flexbox/src/main/java/zhouyou/flexbox/interfaces/OnFlexboxSubscribeListener.java
================================================
package zhouyou.flexbox.interfaces;
import java.util.List;
/**
* 作者:ZhouYou
* 日期:2017/3/27.
*/
public interface OnFlexboxSubscribeListener {
/**
* @param selectedItem 已选中的标签
*/
void onSubscribe(List selectedItem);
}
================================================
FILE: flexbox/src/main/java/zhouyou/flexbox/interfaces/TagWithListener.java
================================================
package zhouyou.flexbox.interfaces;
/**
* 作者:ZhouYou
* 日期:2017/3/25.
*/
public interface TagWithListener {
void onItemSelect(T item);
}
================================================
FILE: flexbox/src/main/java/zhouyou/flexbox/widget/BaseTagView.java
================================================
package zhouyou.flexbox.widget;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import zhouyou.flexbox.interfaces.TagWithListener;
/**
* 作者:ZhouYou
* 日期:2017/3/25.
*/
public class BaseTagView extends FrameLayout implements View.OnClickListener {
private int itemDefaultDrawable;
private int itemSelectDrawable;
private int itemDefaultTextColor;
private int itemSelectTextColor;
private T item;
public TextView textView;
private TagWithListener listener;
private boolean isItemSelected;
public void setListener(TagWithListener listener) {
this.listener = listener;
}
public BaseTagView(Context context) {
this(context, null);
}
public BaseTagView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseTagView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
textView = new TextView(getContext());
textView.setGravity(Gravity.CENTER);
addView(textView);
setOnClickListener(this);
}
/**
* 设置标签
*
* @param item
*/
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
@Override
public void onClick(View v) {
if (listener == null) return;
listener.onItemSelect(item);
}
public void selectItemChangeColorState() {
if (isItemSelected) {
setBackgroundResource(itemDefaultDrawable);
textView.setTextColor(itemDefaultTextColor);
isItemSelected = false;
} else {
setBackgroundResource(itemSelectDrawable);
textView.setTextColor(itemSelectTextColor);
isItemSelected = true;
}
}
public boolean isItemSelected() {
return isItemSelected;
}
public void setItemSelected(boolean itemSelected) {
isItemSelected = itemSelected;
if (itemSelected) {
setBackgroundResource(itemSelectDrawable);
textView.setTextColor(itemSelectTextColor);
} else {
setBackgroundResource(itemDefaultDrawable);
textView.setTextColor(itemDefaultTextColor);
}
}
public void setItemDefaultDrawable(int itemDefaultDrawable) {
this.itemDefaultDrawable = itemDefaultDrawable;
setBackgroundResource(itemDefaultDrawable);
}
public void setItemSelectDrawable(int itemSelectDrawable) {
this.itemSelectDrawable = itemSelectDrawable;
}
public void setItemDefaultTextColor(int itemDefaultTextColor) {
this.itemDefaultTextColor = itemDefaultTextColor;
textView.setTextColor(itemDefaultTextColor);
}
public void setItemSelectTextColor(int itemSelectTextColor) {
this.itemSelectTextColor = itemSelectTextColor;
}
public TextView getTextView() {
return textView;
}
}
================================================
FILE: flexbox/src/main/java/zhouyou/flexbox/widget/TagFlowLayout.java
================================================
package zhouyou.flexbox.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import com.google.android.flexbox.FlexboxLayout;
import zhouyou.flexbox.R;
import zhouyou.flexbox.adapter.TagAdapter;
/**
* 作者:ZhouYou
* 日期:2017/3/28.
*/
public class TagFlowLayout extends FlexboxLayout {
/*是否展示选中效果*/
private boolean isShowHighlight = true;
/*默认和已选的背景*/
private int itemDefaultDrawable;
private int itemSelectDrawable;
/*默认和已选的文字颜色*/
private int itemDefaultTextColor;
private int itemSelectTextColor;
/*操作模式 0 - 多选 | 1 - 单选*/
private int mode = MODE_MULTI_SELECT;
/*可选标签的最大数量*/
private int maxSelection;
public static final int MODE_MULTI_SELECT = 0;
public static final int MODE_SINGLE_SELECT = 1;
public TagFlowLayout(Context context) {
this(context, null);
}
public TagFlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);
isShowHighlight = ta.getBoolean(R.styleable.TagFlowLayout_showHighlight, true);
itemDefaultDrawable = ta.getResourceId(R.styleable.TagFlowLayout_defaultDrawable, 0);
itemSelectDrawable = ta.getResourceId(R.styleable.TagFlowLayout_selectDrawable, 0);
itemDefaultTextColor = ta.getColor(R.styleable.TagFlowLayout_defaultTextColor, 0);
itemSelectTextColor = ta.getColor(R.styleable.TagFlowLayout_selectTextColor, 0);
mode = ta.getInt(R.styleable.TagFlowLayout_mode, MODE_MULTI_SELECT);
maxSelection = ta.getInt(R.styleable.TagFlowLayout_maxSelectionCount, 0);
ta.recycle();
}
public void setAdapter(TagAdapter adapter) {
if (adapter == null) {
removeAllViews();
return;
}
adapter.bindView(this);
adapter.addTags();
}
public boolean isShowHighlight() {
return isShowHighlight;
}
public void setShowHighlight(boolean showHighlight) {
isShowHighlight = showHighlight;
}
public int getItemDefaultDrawable() {
return itemDefaultDrawable;
}
public void setItemDefaultDrawable(int itemDefaultDrawable) {
this.itemDefaultDrawable = itemDefaultDrawable;
}
public int getItemSelectDrawable() {
return itemSelectDrawable;
}
public void setItemSelectDrawable(int itemSelectDrawable) {
this.itemSelectDrawable = itemSelectDrawable;
}
public int getItemDefaultTextColor() {
return itemDefaultTextColor;
}
public void setItemDefaultTextColor(int itemDefaultTextColor) {
this.itemDefaultTextColor = itemDefaultTextColor;
}
public int getItemSelectTextColor() {
return itemSelectTextColor;
}
public void setItemSelectTextColor(int itemSelectTextColor) {
this.itemSelectTextColor = itemSelectTextColor;
}
public int getMode() {
return mode;
}
public void setMode(int mode) {
this.mode = mode;
}
public int getMaxSelection() {
return maxSelection;
}
public void setMaxSelection(int maxSelection) {
this.maxSelection = maxSelection;
}
}
================================================
FILE: flexbox/src/main/res/values/attrs.xml
================================================
================================================
FILE: flexbox/src/main/res/values/strings.xml
================================================
FlexboxUtils
================================================
FILE: flexbox/src/test/java/zhouyou/flexbox/ExampleUnitTest.java
================================================
package zhouyou.flexbox;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see Testing documentation
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Sat Mar 25 17:41:19 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: settings.gradle
================================================
include ':app', ':flexbox'