activity_sou_suo.xml布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:id="@+id/ss" android:orientation="horizontal" android:layout_height="80dp" android:layout_width="match_parent" android:background="#b53232"> <Button android:id="@+id/ssfinish" android:layout_height="30dp" android:layout_width="30dp" android:background="@mipmap/leftjian" android:layout_marginTop="15dp" android:layout_marginLeft="10dp" android:layout_marginBottom="15dp"/> <EditText android:id="@+id/edt" android:layout_height="wrap_content" android:layout_width="0dp" android:background="@drawable/shape002" android:layout_marginTop="5dp" android:layout_marginLeft="10dp" android:layout_marginBottom="5dp" android:textSize="15dp" android:textColor="#000" android:hint="请输入搜索内容" android:layout_weight="1" android:layout_marginRight="10dp" android:layout_gravity="center"/> <Button android:id="@+id/btn" android:layout_height="40dp" android:layout_width="60dp" android:background="#fff" android:layout_marginTop="15dp" android:layout_marginBottom="10dp" android:textSize="20dp" android:layout_marginRight="20dp" android:text="搜索"/> </LinearLayout> <TextView android:layout_marginTop="15dp" android:layout_marginLeft="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="热门搜索" /> <LinearLayout android:layout_marginTop="20dp" android:layout_marginLeft="15dp" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:text="RxIava" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="RxAndroid" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="数据库" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="自定义控件" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_marginLeft="15dp" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:text="下拉刷新上拉加载" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="mvp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="直播" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="权限管理" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_marginLeft="15dp" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:text="Retrofit框架" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="OkHttp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="WebView" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="热修复" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="历史记录" android:textSize="17dp" android:layout_marginTop="15dp" android:layout_marginLeft="10dp" /> <ImageView android:id="@+id/shanchu" android:src="@mipmap/rublish" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginTop="15dp" android:layout_marginLeft="330dp" /> </LinearLayout> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <com.bwei.lgank.myview.TagFlowLayout android:layout_marginTop="30dp" android:id="@+id/id_flowlayout" android:layout_width="fill_parent" android:layout_height="wrap_content" app:max_select="-1" /> </ScrollView> </LinearLayout> tv.xml<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_marginTop="10dp" android:background="@drawable/tag_bg" android:text="Helloworld" android:textColor="#999999" android:textSize="14dp"> </TextView> drawable下的文件夹 border002.xml<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <stroke android:color="#000" android:width="0.05dp"/> <padding/> </shape>
checked_bg.xml<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#ffffff" /> <corners android:radius="2dp" /> <stroke android:width="1dp" android:color="#dddddd" /> <padding android:bottom="5dp" android:left="14dp" android:right="14dp" android:top="5dp" /> </shape>
normal_bg.xml<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#ffffff" /> <corners android:radius="2dp" /> <stroke android:width="1dp" android:color="#dddddd" /> <padding android:bottom="5dp" android:left="14dp" android:right="14dp" android:top="5dp" /> </shape>
shape001.xml<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#ffffff"/> <!--设置按钮四个角为弧形--> <!--android:radius弧形的半径--> <corners android:radius="10dip"/> <!--padding;button里面的文字与button边界的间隔--> <padding android:top="10dp" android:right="10dp" android:left="10dp" android:bottom="10dp"/> </shape>
shape002.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#ffffff"/> <!--设置按钮四个角为弧形--> <!--android:radius弧形的半径--> <corners android:radius="50dip"/> <!--padding;button里面的文字与button边界的间隔--> <padding android:top="10dp" android:right="10dp" android:left="10dp" android:bottom="10dp"/> </shape> tag_bg.xml<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/checked_bg" android:state_checked="true"> </item> <item android:drawable="@drawable/normal_bg"></item> </selector>
values下的文件夹
attrs,xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="TagFlowLayout"> <attr name="auto_select_effect" format="boolean"></attr> <attr name="max_select" format="integer"></attr> <attr name="gravity"> <enum name="left" value="-1" /> <enum name="center" value="0" /> <enum name="right" value="1" /> </attr> </declare-styleable> </resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="kxb">#ff00</color> <color name="hui">#ff888888</color> <color name="huang">#F8F8FF00</color> <color name="lv">#ff00ff00</color> <color name="qing">#00FFFF</color> <color name="lan">#ff0000ff</color> <color name="zi">#ffff00ff</color> </resources>
styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources>
strings.xml
<resources> <string name="app_name">LGank</string> </resources>
SouSuoActivity.java类
import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.bwei.lgank.R; import com.bwei.lgank.adapter.TagAdapter; import com.bwei.lgank.bean.ColorBean; import com.bwei.lgank.sp; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.List; public class SouSuoActivity extends AppCompatActivity { private int color; private TagFlowLayout mFlowLayout; private EditText editText; private Button button; private List<String> strings; //布局管理器 private LayoutInflater mInflater; //流式布局的子布局 private TextView tv; public Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: mFlowLayout.setAdapter(new TagAdapter<String>(strings) { @Override public View getView(FlowLayout parent, int position, String s) { tv = (TextView) mInflater.inflate(R.layout.tv, mFlowLayout, false); tv.setText(s); return tv; } }); break; } super.handleMessage(msg); } }; private LinearLayout ss; private ImageView shanchu; private Button ssfinish; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Window window = getWindow(); getSupportActionBar().hide(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //透明状态栏 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //透明导航栏 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); } setContentView(R.layout.activity_sou_suo); mInflater = LayoutInflater.from(this); EventBus.getDefault().register(this); ss = (LinearLayout) findViewById(R.id.ss); Object color = sp.getData(SouSuoActivity.this, "color", R.color.kxb); ss.setBackgroundColor((Integer) color); mFlowLayout = (TagFlowLayout) findViewById(R.id.id_flowlayout); editText = (EditText) findViewById(R.id.edt); button = (Button) findViewById(R.id.btn); strings = new ArrayList<>(); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String aa = editText.getText().toString().trim(); strings.add(aa); editText.getText().clear(); //通知handler更新UI handler.sendEmptyMessageDelayed(1, 0); } }); shanchu = (ImageView) findViewById(R.id.shanchu); shanchu.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { strings.clear(); handler.sendEmptyMessageDelayed(1, 0); } }); ssfinish = (Button) findViewById(R.id.ssfinish); ssfinish.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); //流式布局tag的点击方法 mFlowLayout.setOnTagClickListener(new TagFlowLayout.OnTagClickListener() { @Override public boolean onTagClick(View view, int position, FlowLayout parent) { Toast.makeText(SouSuoActivity.this, tv.getText(), Toast.LENGTH_SHORT).show(); return true; } }); } @Subscribe(sticky = true,threadMode = ThreadMode.MAIN) public void onEvent(ColorBean colorBean){ color =colorBean.getColor(); } @Override public void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }
TagFlowLayout类
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcelable; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import com.bwei.lgank.R; import com.bwei.lgank.adapter.TagAdapter; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * Created by zhy on 15/9/10. */ public class TagFlowLayout extends FlowLayout implements TagAdapter.OnDataChangedListener { private TagAdapter mTagAdapter; private boolean mAutoSelectEffect = true; private int mSelectedMax = -1;//-1为不限制数量 private static final String TAG = "TagFlowLayout"; private MotionEvent mMotionEvent; private Set<Integer> mSelectedView = new HashSet<Integer>(); public TagFlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout); mAutoSelectEffect = ta.getBoolean(R.styleable.TagFlowLayout_auto_select_effect, true); mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1); ta.recycle(); if (mAutoSelectEffect) { setClickable(true); } } public TagFlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public TagFlowLayout(Context context) { this(context, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { TagView tagView = (TagView) getChildAt(i); if (tagView.getVisibility() == View.GONE) continue; if (tagView.getTagView().getVisibility() == View.GONE) { tagView.setVisibility(View.GONE); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public interface OnSelectListener { void onSelected(Set<Integer> selectPosSet); } private OnSelectListener mOnSelectListener; public void setOnSelectListener(OnSelectListener onSelectListener) { mOnSelectListener = onSelectListener; if (mOnSelectListener != null) setClickable(true); } public interface OnTagClickListener { boolean onTagClick(View view, int position, FlowLayout parent); } private OnTagClickListener mOnTagClickListener; public void setOnTagClickListener(OnTagClickListener onTagClickListener) { mOnTagClickListener = onTagClickListener; if (onTagClickListener != null) setClickable(true); } public void setAdapter(TagAdapter adapter) { mTagAdapter = adapter; mTagAdapter.setOnDataChangedListener(this); mSelectedView.clear(); changeAdapter(); } private void changeAdapter() { removeAllViews(); TagAdapter adapter = mTagAdapter; TagView tagViewContainer = null; HashSet preCheckedList = mTagAdapter.getPreCheckedList(); for (int i = 0; i < adapter.getCount(); i++) { View tagView = adapter.getView(this, i, adapter.getItem(i)); tagViewContainer = new TagView(getContext()); // ViewGroup.MarginLayoutParams clp = (ViewGroup.MarginLayoutParams) tagView.getLayoutParams(); // ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(clp); // lp.width = ViewGroup.LayoutParams.WRAP_CONTENT; // lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; // lp.topMargin = clp.topMargin; // lp.bottomMargin = clp.bottomMargin; // lp.leftMargin = clp.leftMargin; // lp.rightMargin = clp.rightMargin; tagView.setDuplicateParentStateEnabled(true); if (tagView.getLayoutParams() != null) { tagViewContainer.setLayoutParams(tagView.getLayoutParams()); } else { MarginLayoutParams lp = new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.setMargins(dip2px(getContext(), 5), dip2px(getContext(), 5), dip2px(getContext(), 5), dip2px(getContext(), 5)); tagViewContainer.setLayoutParams(lp); } tagViewContainer.addView(tagView); addView(tagViewContainer); if (preCheckedList.contains(i)) { tagViewContainer.setChecked(true); } if (mTagAdapter.setSelected(i, adapter.getItem(i))) { mSelectedView.add(i); tagViewContainer.setChecked(true); } } mSelectedView.addAll(preCheckedList); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { mMotionEvent = MotionEvent.obtain(event); } return super.onTouchEvent(event); } @Override public boolean performClick() { if (mMotionEvent == null) return super.performClick(); int x = (int) mMotionEvent.getX(); int y = (int) mMotionEvent.getY(); mMotionEvent = null; TagView child = findChild(x, y); int pos = findPosByView(child); if (child != null) { doSelect(child, pos); if (mOnTagClickListener != null) { return mOnTagClickListener.onTagClick(child.getTagView(), pos, this); } } return true; } public void setMaxSelectCount(int count) { if (mSelectedView.size() > count) { Log.w(TAG, "you has already select more than " + count + " views , so it will be clear ."); mSelectedView.clear(); } mSelectedMax = count; } public Set<Integer> getSelectedList() { return new HashSet<Integer>(mSelectedView); } private void doSelect(TagView child, int position) { if (mAutoSelectEffect) { if (!child.isChecked()) { //处理max_select=1的情况 if (mSelectedMax == 1 && mSelectedView.size() == 1) { Iterator<Integer> iterator = mSelectedView.iterator(); Integer preIndex = iterator.next(); TagView pre = (TagView) getChildAt(preIndex); pre.setChecked(false); child.setChecked(true); mSelectedView.remove(preIndex); mSelectedView.add(position); } else { if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) return; child.setChecked(true); mSelectedView.add(position); } } else { child.setChecked(false); mSelectedView.remove(position); } if (mOnSelectListener != null) { mOnSelectListener.onSelected(new HashSet<Integer>(mSelectedView)); } } } public TagAdapter getAdapter() { return mTagAdapter; } private static final String KEY_CHOOSE_POS = "key_choose_pos"; private static final String KEY_DEFAULT = "key_default"; @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState()); String selectPos = ""; if (mSelectedView.size() > 0) { for (int key : mSelectedView) { selectPos += key + "|"; } selectPos = selectPos.substring(0, selectPos.length() - 1); } bundle.putString(KEY_CHOOSE_POS, selectPos); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; String mSelectPos = bundle.getString(KEY_CHOOSE_POS); if (!TextUtils.isEmpty(mSelectPos)) { String[] split = mSelectPos.split("\\|"); for (String pos : split) { int index = Integer.parseInt(pos); mSelectedView.add(index); TagView tagView = (TagView) getChildAt(index); if (tagView != null) tagView.setChecked(true); } } super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT)); return; } super.onRestoreInstanceState(state); } private int findPosByView(View child) { final int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { View v = getChildAt(i); if (v == child) return i; } return -1; } private TagView findChild(int x, int y) { final int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { TagView v = (TagView) getChildAt(i); if (v.getVisibility() == View.GONE) continue; Rect outRect = new Rect(); v.getHitRect(outRect); if (outRect.contains(x, y)) { return v; } } return null; } @Override public void onChanged() { mSelectedView.clear(); changeAdapter(); } public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } } TagView类import android.content.Context; import android.view.View; import android.widget.Checkable; import android.widget.FrameLayout; /** * Created by zhy on 15/9/10. */ public class TagView extends FrameLayout implements Checkable { private boolean isChecked; private static final int[] CHECK_STATE = new int[]{android.R.attr.state_checked}; public TagView(Context context) { super(context); } public View getTagView() { return getChildAt(0); } @Override public int[] onCreateDrawableState(int extraSpace) { int[] states = super.onCreateDrawableState(extraSpace + 1); if (isChecked()) { mergeDrawableStates(states, CHECK_STATE); } return states; } /** * Change the checked state of the view * * @param checked The new checked state */ @Override public void setChecked(boolean checked) { if (this.isChecked != checked) { this.isChecked = checked; refreshDrawableState(); } } /** * @return The current checked state of the view */ @Override public boolean isChecked() { return isChecked; } /** * Change the checked state of the view to the inverse of its current state */ @Override public void toggle() { setChecked(!isChecked); } }
TagAdapter适配器import android.view.View; import com.bwei.lgank.myview.FlowLayout; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; public abstract class TagAdapter<T> { private List<T> mTagDatas; private OnDataChangedListener mOnDataChangedListener; private HashSet<Integer> mCheckedPosList = new HashSet<Integer>(); public TagAdapter(List<T> datas) { mTagDatas = datas; } public TagAdapter(T[] datas) { mTagDatas = new ArrayList<T>(Arrays.asList(datas)); } public interface OnDataChangedListener { void onChanged(); } public void setOnDataChangedListener(OnDataChangedListener listener) { mOnDataChangedListener = listener; } public void setSelectedList(int... poses) { Set<Integer> set = new HashSet<>(); for (int pos : poses) { set.add(pos); } setSelectedList(set); } public void setSelectedList(Set<Integer> set) { mCheckedPosList.clear(); if (set != null) mCheckedPosList.addAll(set); notifyDataChanged(); } public HashSet<Integer> getPreCheckedList() { return mCheckedPosList; } public int getCount() { return mTagDatas == null ? 0 : mTagDatas.size(); } public void notifyDataChanged() { mOnDataChangedListener.onChanged(); } public T getItem(int position) { return mTagDatas.get(position); } public abstract View getView(FlowLayout parent, int position, T t); public boolean setSelected(int position, T t) { return false; } }