输入框布局的shape
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="30dp"/> <stroke android:width="2dp" android:color="@color/darkgray"/> <solid android:color="@color/color_white"/> <padding android:top="8dp" android:bottom="8dp" android:left="5dp"/> </shape>
热搜流式布局的shape
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <!-- <solid android:color="@android:color/white"/>--> <corners android:radius="28dp"/> <stroke android:width="1dp" android:color="#3799f4"/> <padding android:left="5dp" android:right="5dp" android:top="5dp" android:bottom="5dp" /> </shape>
自定义流式布局View的主体内容
import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; /** * Created by Dewey . * 自定义流式布局显示搜索框 */ public class FlowLayout extends ViewGroup { public FlowLayout(Context context, AttributeSet attrs, int defStyle){ super(context, attrs, defStyle); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context) { this(context, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // 如果是warp_content情况下,记录宽和高 int width = 0; int height = 0; // 记录每一行的宽度与高度 int lineWidth = 0; int lineHeight = 0; // 得到内部元素的个数 int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { // 通过索引拿到每一个子view View child = getChildAt(i); // 测量子View的宽和高,系统提供的measureChild measureChild(child, widthMeasureSpec, heightMeasureSpec); // 得到LayoutParams MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); // 子View占据的宽度 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; // 子View占据的高度 int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; // 换行 判断 当前的宽度大于 开辟新行 if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { // 对比得到最大的宽度 width = Math.max(width, lineWidth); // 重置lineWidth lineWidth = childWidth; // 记录行高 height += lineHeight; lineHeight = childHeight; } else // 未换行 { // 叠加行宽 lineWidth += childWidth; // 得到当前行最大的高度 lineHeight = Math.max(lineHeight, childHeight); } // 特殊情况,最后一个控件 if (i == cCount - 1) { width = Math.max(lineWidth, width); height += lineHeight; } } setMeasuredDimension( modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(), modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()// ); } /** * 存储所有的View */ private List<List<View>> mAllViews = new ArrayList<List<View>>(); /** * 每一行的高度 */ private List<Integer> mLineHeight = new ArrayList<Integer>(); @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllViews.clear(); mLineHeight.clear(); // 当前ViewGroup的宽度 int width = getWidth(); int lineWidth = 0; int lineHeight = 0; // 存放每一行的子view List<View> lineViews = new ArrayList<View>(); int cCount = getChildCount(); for (int i = 0; i < cCount; 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 - getPaddingLeft() - getPaddingRight()) { // 记录LineHeight mLineHeight.add(lineHeight); // 记录当前行的Views mAllViews.add(lineViews); // 重置我们的行宽和行高 lineWidth = 0; lineHeight = childHeight + lp.topMargin + lp.bottomMargin; // 重置我们的View集合 lineViews = new ArrayList<View>(); } lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin); lineViews.add(child); }// for end // 处理最后一行 mLineHeight.add(lineHeight); mAllViews.add(lineViews); // 设置子View的位置 int left = getPaddingLeft(); int top = getPaddingTop(); // 行数 int lineNum = mAllViews.size(); for (int i = 0; i < lineNum; i++) { // 当前行的所有的View lineViews = mAllViews.get(i); lineHeight = mLineHeight.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); // 判断child的状态 if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); // 为子View进行布局 child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = getPaddingLeft(); top += lineHeight; } } /** * 与当前ViewGroup对应的LayoutParams */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
主MainActivity布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" > <LinearLayout android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:layout_gravity="center_vertical" android:layout_marginLeft="8dp" android:layout_width="50dp" android:layout_height="50dp" android:src="@drawable/left" android:id="@+id/backJian" /> <LinearLayout android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" > <EditText android:id="@+id/edit_input" android:layout_gravity="center_vertical" android:layout_margin="10dp" android:drawableLeft="@drawable/search_icon" android:drawablePadding="5dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/search_edittext_shape" android:textSize="16sp" android:imeOptions="actionSearch" android:inputType="text" android:hint="请输入关键字"/> </LinearLayout> <ImageView android:src="@drawable/right" android:id="@+id/search_btn" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_gravity="center_vertical" android:layout_width="50dp" android:layout_height="50dp"/> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_marginTop="10dp" android:layout_height="1dp" android:background="#050505" /> <!-- 流式布局 --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:textStyle="bold" android:textSize="18sp" android:text="热搜" /> <!--自定义的flowlayout,引用的是自己的包名--> <com.example.custom.FlowLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:id="@+id/id_flowlayout" > </com.example.custom.FlowLayout> <TextView android:layout_width="match_parent" android:layout_marginTop="10dp" android:layout_height="1dp" android:background="#050505" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:textStyle="bold" android:textSize="18sp" android:text="搜索记录" /> <android.support.v7.widget.RecyclerView android:id="@+id/history_recyclerView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dp"></android.support.v7.widget.RecyclerView> <Button android:layout_width="match_parent" android:layout_marginRight="60dp" android:layout_marginLeft="60dp" android:layout_height="40dp" android:background="#ffffff" android:text="清空历史搜索" android:id="@+id/clearbtn"/> </LinearLayout>
主 MainActivity功能代码
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import org.greenrobot.greendao.query.Query; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; /* 搜索框页面: 1. 搜索框输入内容 2. 自定义流式布局,展示搜索的菜名记录 3. 使用GreenDao操作数据库,保存搜索记录,当下次进入搜索页面,能展示记录 4. 点击清除按钮清除数据库内容 5. 点击搜索,根据搜索内容,请求数据 */ public class MainActivity extends Activity { @BindView(R.id.edit_input) EditText editInput; @BindView(R.id.search_btn) ImageView searchBtn; @BindView(R.id.history_recyclerView) RecyclerView historyRecyclerView; @BindView(R.id.id_flowlayout) FlowLayout flowlayout; private HistoryAdapter historyAdapter; List<String> list = new ArrayList<>(); //历史搜索输入数据集合 private Query<SearchDaoBean> queryDao; //历史搜索查询数据集合 private SearchDaoBeanDao dao; private String flows[] = { "应急启动电源", "餐桌", "粽子散装", "智能手表", "摩托车配件", "批发方便面", "王中王火腿", "手机", "桶装矿泉水", "U盘64G", "机械革命电脑", "洗发水", "护发素", "奶粉", "search", "logcat" }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); //自定义流式布局初始化视图 initChildViews(); //设置搜索记录布局视图 initHistoryResultData(); //获取数据库实例,把历史记录显示在页面上 dao = MyApplication.session.getSearchDaoBeanDao(); queryDao = dao.queryBuilder().orderAsc(SearchDaoBeanDao.Properties.Id).build(); List<SearchDaoBean> daoBeanList = queryList(); for (int i = 0; i < daoBeanList.size(); i++) { list.add(daoBeanList.get(i).getSelectGoods()); } } //流式布局 public void initChildViews() { ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); //下面为 热搜流式布局子条目间距 lp.leftMargin = 10; lp.rightMargin = 10; lp.topMargin = 10; lp.bottomMargin = 10; for(int i = 0; i < flows.length; i ++){ TextView view = new TextView(this); view.setText(flows[i]); view.setTextSize(21); //view.setTextColor(Color.WHITE); view.setBackgroundDrawable(getResources().getDrawable(R.drawable.label_bg)); //添加到父View flowlayout.addView(view,lp); } } private void initHistoryResultData() { //设置搜索结果适配器以及布局管理器 historyRecyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false)); historyAdapter = new HistoryAdapter(MainActivity.this, list); historyRecyclerView.setAdapter(historyAdapter); } @OnClick({R.id.search_btn, R.id.clearbtn , R.id.backJian}) public void onViewClicked(View view) { switch (view.getId()) { //点击搜索按钮,传递数据RecyclerView显示,并存入数据库 case R.id.search_btn: //判断输入为空情况下 String string = editInput.getText().toString().trim(); if (TextUtils.isEmpty(string) || string.length() == 0) { Toast.makeText(this, "输入内容不能为空", Toast.LENGTH_SHORT).show(); return; } //保存搜索历史到数据库 String trim = editInput.getText().toString().trim(); SearchDaoBean daoBean = new SearchDaoBean(null, "1775", "TheScar", trim); dao.insert(daoBean); historyAdapter.notifyDataSetChanged(); break; //清空历史搜索集合,,清空数据库,刷新数据 case R.id.clearbtn: list.clear(); deleteAllData(); historyAdapter.notifyDataSetChanged(); break; //销毁当前页面 case R.id.backJian: finish(); break; default: break; } } //查询全部数据的方法 private List<SearchDaoBean> queryList() { List<SearchDaoBean> daoBeans = queryDao.list(); return daoBeans; } //删除所有数据,即清空历史记录 public void deleteAllData() { dao.deleteAll(); } }
历史搜索记录布局适配器 HistoryAdapter
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.example.duhongwang20180601.R; import java.util.List; /** * 历史搜索记录数据 适配器 */ public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHolder>{ private Context context; private List<String> list; public HistoryAdapter(Context context, List<String> list) { this.context = context; this.list = list; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = View.inflate(context, R.layout.layout_history, null); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.tv.setText(list.get(position)); } @Override public int getItemCount() { return list.size(); } public class ViewHolder extends RecyclerView.ViewHolder { private TextView tv; public ViewHolder(View itemView) { super(itemView); tv = (TextView)itemView.findViewById(R.id.history_text); } } }
适配器对应的布局 layout_history.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/history_text" android:layout_margin="7dp" android:textSize="15sp" android:text="" /> </LinearLayout>
GreenDao全局配置初始化 MyApplication
import android.app.Application; import com.example.duhongwang20180601.dao.DaoMaster; import com.example.duhongwang20180601.dao.DaoSession; import com.facebook.drawee.backends.pipeline.Fresco; import org.greenrobot.greendao.database.Database; /** * Fresco GreenDao 的初始化全局配置类 */ public class MyApplication extends Application { //抽取为全局变量 public static DaoSession session; @Override public void onCreate() { super.onCreate(); //1. Fresco Fresco.initialize(this); //2. GreenDao DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "rikao"); Database db = helper.getWritableDb(); session = new DaoMaster(db).newSession(); } }
搜索框输入数据封装为 GreenDao bean 类
import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Generated; /** * Created by Dewey . * 搜索框输入数据封装为 DreenDao bean 类 */ @Entity public class SearchDaoBean { @Id(autoincrement = true) private Long id; private String uid; private String uname; private String selectGoods; @Generated(hash = 1024397953) public SearchDaoBean(Long id, String uid, String uname, String selectGoods) { this.id = id; this.uid = uid; this.uname = uname; this.selectGoods = selectGoods; } @Generated(hash = 1406499419) public SearchDaoBean() { } public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getUid() { return this.uid; } public void setUid(String uid) { this.uid = uid; } public String getUname() { return this.uname; } public void setUname(String uname) { this.uname = uname; } public String getSelectGoods() { return this.selectGoods; } public void setSelectGoods(String selectGoods) { this.selectGoods = selectGoods; } }
布局用到的图片
left.png

right.png
search_icon.png
功能依赖
//1. Recycycleview compile 'com.android.support:recyclerview-v7:26.+'
//2.添加GreenDao及数据库database的依赖 compile 'org.greenrobot:greendao:3.2.2' compile 'org.greenrobot:greendao-generator:3.0.0' compile 'net.zetetic:android-database-sqlcipher:3.5.7@aar' //数据库加密(较新版本)
//7.ButtonKnife //butterknife在Studio3.0版本上需使用以下8.8.1版本(下面2行代码都要加) compile 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.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
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101

首先流式布局搜索框 - 优快云博客
2018-5-31
Android 热门搜索,自定义流式布局,自动换行,自动补齐
二话不说,先上图,如果是你们苦苦寻找的效果,请接着往下看。 绝对干货,直接上代码,直接讲用法,不讲原理,不讲思路,不绕弯弯,就是这么实在!就是喜欢你们复制粘贴! 想要知道如何实现的,代码里面的...
Android搜索框存储搜索记录 - 优快云博客
越来越多的App都用到了搜索框,公司的项目也用到了搜索框,还提出来以下需求:输入...Android 流式布局 + 搜索记录,包括多数据本地存储 转载地址为:http://www....
2018-5-25
FlowLayout流式布局实现搜索清空历史记录 - 优快云博客
2018-5-18
Android 仿快播搜索框上方悬浮的文字搜索
仿快播搜索框页面悬浮的搜索关键字漂浮、飞入飞出的效果 综合评分:4 收藏(4)...android 流添加 热门搜索,切换历史与热门 上传资源 uuid12345 关注 积分97 ...
2018-5-8
自定义view+流式布局+greendao历史搜索 - 优快云博客
2018-5-30
搜索框历史记录,流式布局 - 优快云博客
2018-5-2
Android中关键词的流式布局 - 优快云博客
项目的开发过程中,用到了如上图所示的流式布局,在一番查找之后,在一叶飘舟大神博客的基础上,进行了一些编写,由于之前基本没有使用过自定义的控件,所以属于边敲...
2018-5-22
自定义流式布局实现搜索历史
public class FlowLayout extends ViewGroup{ public FlowLayout(Context context, AttributeSet attr...
Android搜索控件简介
2018-5-4
搜索历史记录流式布局展示
Config package com.tan.searchhistory.constants; public class Config { //数据库 public sta...
Android仿天猫搜索历史记录显示自定义布局
这两天都在弄搜索界面,网上查看了下,参考了下面这位兄弟的: https://www.oschina.net/question/54100_32893 顺便把图也搬了 这个有个缺点,就是必须全屏,...
Android自定义View实现流式布局TextView
2016年12月30日 18KB 下载