Android 模仿淘宝历史记录,记录存在手机内
首先书写控件:
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;//存储子View的LayoutParams 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);//获取子View的LayoutParams,(子View的LayoutParams的对象类型,取决于其ViewGroup的generateLayoutParams()方法的返回的对象类型,这里返回的是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+父控件左内边距开始,y从0+父控件上内边距开始) 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;//子View的LayoutParams 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();//获取子View的LayoutParams,用于获取其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", "表searchHisTab的name=" + 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);}} }
Android 模仿淘宝历史记录,记录存在手机内相关推荐
- Android模仿淘宝详情页界面
话不多说-先上效果图: 图1中主要需要实现的效果: 1.轮播图 2.顶部导航栏的渐变 3.顶部导航栏随着滑动的位置选择对应的值以及点击滑动到对应位置 Android模仿淘宝详情页界面文件:url80. ...
- Android模仿淘宝语音输入条形动画,录音动画自定义View
Android模仿淘宝语音输入条形动画自定义View,类似柱状音频,折线音频,音乐跳动,音频跳动,录音动画,语音输入效果 地址: https://github.com/xfans/VoiceWaveV ...
- 基于Android的淘宝网手机客户端开发见解(配完整视频教程讲解)
淘宝网手机客户端是一个基于Android进行应用的项目,通过该客户端实现了注册功能.登陆.分页展示商品列表.能够对商品按名称进行模糊查询.能够对商品进行管理.能够对商品按价格排序.可以查看商品详细信息 ...
- 爬虫实战系列!淘宝店铺各品牌手机售卖信息爬取及可视化!
声明:本博客只是简单的爬虫示范,并不涉及任何商业用途. 一.前言 最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝"下毒手"了.由于本人平时经常喜欢在淘 ...
- 爬虫实战系列(八):淘宝店铺各品牌手机售卖信息爬取及可视化
声明:本博客只是简单的爬虫示范,并不涉及任何商业用途. 一.前言 最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝"下毒手"了.由于本人平时经常喜欢在淘 ...
- Bootstrap网格系统工作原理、网格系统前缀、利用网格系统实现导航栏效果、栅格系统中的列嵌套、栅格系统中的列偏移、栅格系统中的自动布局列、栅格系统中的重排序、模仿淘宝网站商品展示的页面效果
Bootstrap 网格系统 1.Bootstrap网格系统工作原理 Bootstrap的网格系统是指将页面布局划分为等宽的列.随着屏幕或视口尺寸的增加,系统会自动分为1~12列. 网格系统用于通过一 ...
- Android仿淘宝淘口令实现
先复制信息到剪切板,然后再打开淘宝,.既然是复制,肯定是复制到系统的剪切板了,我们可以通过下边的代码来把口令给复制到系统的剪切板里 1 2 3 4 5 6 //获取剪贴板管理器: ClipboardM ...
- 淘宝店铺各品牌手机售卖信息爬取及可视化!
一.前言 最近博主在浏览淘宝时突然萌发了一个想爬它的念头,于是说干就干,我便开始向淘宝"下毒手"了.由于本人平时经常喜欢在淘宝上浏览各种手机的信息,于是我便以"手机&qu ...
- UI设计:模仿淘宝App首页
UI设计:模仿淘宝App首页
最新文章
- 配置伪静态(URL重写)
- Nagios+pnp4nagios+rrdtool 安装配置为nagios添加自定义插件(三)
- 刘强东宣布: 未来京东将减员50%,每天工作3小时!无人公司来了……
- C++拓展笔记2-3:C++中this指针用法简介
- 开源作品ThinkJDBC—一行代码搞定数据库操作
- Java+Selenium爬贴吧
- [LCS]LCS2005服务器应用程序
- MFC里的GDI CDC HDC到底是什么?
- 【Openstack】【Nova】开发者入门,开发工作流
- javascript一些基础知识
- 法庭智能语音系统_法庭智能语音识别系统_法庭智能语音系统解决方案_深圳市亚讯威视数字技术有限公司...
- Win10如何安装VC6
- 信息管理系统项目前端界面设计
- slf4j、log4j日志级别与配置
- 核心交换机有什么用?如何选择?
- 老中医治蛋变成绿色了
- Kubernetes学习之路(一)之概念和架构解析和证书创建和分发
- w10更新后怎么找计算机全民,Win10系统下全民WiFi不能用了怎么办
- 计算机毕业设计springboot基于疫情背景下的新型点餐送餐系统bpe1s源码+系统+程序+lw文档+部署
- 全球及中国水解蚕丝蛋白行业研究及十四五规划分析报告