首先书写控件:

activity_main.xml

ps:我自己写的已经和淘宝差不多了,但代码要灵活,所有我吧一些不必要的样式全部去掉了,功能还在,只需自己加一写华丽的样式就行

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:custom="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"><RelativeLayout
        android:id="@+id/shdztop"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"><EditText
            android:id="@+id/et_search"
            android:layout_width="match_parent"
            android:layout_height="35dp"
            android:layout_marginBottom="10dp"
            android:layout_marginRight="20dp"
            android:layout_marginTop="36dp"
            android:hint="搜索优惠宝贝"
            android:imeOptions="actionSearch"
            android:windowSoftInputMode="stateHidden|adjustPan"
            android:inputType="textPersonName"
            android:singleLine="true"
            android:text=""
            android:textColorHint="#CCCCCC"
            android:textSize="12dp" /></RelativeLayout><LinearLayout
        android:id="@+id/Pll01"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/shdztop"
        android:background="#ffffff"
        android:orientation="vertical"><LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"><View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:background="#EEEEEE"></View><TextView
                    android:id="@+id/tv_clear"
                    android:layout_width="match_parent"
                    android:layout_height="40dp"
                    android:background="#F6F6F6"
                    android:gravity="center"
                    android:text="清除搜索历史" /></LinearLayout></LinearLayout><com.example.spakebrony.viewgrouptb.FlowViewGroup
        android:background="#00ffffff"
        android:padding="5dp"
        android:layout_below="@+id/Pll01"
        android:id="@+id/flowlayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"></com.example.spakebrony.viewgrouptb.FlowViewGroup></RelativeLayout>

item_flow.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:text="Demo Test"
    android:background="@drawable/textview_bg"
    android:layout_margin="10dp"
    />

接着书写java文件

RecordSQLiteOpenHelper.java

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;public class RecordSQLiteOpenHelper extends SQLiteOpenHelper {private static String name = "temp.db";private static Integer version = 1;public RecordSQLiteOpenHelper(Context context) {super(context, name, null, version);}@Override
    public void onCreate(SQLiteDatabase db) {db.execSQL("create table records(id integer primary key autoincrement,name varchar(200))");}@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}

重写ViewGroup:

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;/**
 * 流式布局
 * Created by zhangxutong on 2016/1/17.
 */
