main.xml布局 <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:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.select.MainActivity"> <com.example.select.SearchView android:id="@+id/searchView" android:layout_margin="5dp" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp"> </com.example.select.SearchView> <LinearLayout android:id="@+id/layout_notice" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="9" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="4dp" android:paddingLeft="10dp" android:paddingTop="4dp" android:text="热搜" android:textColor="#ff0000" android:textSize="12sp" /> <com.example.select.FlawLayout android:id="@+id/flowlayout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3"> </com.example.select.FlawLayout> <LinearLayout android:id="@+id/search_history_ll" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="8" android:orientation="vertical" android:visibility="gone"> <TextView android:id="@+id/contentTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingBottom="4dp" android:paddingLeft="10dp" android:paddingTop="4dp" android:text="历史搜索" android:textSize="12sp" /> <ListView android:id="@+id/listView" style="@style/common_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="@color/default_line_color" android:dividerHeight="0.5dp" android:listSelector="@drawable/list_item_selector"></ListView> <Button android:id="@+id/clear_history_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:background="@drawable/round_btn_selector" android:text="清除历史搜索记录" android:textSize="14sp" /> </LinearLayout> </LinearLayout> </LinearLayout>
MainActivity主页面
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private String[] mVals = new String[]{"Java", "Android", "iOS", "Python", "Mac OS", "PHP", "JavaScript", "Objective-C", "Groovy", "Pascal", "Ruby", "Go", "Swift"}; private LayoutInflater mInflater; private FlawLayout mFlowlayout; private SharedPreferences mPref; public SearchView searchView; public static final String EXTRA_KEY_TYPE = "extra_key_type"; public static final String EXTRA_KEY_KEYWORD = "extra_key_keyword"; public static final String KEY_SEARCH_HISTORY_KEYWORD = "key_search_history_keyword"; private String mType; private List<String> mHistoryKeywords; private LinearLayout mSearchHistoryLl; private ListView listView; private Button clear_history_btn; private ArrayAdapter<String> arrayAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate( savedInstanceState ); setContentView( R.layout.activity_main ); initFlowView(); initHistoryView(); } private void initHistoryView() { searchView = findViewById(R.id.searchView); //获取SharedPreferences mPref = getSharedPreferences("input", MODE_PRIVATE); mType = getIntent().getStringExtra(EXTRA_KEY_TYPE); String keyword = getIntent().getStringExtra(EXTRA_KEY_KEYWORD); if (!TextUtils.isEmpty(keyword)) { searchView.setInputText(keyword); } //记录文本 mHistoryKeywords = new ArrayList<String>(); searchView.setOnSearchViewListener(new SearchView.OnSearchViewListener() { @Override public void onClickSearch(View view) { String keywords = searchView.getInputText(); if(!TextUtils.isEmpty(keywords)){ Toast.makeText(MainActivity.this, keywords + "添加成功", Toast.LENGTH_LONG).show(); save(); }else{ Toast.makeText(MainActivity.this, "请输入搜索信息", Toast.LENGTH_LONG).show(); } save(); } @Override public void onTextChange(CharSequence s) { if (s.length() == 0) { if (mHistoryKeywords.size() > 0) { mSearchHistoryLl.setVisibility(View.VISIBLE); } else { mSearchHistoryLl.setVisibility(View.GONE); } } else { mSearchHistoryLl.setVisibility(View.GONE); } } }); initSeachHistory(); } /* 初始化搜索历史记录 */ private void initSeachHistory() { mSearchHistoryLl = findViewById(R.id.search_history_ll); listView = findViewById(R.id.listView); clear_history_btn = findViewById(R.id.clear_history_btn); clear_history_btn.setOnClickListener(MainActivity.this); String history = mPref.getString(KEY_SEARCH_HISTORY_KEYWORD, ""); if (!TextUtils.isEmpty(history)) { List<String> list = new ArrayList<String>(); for (Object o : history.split(",")) { list.add((String) o); } mHistoryKeywords = list; } if(mHistoryKeywords.size() > 0){ mSearchHistoryLl.setVisibility(View.VISIBLE); }else{ mSearchHistoryLl.setVisibility(View.GONE); } //适配器 arrayAdapter = new ArrayAdapter<>(this, R.layout.item_search_history, mHistoryKeywords); listView.setAdapter(arrayAdapter); //条目点击监听 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { searchView.setInputText(mHistoryKeywords.get(position)); mSearchHistoryLl.setVisibility(View.GONE); } }); //刷新适配器 arrayAdapter.notifyDataSetChanged(); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.clear_history_btn: clearHistory(); break; } } //清空历史记录 private void clearHistory() { mPref = getSharedPreferences("input",MODE_PRIVATE); SharedPreferences.Editor editor = mPref.edit(); editor.remove(KEY_SEARCH_HISTORY_KEYWORD).commit(); //清空集合数据 mHistoryKeywords.clear(); //刷新适配器 arrayAdapter.notifyDataSetChanged(); mSearchHistoryLl.setVisibility(View.GONE); Toast.makeText(MainActivity.this, "清楚搜索历史成功", Toast.LENGTH_LONG).show(); } //储存历史记录 private void save() { String text = searchView.getInputText(); String oldText = mPref.getString(KEY_SEARCH_HISTORY_KEYWORD, ""); if(!TextUtils.isEmpty(text) && !(oldText.contains(text))){ //判断集合的长度,最多保存条目 if(mHistoryKeywords.size() > 5){ return; }else{ SharedPreferences.Editor editor = mPref.edit(); editor.putString(KEY_SEARCH_HISTORY_KEYWORD, text + "-->" + oldText); editor.commit(); mHistoryKeywords.add(0,text); } } //刷新适配器 arrayAdapter.notifyDataSetChanged(); } /* initFlowView和initData与流式布局相关 */ private void initFlowView() { mInflater = LayoutInflater.from(this); mFlowlayout = findViewById(R.id.flowlayout); //初始化数据 initData(); } private void initData() { for (int i = 0; i < mVals.length; i++) { TextView tv = (TextView) mInflater.inflate(R.layout.search_lable_tv, mFlowlayout, false); tv.setText(mVals[i]); final String str = tv.getText().toString(); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { searchView.setInputText(str); } }); mFlowlayout.addView(tv); } } }
继承 ViewGroup 类
public class FlawLayout extends ViewGroup { //存储所有子View private List<List<View>> mAllChildViews = new ArrayList<>(); //每一行的高度 private List<Integer> mLineHeight = new ArrayList<>(); public FlawLayout(Context context) { this(context, null); } public FlawLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlawLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //父控件传进来的宽度和高度以及对应的测量模式 int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); //如果当前ViewGroup的宽高为wrap_content的情况 int width = 0;//自己测量的宽度 int height = 0;//自己测量的高度 //记录每一行的宽度和高度 int lineWidth = 0; int lineHeight = 0; //获取子view的个数 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); //测量子View的宽和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); //得到LayoutParams MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); //子View占据的宽度 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; //子View占据的高度 int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; //换行时候 if (lineWidth + childWidth > sizeWidth) { //对比得到最大的宽度 width = Math.max(width, lineWidth); //重置lineWidth lineWidth = childWidth; //记录行高 height += lineHeight; lineHeight = childHeight; } else {//不换行情况 //叠加行宽 lineWidth += childWidth; //得到最大行高 lineHeight = Math.max(lineHeight, childHeight); } //处理最后一个子View的情况 if (i == childCount - 1) { width = Math.max(width, lineWidth); height += lineHeight; } } //wrap_content setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width, modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllChildViews.clear(); mLineHeight.clear(); //获取当前ViewGroup的宽度 int width = getWidth(); int lineWidth = 0; int lineHeight = 0; //记录当前行的view List<View> lineViews = new ArrayList<View>(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); //如果需要换行 if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width) { //记录LineHeight mLineHeight.add(lineHeight); //记录当前行的Views mAllChildViews.add(lineViews); //重置行的宽高 lineWidth = 0; lineHeight = childHeight + lp.topMargin + lp.bottomMargin; //重置view的集合 lineViews = new ArrayList(); } lineViews.add(child); lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin); } //处理最后一行 mLineHeight.add(lineHeight); mAllChildViews.add(lineViews); //设置子View的位置 int left = 0; int top = 0; //获取行数 int lineCount = mAllChildViews.size(); for (int i = 0; i < lineCount; i++) { //当前行的views和高度 lineViews = mAllChildViews.get(i); lineHeight = mLineHeight.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); //判断是否显示 if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int cLeft = left + lp.leftMargin; int cTop = top + lp.topMargin; int cRight = cLeft + child.getMeasuredWidth(); int cBottom = cTop + child.getMeasuredHeight(); //进行子View进行布局 child.layout(cLeft, cTop, cRight, cBottom); left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = 0; top += lineHeight; } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
SearchView 类的xml布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:orientation="horizontal"> <EditText
android:id="@+id/et_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:hint="请输入你想搜索的内容"
android:maxLines="1"
android:paddingLeft="5dp"
android:paddingRight="5dp" />
<Button
android:id="@+id/btn_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@drawable/round_btn_selector"
android:text="搜索" /></LinearLayout>
SearchView 类
public class SearchView extends LinearLayout{ private EditText input; public SearchView(Context context) { this(context,null); } public SearchView(Context context, @Nullable AttributeSet attrs) { this(context, attrs,0); } public SearchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } //设置监听 public interface OnSearchViewListener{ void onClickSearch(View view); void onTextChange(CharSequence s); } //声明监听 private OnSearchViewListener listener; //提供监听方法 public void setOnSearchViewListener(OnSearchViewListener listener){ this.listener = listener; } private void initView(Context context) { View view = View.inflate(context,R.layout.search_title,this); //找到控件 input = view.findViewById(R.id.et_input); Button btn_search = view.findViewById(R.id.btn_search); btn_search.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(listener != null){ listener.onClickSearch(v); } } }); input.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if(listener != null){ listener.onTextChange(s); } } @Override public void afterTextChanged(Editable s) { } }); } //提供取值的方法 public String getInputText(){ return input.getText().toString(); } //提供赋值的方法 public void setInputText(String string){ input.setText(string); } }item_search_history.xml布局
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/contentTextView" android:layout_width="match_parent" android:layout_height="51dp" android:paddingLeft="10dp" android:gravity="center_vertical" android:background="@drawable/list_item_selector" android:textSize="14sp" android:textColor="#ff403b37"> </TextView>search_lable_tv.xml布局
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:background="@drawable/search_label" android:paddingBottom="10dp" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingTop="10dp" android:text="Helloworld" android:textColor="#3f3e3e" android:textSize="14sp"> </TextView>