效果图
1主页面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<!--标题放大镜和输入框的自定义view-->
<com.example.day04_water_fall02.TitleBarView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!--搜索历史的自定义view和热门搜索公用一个-->
<com.example.day04_water_fall02.WaterGroupNameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="搜索历史"
android:textColor="#00ff00" />
<!--显示内容的自定义view-->
<com.example.day04_water_fall02.WaterFall
android:id="@+id/water_fall_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp" />
<Button
android:id="@+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="清空历史"
/>
<!--热门搜索的自定义view-->
<com.example.day04_water_fall02.WaterGroupNameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="热门搜索"
android:textColor="#00ffff" />
<!--显示内容的自定义view-->
<com.example.day04_water_fall02.WaterFall
android:id="@+id/water_fall_hot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp" />
</LinearLayout>
2.标题放大镜和输入框的布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/search_title"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerVertical="true"
android:background="@drawable/search"
/>
<EditText
android:id="@+id/edit_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/search_title"
/>
</RelativeLayout>
3.放大镜和输入框的自定义view类TitleBarView继承LinearLayout
package com.example.day04_water_fall02;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class TitleBarView extends LinearLayout {
private Context context;
private EditText editText;
private ImageView imageView;
public TitleBarView(Context context) {
super(context);
this.context = context;
init();
}
public TitleBarView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
//第三步:设置成员变量
private OnButtonClientListener onButtonClientListener;
private void init() {
View view = View.inflate(context,R.layout.title,null);
editText = view.findViewById(R.id.edit_title);
imageView = view.findViewById(R.id.search_title);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//第六步:在将要回调的地方,首先判断非空
if(onButtonClientListener!=null){
//第七步:执行回调方法,传参
onButtonClientListener.onButtonClick(editText.getText().toString());
}
}
});
addView(view);
}
//第一步 定义一个接口
public interface OnButtonClientListener{
//第二步 写好方法和回传参数
void onButtonClick(String str);
}
//第四步:传入,并且给成员变量赋值
//第五步:在想要接受回调的地方,调用set方法,设置监听详见MainActivity第41行
public void setOnButtonClientListener(OnButtonClientListener onButtonClientListener) {
this.onButtonClientListener = onButtonClientListener;
}
}
4.自定义属性的xml(在values下建一个 attrs.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomTurntable">
<!--name为属性的名字,可以随意起,只要符合规则看的懂-->
<!--format为属性内容的类型-->
<attr name="text" format="string"/>
</declare-styleable>
<declare-styleable name="WeekFlowLayout">
<attr name="textColor" format="color"/>
</declare-styleable>
</resources>
5.实现搜索历史和热门搜索的自定义view类WaterGroupNameLayout需要继承TextView
package com.example.day04_water_fall02;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.widget.TextView;
@SuppressLint("AppCompatCustomView")
public class WaterGroupNameLayout extends TextView {
public WaterGroupNameLayout(Context context) {
super(context);
}
public WaterGroupNameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//自定义属性
//第一步,在value文件夹下建立一个attr.xml文件,
//第二步,写<declear....标签
//第三步,写<attr 标签 name:方法名 format:属性
//第四步,在自定义view中的有AttributeSet的构造方法里写以下代码
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.WeekFlowLayout);
int color = array.getColor(R.styleable.WeekFlowLayout_textColor, Color.BLUE);
//第五步,在布局文件根控件中写xmlns:app="http://schemas.android.com/apk/res-auto"
//第六步,在想要调用自定义属性的控件中添加app:方法名=“想要设置的值”
setTextColor(color);
//第七步最后要回收
array.recycle();
}
}
6.显示内容的自定义view类WaterFall需要继承LinearLayout
package com.example.day04_water_fall02;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
public class WaterFall extends LinearLayout {
/**
* 孩子中最高的一个
*/
private int mChildMaxHeight;
/**
* 每个孩子的左右间距
* 默认是20单位是px
*/
private int mHSpace = 20;
/**
* 每一行的上下间距
* 20是默认值,单位是px
*/
private int mVSpace = 20;
public WaterFall(Context context) {
super(context);
}
public WaterFall(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//拿到父容器的宽高以及计算模式
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
//测量孩子的大小
measureChildren(widthMeasureSpec, heightMeasureSpec);
//寻找孩子中最高的的一个孩子,找到的值会放在mChildMaxHeight变量中
findMaxChildMaxHeight();
//初始化值
int left = 0, top = 0;
//循环所有的孩子
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
//判断是否是一行的开头
if (left != 0) {
//如果子元素的宽度+左边距>大于夫需要换行了,因为放不下
if ((left + view.getMeasuredWidth()) > sizeWidth) {
//计算出下一行的top
top += mChildMaxHeight + mVSpace;
//重新计算 left需要归零
left = 0;
}
}
left += view.getMeasuredWidth() + mHSpace;
}
setMeasuredDimension(sizeWidth, (top + mChildMaxHeight) > sizeHeight ? sizeHeight : top + mChildMaxHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
findMaxChildMaxHeight();
//开始安排孩子的位置
//出始化
int left = 0, top = 0;
//循环所有的孩子
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
//判断是否是一行的开头
if (left != 0) {
//需要换行了,因为放不下
if ((left + view.getMeasuredWidth()) > getWidth()) {
//计算出下一行的top
top += mChildMaxHeight + mVSpace;
left = 0;
}
}
//安排孩子的位置
view.layout(left, top, left + view.getMeasuredWidth(), top + mChildMaxHeight);
left += view.getMeasuredWidth() + mHSpace;
}
}
//寻找孩子中最高的一个孩子
private void findMaxChildMaxHeight() {
mChildMaxHeight = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
//返回指定位置的视图
View view = getChildAt(i);
//指定的高度是否打于最高的高度
if (view.getMeasuredHeight() > mChildMaxHeight) {
//如果大于就把指定的高度赋值最高的
mChildMaxHeight = view.getMeasuredHeight();
}
}
}
}
7.在drawable下创建shape textshape.xml用来给显示内容的textview自定义边框
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#00000000"/>
<corners android:radius="10px"/>
<stroke
android:width="1px"
android:color="#999999"
/>
</shape>
8.MainActivity页面分别获取自定义view的布局
package com.example.day04_water_fall02;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.example.day04_water_fall02.db.WaterDao;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private WaterFall waterFall;
private EditText editText;
private Button button;
private List<String> list = new ArrayList<>();
private WaterFall waterFall_seach;
private WaterFall waterFall_hot;
private TitleBarView title;
private Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
waterFall_seach = findViewById(R.id.water_fall_search);
waterFall_hot = findViewById(R.id.water_fall_hot);
title = findViewById(R.id.title);
button = findViewById(R.id.clear);
//点击
title.setOnButtonClientListener(new TitleBarView.OnButtonClientListener() {
private String uuid1;
@Override
public void onButtonClick(final String str) {
if (str.equals("")) {
return;
} else {
final TextView textView = new TextView(MainActivity.this);
//随机字符串当做唯一标识
UUID uuid = UUID.randomUUID();
textView.setTag(uuid);
uuid1 = String.valueOf(textView.getTag());
WaterDao.getIntance(MainActivity.this).add(str, uuid1);
textView.setText(str);
textView.setTextSize(20);
textView.setBackgroundResource(R.drawable.textshape);
waterFall_seach.addView(textView);
//长按删除
textView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
WaterDao.getIntance(MainActivity.this).del(uuid1);
waterFall_seach.removeView(v);
return true;
}
});
//点击提示
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"点击了"+str,Toast.LENGTH_SHORT).show();
}
});
}
}
});
//第二次进入页面从数据库查出来展示
List<WaterBean> select = WaterDao.getIntance(MainActivity.this).select();
if (select.size() != 0) {
for (final WaterBean s : select) {
final TextView textView = new TextView(MainActivity.this);
textView.setText(s.getName());
textView.setTextSize(20);
textView.setBackgroundResource(R.drawable.textshape);
waterFall_seach.addView(textView);
//长按删除
textView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
WaterDao.getIntance(MainActivity.this).del(s.getUuid());
waterFall_seach.removeView(v);
return true;
}
});
//点击提示
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"点击了"+s.getName(),Toast.LENGTH_SHORT).show();
}
});
}
}
//热门搜索
String[] str = new String[]{
"水煮肉片", "锅包肉", "鱼香肉丝", "水煮鱼", "木须肉", "地三鲜", "尖椒干豆腐"
, "干锅土豆片", "汉堡", "炸鸡", "可乐", "啤酒", "火腿", "米饭"
};
for (int i = 0; i < str.length; i++) {
TextView textView1 = new TextView(MainActivity.this);
textView1.setText(str[i]);
textView1.setTextSize(20);
textView1.setBackgroundResource(R.drawable.textshape);
waterFall_hot.addView(textView1);
}
//清空历史
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
WaterDao.getIntance(MainActivity.this).delAll();
waterFall_seach.removeAllViews();
}
});
}
}
9.使用数据库需要的bean 里面有两个参数其中uuid是为了根据UUID来删除单个
package com.example.day04_water_fall02;
public class WaterBean {
private String name;
private String uuid;
public WaterBean(String name, String uuid) {
this.name = name;
this.uuid = uuid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
}
10.数据库创建表页面
package com.example.day04_water_fall02.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SqlitHelper extends SQLiteOpenHelper {
public SqlitHelper(Context context) {
super(context, "Water.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table waters(id integer primary key autoincrement," +
"name text," +
"uuid text)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
11.数据库写增删改查方法页
package com.example.day04_water_fall02.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.example.day04_water_fall02.WaterBean;
import java.util.ArrayList;
import java.util.List;
public class WaterDao {
private static WaterDao intance;
private Context context;
private final SqlitHelper sqlitHelper;
private final SQLiteDatabase sb;
public WaterDao(Context context) {
this.context = context;
sqlitHelper = new SqlitHelper(context);
sb = sqlitHelper.getWritableDatabase();
}
public static WaterDao getIntance(Context context) {
if (intance==null){
intance = new WaterDao(context);
}
return intance;
}
//添加
public void add(String name,String uuid){
ContentValues values = new ContentValues();
values.put("name",name);
values.put("uuid",uuid);
sb.insert("waters",null,values);
}
//删除
public void del(String uuid ){
sb.delete("waters","uuid = ?",new String[]{uuid});
}
//删除所有
public void delAll(){
sb.delete("waters",null,null);
}
//查询
public List<WaterBean> select(){
List<WaterBean> list = new ArrayList<>();
Cursor waters = sb.query("waters", null, null, null, null, null, null, null);
if(waters!=null){
while (waters.moveToNext()){
String name = waters.getString(waters.getColumnIndex("name"));
String uuid = waters.getString(waters.getColumnIndex("uuid"));
WaterBean waterBean = new WaterBean(name,uuid);
list.add(waterBean);
}
}
return list;
}
}