public class FlowViewGroup extends ViewGroup {private static final String TAG = "zxt/FlowViewGroup";public FlowViewGroup(Context context) {this(context, null);}public FlowViewGroup(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FlowViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}//onMeasure里,测量所有子View的宽高,以及确定Viewgroup自己的宽高。
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//获取系统传递过来测量出的宽度 高度,以及相应的测量模式。
        //如果测量模式为 EXACTLY( 确定的dp值,match_parent),则可以调用setMeasuredDimension()设置,
        //如果测量模式为 AT_MOST(wrap_content),则需要经过计算再去调用setMeasuredDimension()设置
        int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);//计算宽度 高度 //wrap_content测量模式下会使用到:
        //存储最后计算出的宽度,
        int maxLineWidth = 0;//存储最后计算出的高度
        int totalHeight = 0;//存储当前行的宽度
        int curLineWidth = 0;//存储当前行的高度
        int curLineHeight = 0;// 得到内部元素的个数
        int count = getChildCount();//存储子View
        View child =null;//存储子ViewLayoutParams
        MarginLayoutParams params =null;//View Layout需要的宽高(包含margin),用于计算是否越界
        int childWidth;int childHeight;//遍历子View 计算父控件宽高
        for (int i = 0; i < count; i++) {child = getChildAt(i);//如果gone,不测量了
            if (View.GONE == child.getVisibility()) {continue;}//先测量子View
            measureChild(child, widthMeasureSpec, heightMeasureSpec);//获取子ViewLayoutParams(ViewLayoutParams的对象类型,取决于其ViewGroupgenerateLayoutParams()方法的返回的对象类型,这里返回的是MarginLayoutParams)
            params = (MarginLayoutParams) child.getLayoutParams();//View需要的宽度 为 子View 本身宽度+marginLeft + marginRight
            childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin;childHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin;Log.i(TAG, "View Layout需要的宽高(包含margin)childWidth:" + childWidth + "   ,childHeight:" + childHeight);//如果当前的行宽度大于 父控件允许的最大宽度 则要换行
            //父控件允许的最大宽度 如果要适配 padding 这里要- getPaddingLeft() - getPaddingRight()
            //即为测量出的宽度减去父控件的左右边距
            if (curLineWidth + childWidth > widthMeasure - getPaddingLeft() - getPaddingRight()) {//通过比较 当前行宽 和以前存储的最大行宽,得到最新的最大行宽,用于设置父控件的宽度
                maxLineWidth = Math.max(maxLineWidth, curLineWidth);//父控件的高度增加了,为当前高度+当前行的高度
                totalHeight += curLineHeight;//换行后 刷新 当前行 宽高数据: 因为新的一行就这一个View,所以为当前这个view占用的宽高(要加上View  margin)
                curLineWidth = childWidth;curLineHeight = childHeight;} else {//不换行:叠加当前行宽 和 比较当前行高:
                curLineWidth += childWidth;curLineHeight = Math.max(curLineHeight, childHeight);}//如果已经是最后一个View,要比较当前行的 宽度和最大宽度,叠加一共的高度
            if (i == count - 1) {maxLineWidth = Math.max(maxLineWidth, curLineWidth);totalHeight += childHeight;}}Log.i(TAG, "系统测量允许的尺寸最大值:widthMeasure:" + widthMeasure + "   ,heightMeasure:" + heightMeasure);Log.i(TAG, "经过我们测量实际的尺寸(不包括父控件的padding)maxLineWidth:" + maxLineWidth + "   ,totalHeight:" + totalHeight);Log.i(TAG, "heightMode == MeasureSpec.AT_MOST:" +(heightMode == MeasureSpec.AT_MOST));Log.i(TAG, "heightMode == MeasureSpec.EXACTLY:" +(heightMode == MeasureSpec.EXACTLY));Log.i(TAG, "heightMode == MeasureSpec.UNSPECIFIED:" +(heightMode == MeasureSpec.UNSPECIFIED));//适配padding,如果是wrap_content,则除了子控件本身占据的控件,还要在加上父控件的padding
        setMeasuredDimension(widthMode != MeasureSpec.EXACTLY ? maxLineWidth + getPaddingLeft() + getPaddingRight() : widthMeasure,heightMode != MeasureSpec.EXACTLY ? totalHeight + getPaddingTop() + getPaddingBottom() : heightMeasure);//fix by zhangxutong 有些页面太长了
    }//布局父控件位置以及子控件的位置
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {Log.i(TAG, "changed:" + changed + "   ,l:" + l + "  t:" + t + "  r:" + r + "  b:" + b);//子控件的个数
        int count = getChildCount();//ViewParent宽度(包含padding)
        int width = getWidth();//ViewParent 的右边x的布局限制值
        int rightLimit =  width - getPaddingRight();//存储基准的left top (子类.layout(),里的坐标是基于父控件的坐标,所以 x应该是从0+父控件左内边距开始,y0+父控件上内边距开始)
        int baseLeft = 0 + getPaddingLeft();int baseTop = 0 + getPaddingTop();//存储现在的left top
        int curLeft = baseLeft;int curTop = baseTop;//View
        View child = null;//view用于layout l t r b
        int viewL,viewT,viewR,viewB;//ViewLayoutParams
        MarginLayoutParams params = null;//View Layout需要的宽高(包含margin),用于计算是否越界
        int childWidth;int childHeight;//View 本身的宽高
        int childW,childH;//临时增加一个temp 存储上一个View的高度 解决过长的两行View导致显示不正确的bug
        int lastChildHeight =0;//
        for (int i = 0; i < count; i++) {child = getChildAt(i);//如果gone,不布局了
            if (View.GONE == child.getVisibility()) {continue;}//获取子View本身的宽高:
            childW = child.getMeasuredWidth();childH = child.getMeasuredHeight();//获取子ViewLayoutParams,用于获取其margin
            params = (MarginLayoutParams) child.getLayoutParams();//View需要的宽高 为 本身宽高+marginLeft + marginRight
            childWidth =  childW + params.leftMargin + params.rightMargin;childHeight = childH + params.topMargin + params.bottomMargin;//这里要考虑padding,所以右边界为 ViewParent宽度(包含padding) -ViewParent右内边距
            if (curLeft + childWidth > rightLimit ) {//如果当前行已经放不下该子View了 需要换行放置:
                //在新的一行布局子View,左x就是baseLeft,上y top +前一行高(这里假设的是每一行行高一样)                curTop = curTop + lastChildHeight;//layout时要考虑margin
                viewL = baseLeft +params.leftMargin;viewT = curTop + params.topMargin;viewR = viewL + childW;viewB = viewT + childH;//child.layout(baseLeft + params.leftMargin, curTop + params.topMargin, baseLeft + params.leftMargin + child.getMeasuredWidth(), curTop + params.topMargin + child.getMeasuredHeight());
                //Log.i(TAG,"新的一行:" +"   ,baseLeft:"+baseLeft +"  curTop:"+curTop+"  baseLeft+childWidth:"+(baseLeft+childWidth)+"  curTop+childHeight:"+ ( curTop+childHeight));
                curLeft = baseLeft + childWidth;} else {//当前行可以放下子View:
                viewL = curLeft +params.leftMargin;viewT = curTop + params.topMargin;viewR = viewL + childW;viewB = viewT + childH;//child.layout(curLeft + params.leftMargin, curTop + params.topMargin, curLeft + params.leftMargin + child.getMeasuredWidth(), curTop + params.topMargin + child.getMeasuredHeight());
                //Log.i(TAG,"当前行:"+changed +"   ,curLeft:"+curLeft +"  curTop:"+curTop+"  curLeft+childWidth:"+(curLeft+childWidth)+"  curTop+childHeight:"+(curTop+childHeight));
                curLeft = curLeft + childWidth;}lastChildHeight = childHeight;//布局子View
            child.layout(viewL,viewT,viewR,viewB);}}/**
     * @return 当前ViewGroup返回的Params的类型
     */
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}
}

最后: MainActivity.java

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SimpleAdapter;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class MainActivity extends AppCompatActivity {TextView tv;private ArrayList<String> list=new ArrayList<String>();private FlowViewGroup mFlowViewGroup;private EditText et_search;private TextView tv_tip;private TextView tv_clear;private RecordSQLiteOpenHelper helper = new RecordSQLiteOpenHelper(this);;private SQLiteDatabase db;private ImageButton Pib01;public MainActivity() {}@Override
    public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化控件
        initView();Intent intent = getIntent();// 清空搜索历史
        tv_clear.setOnClickListener(new View.OnClickListener() {@Override
            public void onClick(View v) {deleteData();initDatas("");mFlowViewGroup.setVisibility(View.INVISIBLE);finish();Intent intent = new Intent(MainActivity.this, MainActivity.class);startActivity(intent);overridePendingTransition(0,0);}});// 搜索框的键盘搜索键点击回调
        et_search.setOnKeyListener(new View.OnKeyListener() {// 输入完后按键盘上的搜索键

            public boolean onKey(View v, int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {// 修改回车键功能
                    // 先隐藏键盘
                    ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);// 按完搜索键后将当前查询的关键字保存起来,如果该关键字已经存在就不执行保存
                    boolean hasData = hasData(et_search.getText().toString().trim());if (!hasData) {insertData(et_search.getText().toString().trim());queryData_(String.valueOf(et_search.getText()));}finish();Intent intent = new Intent(MainActivity.this,MainActivity.class);intent.putExtra("ss",et_search.getText().toString().trim());startActivity(intent);}return false;}});// 搜索框的文本变化实时监听
        et_search.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) {}@Override
            public void afterTextChanged(Editable s) {String tempName = et_search.getText().toString();// 根据tempName去模糊查询数据库中有没有数据
                //initDatas(tempName);

            }});// 插入数据,便于测试,否则第一次进入没有数据怎么测试呀?
        insertData(null);/*// 第一次进入查询所有的历史记录
        queryData("");*/
        initDatas("");}/**
     * 插入数据
     */
    private void insertData(String tempName) {if (tempName!=null) {db = helper.getWritableDatabase();db.execSQL("insert into records(name) values('" + tempName + "')");db.close();}}/**
     * 模糊查询数据
     */
    private void queryData_(String tempName) {Cursor cursor = helper.getReadableDatabase().rawQuery("select id as _id,name from records where name like '%" + tempName + "%' order by id desc ", null);if (cursor.moveToNext()) {cursor.moveToFirst();int a=0;do {String name = cursor.getString(cursor.getColumnIndex("name"));Log.i("TAG", "searchHisTabname=" + name);if (name != null && !name.equals("")) {list.add(name);}} while (cursor.moveToNext());cursor.close();}}/**
     * 检查数据库中是否已经有该条记录
     */
    private boolean hasData(String tempName) {Cursor cursor = helper.getReadableDatabase().rawQuery("select id as _id,name from records where name =?", new String[]{tempName});//判断是否有下一个
        return cursor.moveToNext();}/**
     * 清空数据
     */
    private void deleteData() {db = helper.getWritableDatabase();db.execSQL("delete from records");db.close();}private void initView() {mFlowViewGroup = (FlowViewGroup) findViewById(R.id.flowlayout);et_search = (EditText) findViewById(R.id.et_search);tv_clear = (TextView) findViewById(R.id.tv_clear);et_search.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {if (actionId == EditorInfo.IME_ACTION_SEARCH) {Log.i("---","搜索操作执行");/* jsonArray1=null;
                    init2(null);*/
                }return false;}});}/**
     * 隐藏软键盘
     *
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {View v = getCurrentFocus();if (isShouldHideInput(v, ev)) {InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);if (imm != null) {imm.hideSoftInputFromWindow(v.getWindowToken(), 0);}}return super.dispatchTouchEvent(ev);}// 必不可少,否则所有的组件都不会有TouchEvent        if (getWindow().superDispatchTouchEvent(ev)) {return true;}return onTouchEvent(ev);}public boolean isShouldHideInput(View v, MotionEvent event) {if (v != null && (v instanceof EditText)) {int[] leftTop = {0, 0};//获取输入框当前的location位置
            v.getLocationInWindow(leftTop);int left = leftTop[0];int top = leftTop[1];int bottom = top + v.getHeight();int right = left + v.getWidth();if (event.getX() > left && event.getX() < right&& event.getY() > top && event.getY() < bottom) {// 点击的是输入框区域,保留点击EditText的事件
                return false;} else {return true;}}return false;}private void initDatas(String name) {queryData_(name);for (int i=0;i<list.size();i++){tv= (TextView) LayoutInflater.from(this).inflate(R.layout.item_flow,mFlowViewGroup,false);tv.setText(list.get(i));tv.setOnClickListener(new View.OnClickListener() {@Override
                public void onClick(View v) {//Toast.makeText(Pdd_search.this,""+((TextView)v).getText(),Toast.LENGTH_SHORT).show();
                    et_search.setText(((TextView)v).getText());}});mFlowViewGroup.addView(tv);}}
}
ps: MainActivity比较灵活,虽大致不需要改的,单跳转页面的位置需要改动
效果图

Android 模仿淘宝历史记录,记录存在手机内相关推荐

  1. Android模仿淘宝详情页界面

    话不多说-先上效果图: 图1中主要需要实现的效果: 1.轮播图 2.顶部导航栏的渐变 3.顶部导航栏随着滑动的位置选择对应的值以及点击滑动到对应位置 Android模仿淘宝详情页界面文件:url80. ...

  2. Android模仿淘宝语音输入条形动画,录音动画自定义View

    Android模仿淘宝语音输入条形动画自定义View,类似柱状音频,折线音频,音乐跳动,音频跳动,录音动画,语音输入效果 地址: https://github.com/xfans/VoiceWaveV ...

  3. 基于Android的淘宝网手机客户端开发见解(配完整视频教程讲解)

    淘宝网手机客户端是一个基于Android进行应用的项目,通过该客户端实现了注册功能.登陆.分页展示商品列表.能够对商品按名称进行模糊查询.能够对商品进行管理.能够对商品按价格排序.可以查看商品详细信息 ...

  4. 爬虫实战系列!淘宝店铺各品牌手机售卖信息爬取及可视化!

    声明:本博客只是简单的爬虫示范,并不涉及任何商业用途. 一.前言 最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝"下毒手"了.由于本人平时经常喜欢在淘 ...

  5. 爬虫实战系列(八):淘宝店铺各品牌手机售卖信息爬取及可视化

    声明:本博客只是简单的爬虫示范,并不涉及任何商业用途. 一.前言 最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝"下毒手"了.由于本人平时经常喜欢在淘 ...

  6. Bootstrap网格系统工作原理、网格系统前缀、利用网格系统实现导航栏效果、栅格系统中的列嵌套、栅格系统中的列偏移、栅格系统中的自动布局列、栅格系统中的重排序、模仿淘宝网站商品展示的页面效果

    Bootstrap 网格系统 1.Bootstrap网格系统工作原理 Bootstrap的网格系统是指将页面布局划分为等宽的列.随着屏幕或视口尺寸的增加,系统会自动分为1~12列. 网格系统用于通过一 ...

  7. Android仿淘宝淘口令实现

    先复制信息到剪切板,然后再打开淘宝,.既然是复制,肯定是复制到系统的剪切板了,我们可以通过下边的代码来把口令给复制到系统的剪切板里 1 2 3 4 5 6 //获取剪贴板管理器: ClipboardM ...

  8. 淘宝店铺各品牌手机售卖信息爬取及可视化!

    一.前言 最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝"下毒手"了.由于本人平时经常喜欢在淘宝上浏览各种手机的信息,于是我便以"手机&qu ...

  9. UI设计:模仿淘宝App首页

    UI设计:模仿淘宝App首页

最新文章

  1. 配置伪静态(URL重写)
  2. Nagios+pnp4nagios+rrdtool 安装配置为nagios添加自定义插件(三)
  3. 刘强东宣布: 未来京东将减员50%,每天工作3小时!无人公司来了……
  4. C++拓展笔记2-3:C++中this指针用法简介
  5. 开源作品ThinkJDBC—一行代码搞定数据库操作
  6. Java+Selenium爬贴吧
  7. [LCS]LCS2005服务器应用程序
  8. MFC里的GDI CDC HDC到底是什么?
  9. 【Openstack】【Nova】开发者入门,开发工作流
  10. javascript一些基础知识
  11. 法庭智能语音系统_法庭智能语音识别系统_法庭智能语音系统解决方案_深圳市亚讯威视数字技术有限公司...
  12. Win10如何安装VC6
  13. 信息管理系统项目前端界面设计
  14. slf4j、log4j日志级别与配置
  15. 核心交换机有什么用?如何选择?
  16. 老中医治蛋变成绿色了
  17. Kubernetes学习之路(一)之概念和架构解析和证书创建和分发
  18. w10更新后怎么找计算机全民,Win10系统下全民WiFi不能用了怎么办
  19. 计算机毕业设计springboot基于疫情背景下的新型点餐送餐系统bpe1s源码+系统+程序+lw文档+部署
  20. 全球及中国水解蚕丝蛋白行业研究及十四五规划分析报告

热门文章

  1. 解决RuntimeError: stack expects a non-empty Tensorlist问题
  2. 创建学生表,课程表,班级表,班级课程表
  3. YAML详解 是什么
  4. 抓到Netty一个隐藏很深的内存泄露Bug | 详解Recycler对象池的精妙设计与实现
  5. 毕业设计 大数据B站数据分析与可视化 - python 数据分析 大数据
  6. 网吧电脑算完整的计算机系统么,怎么看网吧电脑的系统和位数?
  7. 如何输出一个国际象棋棋盘
  8. 【笔试强训】Day_02
  9. psd 将分组合并导出png图片
  10. element table 左对齐