├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── misc.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── tangguna
│ │ └── searchbox
│ │ └── searchbox
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── tangguna
│ │ │ └── searchbox
│ │ │ └── searchbox
│ │ │ ├── MainActivity.java
│ │ │ └── SearchActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── search.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── tangguna
│ └── searchbox
│ └── searchbox
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── img
├── Screenshot_1536113887.png
├── Screenshot_1536113915.png
├── Screenshot_1536113922.png
├── Screenshot_1536113962.png
└── Screenshot_1536126402.png
├── library
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── tangguna
│ │ └── searchbox
│ │ └── library
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── tangguna
│ │ │ └── searchbox
│ │ │ └── library
│ │ │ ├── adapter
│ │ │ ├── HistoryDataAdapter.java
│ │ │ └── HistoryDataListViewAdapter.java
│ │ │ ├── cache
│ │ │ └── HistoryCache.java
│ │ │ ├── callback
│ │ │ └── onSearchCallBackListener.java
│ │ │ └── widget
│ │ │ ├── FlowLayout.java
│ │ │ ├── SearchLayout.java
│ │ │ ├── SearchListLayout.java
│ │ │ ├── SelfSearchGridView.java
│ │ │ └── SelfSearchListView.java
│ └── res
│ │ ├── drawable-xhdpi
│ │ ├── explore_search_close.png
│ │ ├── explore_search_close_nt.png
│ │ ├── explore_search_icon.png
│ │ ├── explore_search_icon_nt.png
│ │ ├── icon_clear_data.png
│ │ └── icon_close.png
│ │ ├── drawable
│ │ ├── bg_shadow_set_bottom.xml
│ │ ├── ll_clear_bg.xml
│ │ ├── search.xml
│ │ ├── search_baground_shap.xml
│ │ ├── search_title_baground_shap.xml
│ │ ├── search_title_baground_shap2.xml
│ │ ├── sousuo_back_or_search_button_shap.xml
│ │ ├── sousuo_bg_gray_1.xml
│ │ ├── sousuo_bg_gray_2.xml
│ │ ├── sousuo_bg_gray_3.xml
│ │ ├── sousuo_bg_gray_4.xml
│ │ ├── sousuo_bg_gray_5.xml
│ │ ├── sousuo_bg_gray_state_pressed_shap.xml
│ │ ├── sousuo_bg_level.xml
│ │ └── sousuo_clearolddata_shap.xml
│ │ ├── layout
│ │ ├── list_item.xml
│ │ ├── msearch_top.xml
│ │ ├── msearchlayout.xml
│ │ ├── search_olddata_item.xml
│ │ ├── searchlistlayout.xml
│ │ └── suosou_item.xml
│ │ └── values
│ │ ├── color.xml
│ │ ├── strings.xml
│ │ └── style.xml
│ └── test
│ └── java
│ └── com
│ └── tangguna
│ └── searchbox
│ └── library
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SearchBox
2 | android 自定义选择框
3 | ##### gridView布局
4 | 
5 | ##### ListView布局
6 | 
7 | ### 功能
8 | 1.包含历史搜索,热门搜索;
9 | 2.可以从服务器或者本地加载数据;
10 | 3.历史记录缓存,动态添加记录
11 | 4 listView,gridView两种显示方式
12 | ### 配置
13 | #### 在根build.gradle中添加
14 | allprojects {
15 | repositories {
16 | ...
17 | maven { url 'https://jitpack.io' }
18 | }
19 | }
20 | #### 添加依赖
21 | dependencies {
22 | implementation 'com.github.tangguna:SearchBox:1.0.1'
23 | }
24 |
25 | ###使用方式
26 | #### 实现接口onSearchCallBackListener
27 | public abstract void Search(String str):搜索关键字
28 | public abstract void Back():返回
29 | public abstract void ClearOldData():清空历史记录
30 | public abstract void SaveOldData(ArrayList AlloldDataList):保存搜索记录
31 | #### 调用 GridView
32 | 在XML中添加布局
33 |
39 |
40 | #### 实现initData(@Nullable List olddatalist,@Nullable List hotdata, onSearchCallBackListener sCb,int styleId)
41 | /**
42 | *
43 | * @param olddatalist 历史搜索数据集合
44 | * @param hotdata 热门搜索数据集合
45 | * @param sCb 事件处理监听
46 | * @param styleId 热门搜索样式(值在1到5之间) 可以在drawable下修改、添加 sousuo_bg_gray_X等样式背景
47 | */
48 | public void initData(@Nullable List olddatalist,@Nullable List hotdata, onSearchCallBackListener sCb,int styleId){
49 | }
50 | #### 在activity中添加:
51 | List skills = HistoryCache.toArray(getApplicationContext());
52 | String shareHotData ="C++,C,PHP,React";
53 | List skillHots = Arrays.asList(shareHotData.split(","));
54 | searchLayout.initData(skills, skillHots, new onSearchCallBackListener() {
55 | @Override
56 | public void Search(String str) {
57 | //进行或联网搜索
58 | Log.e("点击",str.toString());
59 | Bundle bundle = new Bundle();
60 | bundle.putString("data",str);
61 | startActivity(SearchActivity.class,bundle);//此方法为跳转传值,详情见代码
62 | }
63 | @Override
64 | public void Back() {
65 | finish();
66 | }
67 |
68 | @Override
69 | public void ClearOldData() {
70 | //清除历史搜索记录 更新记录原始数据
71 | HistoryCache.clear(getApplicationContext());
72 | Log.e("点击","清除数据");
73 | }
74 | @Override
75 | public void SaveOldData(ArrayList AlloldDataList) {
76 | //保存所有的搜索记录
77 | HistoryCache.saveHistory(getApplicationContext(),HistoryCache.toJsonArray(AlloldDataList));
78 | Log.e("点击","保存数据");
79 | }
80 | },1);
81 |
82 | #### HistoryCache
83 | HistoryCache为历史记录缓存类,包含方法如下:
84 | public static void clear(Context context):清除所有数据
85 | public static void saveHistory(Context context, String result):保存记录
86 | public static String getHistory(Context context):获取保存记录
87 | public static List toArray(Context context):把json数据转换成list
88 | public static String toJsonArray(List historyList):ArrayList 转换成JsonArray
89 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "com.tangguna.searchbox.searchbox"
7 | minSdkVersion 19
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(include: ['*.jar'], dir: 'libs')
23 | implementation 'com.android.support:appcompat-v7:27.0.2'
24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
28 | implementation project(':library')
29 | }
30 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/tangguna/searchbox/searchbox/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.searchbox;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.tangguna.searchbox.searchbox", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tangguna/searchbox/searchbox/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.searchbox;
2 |
3 | import android.content.Intent;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 |
8 | import com.tangguna.searchbox.library.cache.HistoryCache;
9 | import com.tangguna.searchbox.library.callback.onSearchCallBackListener;
10 | import com.tangguna.searchbox.library.widget.SearchListLayout;
11 | import com.tangguna.searchbox.library.widget.SelfSearchListView;
12 |
13 | import java.util.ArrayList;
14 | import java.util.Arrays;
15 | import java.util.List;
16 |
17 | public class MainActivity extends AppCompatActivity {
18 |
19 | private SearchListLayout searchLayout;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_main);
25 | searchLayout = (SearchListLayout)findViewById(R.id.searchlayout);
26 | initData();
27 | }
28 |
29 | private void initData() {
30 | List skills = HistoryCache.toArray(getApplicationContext());
31 | String shareHotData ="C++,C,PHP,React";
32 | List skillHots = Arrays.asList(shareHotData.split(","));
33 | searchLayout.initData(skills, skillHots, new onSearchCallBackListener() {
34 | @Override
35 | public void Search(String str) {
36 | //进行或联网搜索
37 | Log.e("点击",str.toString());
38 | Bundle bundle = new Bundle();
39 | bundle.putString("data",str);
40 | startActivity(SearchActivity.class,bundle);
41 | }
42 | @Override
43 | public void Back() {
44 | finish();
45 | }
46 |
47 | @Override
48 | public void ClearOldData() {
49 | //清除历史搜索记录 更新记录原始数据
50 | HistoryCache.clear(getApplicationContext());
51 | Log.e("点击","清除数据");
52 | }
53 | @Override
54 | public void SaveOldData(ArrayList AlloldDataList) {
55 | //保存所有的搜索记录
56 | HistoryCache.saveHistory(getApplicationContext(),HistoryCache.toJsonArray(AlloldDataList));
57 | Log.e("点击","保存数据");
58 | }
59 | },1);
60 | }
61 |
62 |
63 |
64 | public void startActivity(Class> openClass, Bundle bundle) {
65 | Intent intent = new Intent(this,openClass);
66 | if (null != bundle)
67 | intent.putExtras(bundle);
68 | startActivity(intent);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tangguna/searchbox/searchbox/SearchActivity.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.searchbox;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.widget.TextView;
7 |
8 | public class SearchActivity extends AppCompatActivity {
9 | @Override
10 | protected void onCreate(@Nullable Bundle savedInstanceState) {
11 | super.onCreate(savedInstanceState);
12 | setContentView(R.layout.search);
13 | TextView textView =(TextView) findViewById(R.id.tv_show);
14 |
15 | Bundle bundle = getIntent().getExtras();
16 | if (bundle != null){
17 | textView.setText(bundle.getString("data"));
18 | }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/search.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SearchBox
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/tangguna/searchbox/searchbox/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.searchbox;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.2'
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Sep 04 14:15:51 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/img/Screenshot_1536113887.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/img/Screenshot_1536113887.png
--------------------------------------------------------------------------------
/img/Screenshot_1536113915.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/img/Screenshot_1536113915.png
--------------------------------------------------------------------------------
/img/Screenshot_1536113922.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/img/Screenshot_1536113922.png
--------------------------------------------------------------------------------
/img/Screenshot_1536113962.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/img/Screenshot_1536113962.png
--------------------------------------------------------------------------------
/img/Screenshot_1536126402.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/img/Screenshot_1536126402.png
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | group='com.github.tangguna'
4 | android {
5 | compileSdkVersion 27
6 |
7 |
8 |
9 | defaultConfig {
10 | minSdkVersion 19
11 | targetSdkVersion 27
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 |
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 |
31 | implementation 'com.android.support:appcompat-v7:27.0.2'
32 | testImplementation 'junit:junit:4.12'
33 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
34 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
35 | api 'com.google.code.gson:gson:2.7'
36 | }
37 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/tangguna/searchbox/library/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.tangguna.searchbox.library.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/adapter/HistoryDataAdapter.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 | import android.widget.TextView;
8 |
9 | import com.tangguna.searchbox.library.R;
10 |
11 | import java.util.ArrayList;
12 |
13 | /**
14 | * GridView列表展示历史记录数据
15 | */
16 | public class HistoryDataAdapter extends BaseAdapter {
17 |
18 | private Context context;
19 | private ArrayList list = new ArrayList();
20 |
21 |
22 | public HistoryDataAdapter(Context context, ArrayList list) {
23 | this.context = context;
24 | this.list = list;
25 | }
26 |
27 |
28 | @Override
29 | public int getCount() {
30 | return list.size();
31 | }
32 |
33 | @Override
34 | public Object getItem(int i) {
35 | return list.get(i);
36 | }
37 |
38 | @Override
39 | public long getItemId(int i) {
40 | return i;
41 | }
42 |
43 | @Override
44 | public View getView(int i, View view, ViewGroup viewGroup) {
45 | ViewHolder holder = null;
46 | if (view == null){
47 | holder = new ViewHolder();
48 | view = View.inflate(context,R.layout.search_olddata_item,null);
49 | holder.tv = (TextView) view.findViewById(R.id.text);
50 | view.setTag(holder);
51 | }else {
52 | holder = (ViewHolder) view.getTag();
53 | }
54 | holder.tv.setText(list.get(i));
55 | return view;
56 | }
57 |
58 | public class ViewHolder{
59 | TextView tv;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/adapter/HistoryDataListViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 |
10 | import com.tangguna.searchbox.library.R;
11 |
12 | import java.util.ArrayList;
13 |
14 | /**
15 | * ListView列表展示历史记录
16 | */
17 | public class HistoryDataListViewAdapter extends BaseAdapter {
18 |
19 | private Context context;
20 | private ArrayList list = new ArrayList();
21 |
22 | public HistoryDataListViewAdapter(Context context, ArrayList list) {
23 | this.context = context;
24 | this.list = list;
25 | }
26 |
27 |
28 | @Override
29 | public int getCount() {
30 | return list.size();
31 | }
32 |
33 | @Override
34 | public Object getItem(int i) {
35 | return list.get(i);
36 | }
37 |
38 | @Override
39 | public long getItemId(int i) {
40 | return i;
41 | }
42 |
43 | @Override
44 | public View getView(int i, View view, ViewGroup viewGroup) {
45 | ViewHolder holder = null;
46 | if (view == null){
47 | holder = new ViewHolder();
48 | view = View.inflate(context,R.layout.list_item,null);
49 | holder.tv_info = (TextView)view.findViewById(R.id.tv_info);
50 | view.setTag(holder);
51 | }else {
52 | holder = (ViewHolder) view.getTag();
53 | }
54 | holder.tv_info.setText(list.get(i));
55 | return view;
56 | }
57 |
58 | class ViewHolder{
59 | TextView tv_info;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/cache/HistoryCache.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.cache;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import com.google.gson.Gson;
6 | import com.google.gson.reflect.TypeToken;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 历史缓存工具类
12 | */
13 | public class HistoryCache {
14 |
15 | /**
16 | * 清除所有数据
17 | * @param context
18 | */
19 | public static void clear(Context context) {
20 | SharedPreferences sp = context.getSharedPreferences("record", Context.MODE_PRIVATE);
21 | sp.edit().clear().commit();
22 | }
23 |
24 | /**
25 | * 保存历史记录到SharedPreferences中
26 | *
27 | * @param result
28 | */
29 | public static void saveHistory(Context context, String result) {
30 | SharedPreferences sp = context.getSharedPreferences("record", Context.MODE_PRIVATE);
31 | SharedPreferences.Editor editor = sp.edit();
32 | editor.putString("record_key", result);
33 | editor.commit();
34 | }
35 |
36 | /**
37 | * 获取保存在SharedPreferences中的历史记录
38 | *
39 | * @return
40 | */
41 | public static String getHistory(Context context) {
42 | SharedPreferences sp = context.getSharedPreferences("record", Context.MODE_PRIVATE);
43 | String result = sp.getString("record_key", null);
44 | return result;
45 | }
46 |
47 | /**
48 | * 把json数据转换成list
49 | * @param context
50 | * @return
51 | */
52 | public static List toArray(Context context) {
53 |
54 | String history = getHistory(context);
55 | Gson gson = new Gson();
56 | List retList = gson.fromJson(history, new TypeToken>() {
57 | }.getType());
58 | return retList;
59 | }
60 |
61 | /**
62 | * ArrayList 转换成JsonArray
63 | * @param historyList
64 | * @return
65 | */
66 | public static String toJsonArray(List historyList) {
67 |
68 | Gson gson = new Gson();
69 | return gson.toJson(historyList); // 将JSONArray转换得到String
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/callback/onSearchCallBackListener.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.callback;
2 |
3 | import android.os.Bundle;
4 |
5 | import java.util.ArrayList;
6 |
7 | public interface onSearchCallBackListener {
8 | /**
9 | * @param str 搜索关键字
10 | */
11 | public abstract void Search(String str);
12 | /**
13 | * 后退
14 | */
15 | public abstract void Back();
16 | /**
17 | * 清除历史搜索记录
18 | */
19 | public abstract void ClearOldData();
20 |
21 | /**
22 | * 保存搜索记录
23 | */
24 | public abstract void SaveOldData(ArrayList AlloldDataList);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/widget/FlowLayout.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * 流布局
13 | */
14 | public class FlowLayout extends ViewGroup {
15 |
16 | public FlowLayout(Context context) {
17 | super(context);
18 | }
19 |
20 | public FlowLayout(Context context, AttributeSet attrs) {
21 | super(context, attrs);
22 | }
23 |
24 | public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
25 | super(context, attrs, defStyleAttr);
26 | }
27 |
28 |
29 |
30 | @Override
31 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
32 |
33 | int widthsize = MeasureSpec.getSize(widthMeasureSpec);
34 | int heightsize = MeasureSpec.getSize(heightMeasureSpec);
35 |
36 | int widthmode = MeasureSpec.getMode(widthMeasureSpec);
37 | int heightmode = MeasureSpec.getMode(heightMeasureSpec);
38 |
39 | // wrap_content
40 | int width = 0;
41 | int height = 0;
42 |
43 | // 记录每一行的宽度与高度
44 | int lineWidth = 0;
45 | int lineHeight = 0;
46 |
47 | // 得到内部元素的个数
48 | int cCount = getChildCount();
49 |
50 |
51 | for(int i=0;i widthsize - (getPaddingLeft() + getPaddingRight())) {
70 | // 对比得到最大的宽度
71 | width = Math.max(width, lineWidth);
72 | // 重置lineWidth
73 | lineWidth = childWidth;
74 |
75 | // 记录行高
76 | height += lineHeight;
77 | lineHeight = childHeight;
78 | }
79 | else
80 | {
81 | //未换行
82 | // 叠加行宽
83 | lineWidth += childWidth;
84 | // 得到当前行最大的高度
85 | lineHeight = Math.max(lineHeight, childHeight);
86 | }
87 |
88 | // 最后一个控件
89 | if (i == cCount - 1)
90 | {
91 | width = Math.max(lineWidth, width);
92 | height += lineHeight;
93 | }
94 | }
95 |
96 |
97 | setMeasuredDimension(
98 | widthmode == MeasureSpec.EXACTLY ? widthsize : width + getPaddingLeft() + getPaddingRight(),
99 | heightmode == MeasureSpec.EXACTLY ? heightsize : height + getPaddingTop() + getPaddingBottom()//
100 | );
101 | }
102 |
103 |
104 | /**
105 | * 存储所有的View
106 | */
107 | private List> mAllViews = new ArrayList>();
108 | /**
109 | * 每一行的高度
110 | */
111 | private List mLineHeight = new ArrayList();
112 |
113 | @Override
114 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
115 | mAllViews.clear();
116 | mLineHeight.clear();
117 | // 当前ViewGroup的宽度
118 | int width = getWidth();
119 | int lineWidth = 0;
120 | int lineHeight = 0;
121 | List lineViews = new ArrayList();
122 | int cCount = getChildCount();
123 | for (int i = 0; i < cCount; i++)
124 | {
125 | View child = getChildAt(i);
126 | MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
127 | int childWidth = child.getMeasuredWidth();
128 | int childHeight = child.getMeasuredHeight();
129 | // 如果需要换行
130 | if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight()) {
131 | // 记录LineHeight
132 | mLineHeight.add(lineHeight);
133 | // 记录当前行的Views
134 | mAllViews.add(lineViews);
135 | // 重置我们的行宽和行高
136 | lineWidth = 0;
137 | lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
138 | // 重置我们的View集合
139 | lineViews = new ArrayList();
140 | }
141 |
142 | lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
143 | lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);
144 | lineViews.add(child);
145 | }
146 | // for end
147 | // 处理最后一行
148 | mLineHeight.add(lineHeight);
149 | mAllViews.add(lineViews);
150 |
151 | // 设置子View的位置
152 | int left = getPaddingLeft();
153 | int top = getPaddingTop();
154 | // 行数
155 | int lineNum = mAllViews.size();
156 | for (int i = 0; i < lineNum; i++)
157 | {
158 | // 当前行的所有的View
159 | lineViews = mAllViews.get(i);
160 | lineHeight = mLineHeight.get(i);//相对开始的高度
161 | for (int j = 0; j < lineViews.size(); j++)
162 | {
163 | View child = lineViews.get(j);
164 | // 判断child的状态
165 | if (child.getVisibility() == View.GONE)
166 | {
167 | continue;
168 | }
169 |
170 | MarginLayoutParams lp = (MarginLayoutParams) child
171 | .getLayoutParams();
172 |
173 | int lc = left + lp.leftMargin;
174 | int tc = top + lp.topMargin;
175 | int rc = lc + child.getMeasuredWidth();
176 | int bc = tc + child.getMeasuredHeight();
177 |
178 | // 为子View进行布局
179 | child.layout(lc, tc, rc, bc);
180 |
181 | left += child.getMeasuredWidth() + lp.leftMargin
182 | + lp.rightMargin;
183 | }
184 |
185 | left = getPaddingLeft() ;
186 | top += lineHeight ;
187 | }
188 | }
189 |
190 | /**
191 | * 与当前ViewGroup对应的LayoutParams
192 | */
193 | @Override
194 | public LayoutParams generateLayoutParams(AttributeSet attrs)
195 | {
196 | return new MarginLayoutParams(getContext(), attrs);
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/widget/SearchLayout.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.graphics.drawable.ColorDrawable;
7 | import android.support.annotation.Nullable;
8 | import android.text.Editable;
9 | import android.text.TextWatcher;
10 | import android.util.AttributeSet;
11 | import android.util.Log;
12 | import android.view.KeyEvent;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.inputmethod.EditorInfo;
16 | import android.widget.AdapterView;
17 | import android.widget.Button;
18 | import android.widget.EditText;
19 | import android.widget.ImageView;
20 | import android.widget.LinearLayout;
21 | import android.widget.TextView;
22 |
23 | import com.tangguna.searchbox.library.R;
24 | import com.tangguna.searchbox.library.adapter.HistoryDataAdapter;
25 | import com.tangguna.searchbox.library.callback.onSearchCallBackListener;
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 | import java.util.Random;
30 |
31 | /**
32 | * 搜索框 GridView
33 | */
34 | public class SearchLayout extends LinearLayout {
35 |
36 | private String msearch_hint;
37 | private int msearch_baground;
38 | private Context context;
39 | private ImageView ib_searchtext_delete;
40 | private EditText et_searchtext_search;
41 | private LinearLayout searchview;
42 | private Button bt_text_search_back;
43 | private TextView tvclearolddata;
44 | //历史搜索
45 | private SelfSearchGridView gridViewData;
46 | private HistoryDataAdapter historyDataAdapter;
47 | private ArrayList historyList = new ArrayList<>();
48 | //热门搜索
49 | FlowLayout hotflowLayout;
50 |
51 | private String backtitle="取消",searchtitle="搜索";
52 | private OnClickListener TextViewItemListener;
53 | private int countOldDataSize=15;//默认搜索记录的条数, 正确的是传入进来的条数
54 |
55 | public SearchLayout(Context context) {
56 | super(context);
57 | this.context = context;
58 | initView();
59 | }
60 |
61 | public SearchLayout(Context context, @Nullable AttributeSet attrs) {
62 | super(context, attrs);
63 | this.context = context;
64 |
65 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.searchmlist);
66 | msearch_hint = array.getString(R.styleable.searchmlist_search_hint);
67 | msearch_baground = array.getResourceId(R.styleable.searchmlist_search_baground,R.drawable.search_baground_shap);
68 | array.recycle();
69 | initView();
70 | }
71 |
72 | public SearchLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
73 | super(context, attrs, defStyleAttr);
74 | this.context = context;
75 | initView();
76 | }
77 |
78 | private void initView() {
79 |
80 | backtitle=getResources().getString(R.string.search_cancel);
81 | searchtitle=getResources().getString(R.string.search_verify);
82 | searchview =(LinearLayout) LayoutInflater.from(context).inflate(R.layout.msearchlayout, null);
83 | //把获得的view加载到这个控件中
84 | addView(searchview);
85 | //把两个按钮从布局文件中找到
86 | ib_searchtext_delete = (ImageView) searchview.findViewById(R.id.ib_searchtext_delete);
87 | et_searchtext_search = (EditText) searchview.findViewById(R.id.et_searchtext_search);
88 | et_searchtext_search.setBackgroundResource(msearch_baground);
89 | et_searchtext_search.setHint(msearch_hint);
90 | //搜索返回时一个按钮
91 | bt_text_search_back = (Button) searchview.findViewById(R.id.buttonback);
92 | //清除历史记录
93 | tvclearolddata = (TextView) searchview.findViewById(R.id.tvclearolddata);
94 |
95 | gridViewData= (SelfSearchGridView)searchview.findViewById(R.id.gridviewolddata);
96 | gridViewData.setSelector(new ColorDrawable(Color.TRANSPARENT));//去除背景点击效果
97 |
98 | hotflowLayout = (FlowLayout)searchview.findViewById(R.id.id_flowlayouthot);
99 | setLinstener();
100 | }
101 |
102 | //文本观察者
103 | private class MyTextWatcher implements TextWatcher {
104 |
105 | @Override
106 | public void afterTextChanged(Editable s) {
107 |
108 | }
109 |
110 | @Override
111 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
112 | et_searchtext_search.setCursorVisible(true);
113 | et_searchtext_search.setSelection(et_searchtext_search.getText().toString().length());
114 | }
115 | //当文本改变时候的操作
116 | @Override
117 | public void onTextChanged(CharSequence s, int start, int before, int count) {
118 | //如果编辑框中文本的长度大于0就显示删除按钮否则不显示
119 | if(s.length() > 0){
120 | ib_searchtext_delete.setVisibility(View.VISIBLE);
121 | bt_text_search_back.setText(searchtitle);
122 | }else{
123 | ib_searchtext_delete.setVisibility(View.GONE);
124 | bt_text_search_back.setText(backtitle);
125 | }
126 | }
127 |
128 | }
129 |
130 | private void setLinstener() {
131 | //给删除按钮添加点击事件
132 | ib_searchtext_delete.setOnClickListener(new OnClickListener() {
133 | @Override
134 | public void onClick(View v) {
135 | // TODO Auto-generated method stub
136 | et_searchtext_search.setText("");
137 | }
138 | });
139 | //给编辑框添加文本改变事件
140 | et_searchtext_search.addTextChangedListener(new MyTextWatcher());
141 |
142 | et_searchtext_search.setOnEditorActionListener(new TextView.OnEditorActionListener() {
143 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
144 | if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
145 |
146 | String searchtext = et_searchtext_search.getText().toString().trim();
147 | //dosoming
148 | // Toast.makeText(context, "搜索" +searchtext, Toast.LENGTH_SHORT).show();
149 | executeSearch_and_NotifyDataSetChanged(searchtext);
150 | return true;
151 | }
152 | return false;
153 | }
154 | });
155 |
156 |
157 |
158 | bt_text_search_back.setOnClickListener(new OnClickListener() {
159 | @Override
160 | public void onClick(View v) {
161 | String searchtext = et_searchtext_search.getText().toString().trim();
162 | if (bt_text_search_back.getText().toString().equals(searchtitle)) {
163 | // Toast.makeText(context, "点击button搜索" + searchtext, Toast.LENGTH_SHORT).show();
164 | executeSearch_and_NotifyDataSetChanged(searchtext);
165 | } else {
166 | // Toast.makeText(context, "点击button 返回", Toast.LENGTH_SHORT).show();
167 | if (sCBlistener != null)
168 | sCBlistener.Back();
169 | }
170 | }
171 | });
172 |
173 |
174 |
175 | tvclearolddata.setOnClickListener(new OnClickListener() {
176 | @Override
177 | public void onClick(View v) {
178 | if(sCBlistener!=null) {
179 | historyList.clear();
180 | historyDataAdapter.notifyDataSetChanged();
181 | sCBlistener.ClearOldData();
182 | }
183 | }
184 | });
185 |
186 |
187 | TextViewItemListener = new OnClickListener(){
188 | @Override
189 | public void onClick(View v) {
190 | String string = ((TextView)v).getText().toString();
191 | // Toast.makeText(context, "Item点击"+string, Toast.LENGTH_SHORT).show();
192 | executeSearch_and_NotifyDataSetChanged(string);
193 |
194 | }
195 | };
196 |
197 | gridViewData.setOnItemClickListener(new AdapterView.OnItemClickListener() {
198 | @Override
199 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
200 | if(sCBlistener!=null){
201 | sCBlistener.Search(historyList.get(position).trim());
202 | et_searchtext_search.setText(historyList.get(position).trim());
203 | et_searchtext_search.setCursorVisible(false);
204 | et_searchtext_search.setSelection(et_searchtext_search.getText().toString().length());
205 | //点击项移动到首部位
206 | swap(historyList,position,0);
207 | historyDataAdapter.notifyDataSetChanged();
208 | }
209 | }
210 | });
211 |
212 | }
213 |
214 |
215 | /**
216 | *
217 | * @param olddatalist 历史搜索数据集合
218 | * @param hotdata 热门搜索数据集合
219 | * @param sCb 事件处理监听
220 | * @param styleId 热门搜索样式(值在1到5之间) 可以在drawable下修改、添加 sousuo_bg_gray_X等样式背景
221 | */
222 | public void initData(@Nullable List olddatalist,@Nullable List hotdata, onSearchCallBackListener sCb,int styleId){
223 | SetCallBackListener(sCb);
224 | hotflowLayout.removeAllViews();
225 | historyList.clear();
226 | if(olddatalist!=null)
227 | historyList.addAll(olddatalist);
228 | historyDataAdapter = new HistoryDataAdapter(context,historyList);
229 | gridViewData.setAdapter(historyDataAdapter);
230 |
231 |
232 | LayoutInflater mInflater = LayoutInflater.from(context);
233 | if (hotdata != null){
234 | for (int i = 0; i < hotdata.size(); i++)
235 | {
236 | TextView tv = (TextView) mInflater.inflate(R.layout.suosou_item,hotflowLayout, false);
237 | tv.setText(hotdata.get(i));
238 | tv.setOnClickListener(TextViewItemListener);
239 | tv.getBackground().setLevel(MyRandom(1,styleId));
240 | hotflowLayout.addView(tv);
241 | }
242 | }else {
243 | return;
244 | }
245 | }
246 |
247 |
248 |
249 | private void executeSearch_and_NotifyDataSetChanged(String str){
250 | if(sCBlistener!=null&&(!str.equals(""))){
251 | if (historyList.size() > 0 && historyList.get(0).equals(str)) {
252 | }
253 | else
254 | {
255 | if (historyList.size() == countOldDataSize && historyList.size()>0)
256 | historyList.remove(historyList.size() - 1);
257 | //判断字符串是否在历史记录中 如果在就不添加,反之则添加
258 | if (historyList != null && !historyList.contains(str))
259 | {
260 | historyList.add(0, str);//把最新的添加到前面
261 | historyDataAdapter.notifyDataSetChanged();
262 | sCBlistener.SaveOldData(historyList);
263 | }else {
264 | historyList.remove(str);
265 | historyList.add(0, str);//把最新的添加到前面
266 | historyDataAdapter.notifyDataSetChanged();
267 | sCBlistener.SaveOldData(historyList);
268 | }
269 | }
270 | et_searchtext_search.setText(str);
271 | sCBlistener.Search(str);
272 | et_searchtext_search.setCursorVisible(false);
273 | et_searchtext_search.setSelection(et_searchtext_search.getText().toString().length());
274 | }
275 | }
276 |
277 |
278 |
279 |
280 | /**
281 | * 生成随机数
282 | * @param max 最大值
283 | * @param min 最小值
284 | * @return
285 | */
286 | public int MyRandom(int min,int max){
287 | Random random = new Random();
288 | int s = random.nextInt(max)%(max-min+1) + min;
289 | return s;
290 | }
291 |
292 | private onSearchCallBackListener sCBlistener;
293 | /**
294 | * 设置接口回调
295 | * @param onSearchCallBackListener setCallBackListener接口
296 | */
297 | private void SetCallBackListener(onSearchCallBackListener onSearchCallBackListener){
298 | sCBlistener=onSearchCallBackListener;
299 | }
300 |
301 |
302 | /**
303 | * 调换集合中两个指定位置的元素, 若两个元素位置中间还有其他元素,需要实现中间元素的前移或后移的操作。
304 | * @param list 集合
305 | * @param oldPosition 需要调换的元素
306 | * @param newPosition 被调换的元素
307 | * @param
308 | */
309 | public static void swap(List list, int oldPosition, int newPosition){
310 | if(null == list){
311 | throw new IllegalStateException("集合不能为空");
312 | }
313 | T tempElement = list.get(oldPosition);
314 |
315 | // 向前移动,前面的元素需要向后移动
316 | if(oldPosition < newPosition){
317 | for(int i = oldPosition; i < newPosition; i++){
318 | list.set(i, list.get(i + 1));
319 | }
320 | list.set(newPosition, tempElement);
321 | }
322 | // 向后移动,后面的元素需要向前移动
323 | if(oldPosition > newPosition){
324 | for(int i = oldPosition; i > newPosition; i--){
325 | list.set(i, list.get(i - 1));
326 | }
327 | list.set(newPosition, tempElement);
328 | }
329 | }
330 | }
331 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/widget/SearchListLayout.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.graphics.drawable.ColorDrawable;
7 | import android.support.annotation.Nullable;
8 | import android.text.Editable;
9 | import android.text.TextWatcher;
10 | import android.util.AttributeSet;
11 | import android.view.KeyEvent;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.inputmethod.EditorInfo;
15 | import android.widget.AdapterView;
16 | import android.widget.Button;
17 | import android.widget.EditText;
18 | import android.widget.ImageView;
19 | import android.widget.LinearLayout;
20 | import android.widget.TextView;
21 |
22 | import com.tangguna.searchbox.library.R;
23 | import com.tangguna.searchbox.library.adapter.HistoryDataAdapter;
24 | import com.tangguna.searchbox.library.adapter.HistoryDataListViewAdapter;
25 | import com.tangguna.searchbox.library.cache.HistoryCache;
26 | import com.tangguna.searchbox.library.callback.onSearchCallBackListener;
27 |
28 | import java.util.ArrayList;
29 | import java.util.List;
30 | import java.util.Random;
31 |
32 | /**
33 | * 搜索框ListView
34 | */
35 | public class SearchListLayout extends LinearLayout {
36 | private String msearch_hint;
37 | private int msearch_baground;
38 | private Context context;
39 | private ImageView ib_searchtext_delete;
40 | private EditText et_searchtext_search;
41 | private LinearLayout searchview;
42 | private LinearLayout ll_clear;
43 | private Button bt_text_search_back;
44 | private TextView tvclearolddata;
45 | //历史搜索
46 | private SelfSearchListView gridViewData;
47 | private HistoryDataListViewAdapter historyDataAdapter;
48 | private ArrayList historyList = new ArrayList<>();
49 | //热门搜索
50 | FlowLayout hotflowLayout;
51 |
52 | private String backtitle="取消",searchtitle="搜索";
53 | private View.OnClickListener TextViewItemListener;
54 | private int countOldDataSize=15;//默认搜索记录的条数, 正确的是传入进来的条数
55 |
56 | public SearchListLayout(Context context) {
57 | super(context);
58 | this.context = context;
59 | initView();
60 | }
61 |
62 | public SearchListLayout(Context context, @Nullable AttributeSet attrs) {
63 | super(context, attrs);
64 | this.context = context;
65 |
66 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.searchmlist);
67 | msearch_hint = array.getString(R.styleable.searchmlist_search_hint);
68 | msearch_baground = array.getResourceId(R.styleable.searchmlist_search_baground,R.drawable.search_baground_shap);
69 | array.recycle();
70 | initView();
71 | }
72 |
73 | public SearchListLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
74 | super(context, attrs, defStyleAttr);
75 | this.context = context;
76 | initView();
77 | }
78 |
79 | private void initView() {
80 | backtitle=getResources().getString(R.string.search_cancel);
81 | searchtitle=getResources().getString(R.string.search_verify);
82 | searchview =(LinearLayout) LayoutInflater.from(context).inflate(R.layout.searchlistlayout, null);
83 | //把获得的view加载到这个控件中
84 | addView(searchview);
85 | //把两个按钮从布局文件中找到
86 | ib_searchtext_delete = (ImageView) searchview.findViewById(R.id.ib_searchtext_delete);
87 | et_searchtext_search = (EditText) searchview.findViewById(R.id.et_searchtext_search);
88 | et_searchtext_search.setBackgroundResource(msearch_baground);
89 | et_searchtext_search.setHint(msearch_hint);
90 | //搜索返回时一个按钮
91 | bt_text_search_back = (Button) searchview.findViewById(R.id.buttonback);
92 | //清除历史记录
93 | tvclearolddata = (TextView) searchview.findViewById(R.id.tvclearolddata);
94 | //清空搜索记录
95 | ll_clear = (LinearLayout) findViewById(R.id.ll_clear);
96 | gridViewData= (SelfSearchListView) searchview.findViewById(R.id.gridviewolddata);
97 | gridViewData.setSelector(new ColorDrawable(Color.TRANSPARENT));//去除背景点击效果
98 |
99 | hotflowLayout = (FlowLayout)searchview.findViewById(R.id.id_flowlayouthot);
100 | setLinstener();
101 | }
102 |
103 | //文本观察者
104 | private class MyTextWatcher implements TextWatcher {
105 |
106 | @Override
107 | public void afterTextChanged(Editable s) {
108 |
109 | }
110 |
111 | @Override
112 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
113 | et_searchtext_search.setCursorVisible(true);
114 | et_searchtext_search.setSelection(et_searchtext_search.getText().toString().length());
115 | }
116 | //当文本改变时候的操作
117 | @Override
118 | public void onTextChanged(CharSequence s, int start, int before, int count) {
119 | //如果编辑框中文本的长度大于0就显示删除按钮否则不显示
120 | if(s.length() > 0){
121 | ib_searchtext_delete.setVisibility(View.VISIBLE);
122 | bt_text_search_back.setText(searchtitle);
123 | }else{
124 | ib_searchtext_delete.setVisibility(View.GONE);
125 | bt_text_search_back.setText(backtitle);
126 | }
127 | }
128 |
129 | }
130 |
131 | private void setLinstener() {
132 | /**
133 | * 清空历史记录
134 | */
135 | ll_clear.setOnClickListener(new OnClickListener() {
136 | @Override
137 | public void onClick(View view) {
138 | if(sCBlistener!=null) {
139 | historyList.clear();
140 | historyDataAdapter.notifyDataSetChanged();
141 | sCBlistener.ClearOldData();
142 | }
143 | ll_clear.setVisibility(GONE);
144 | }
145 | });
146 | //给删除按钮添加点击事件
147 | ib_searchtext_delete.setOnClickListener(new View.OnClickListener() {
148 | @Override
149 | public void onClick(View v) {
150 | // TODO Auto-generated method stub
151 | et_searchtext_search.setText("");
152 | }
153 | });
154 | //给编辑框添加文本改变事件
155 | et_searchtext_search.addTextChangedListener(new MyTextWatcher());
156 |
157 | et_searchtext_search.setOnEditorActionListener(new TextView.OnEditorActionListener() {
158 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
159 | if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
160 |
161 | String searchtext = et_searchtext_search.getText().toString().trim();
162 | //dosoming
163 | // Toast.makeText(context, "搜索" +searchtext, Toast.LENGTH_SHORT).show();
164 | executeSearch_and_NotifyDataSetChanged(searchtext);
165 | return true;
166 | }
167 | return false;
168 | }
169 | });
170 |
171 |
172 |
173 | bt_text_search_back.setOnClickListener(new View.OnClickListener() {
174 | @Override
175 | public void onClick(View v) {
176 | String searchtext = et_searchtext_search.getText().toString().trim();
177 | if (bt_text_search_back.getText().toString().equals(searchtitle)) {
178 | // Toast.makeText(context, "点击button搜索" + searchtext, Toast.LENGTH_SHORT).show();
179 | executeSearch_and_NotifyDataSetChanged(searchtext);
180 | } else {
181 | // Toast.makeText(context, "点击button 返回", Toast.LENGTH_SHORT).show();
182 | if (sCBlistener != null)
183 | sCBlistener.Back();
184 | }
185 | }
186 | });
187 |
188 |
189 |
190 | tvclearolddata.setOnClickListener(new View.OnClickListener() {
191 | @Override
192 | public void onClick(View v) {
193 | if(sCBlistener!=null) {
194 | historyList.clear();
195 | historyDataAdapter.notifyDataSetChanged();
196 | sCBlistener.ClearOldData();
197 | }
198 | }
199 | });
200 |
201 |
202 | TextViewItemListener = new View.OnClickListener(){
203 | @Override
204 | public void onClick(View v) {
205 | String string = ((TextView)v).getText().toString();
206 | // Toast.makeText(context, "Item点击"+string, Toast.LENGTH_SHORT).show();
207 | executeSearch_and_NotifyDataSetChanged(string);
208 |
209 | }
210 | };
211 |
212 | gridViewData.setOnItemClickListener(new AdapterView.OnItemClickListener() {
213 | @Override
214 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
215 | if(sCBlistener!=null){
216 | sCBlistener.Search(historyList.get(position).trim());
217 | et_searchtext_search.setText(historyList.get(position).trim());
218 | et_searchtext_search.setCursorVisible(false);
219 | et_searchtext_search.setSelection(et_searchtext_search.getText().toString().length());
220 | //点击项移动到首部位
221 | swap(historyList,position,0);
222 | historyDataAdapter.notifyDataSetChanged();
223 | }
224 | }
225 | });
226 |
227 | }
228 |
229 |
230 | /**
231 | *
232 | * @param olddatalist 历史搜索数据集合
233 | * @param hotdata 热门搜索数据集合
234 | * @param sCb 事件处理监听
235 | * @param styleId 热门搜索样式(值在1到5之间) 可以在drawable下修改、添加 sousuo_bg_gray_X等样式背景
236 | */
237 | public void initData(@Nullable List olddatalist, @Nullable List hotdata, onSearchCallBackListener sCb, int styleId){
238 | SetCallBackListener(sCb);
239 | hotflowLayout.removeAllViews();
240 | historyList.clear();
241 | if(olddatalist!=null)
242 | historyList.addAll(olddatalist);
243 | ll_clear.setVisibility(VISIBLE);
244 | historyDataAdapter = new HistoryDataListViewAdapter(context,historyList);
245 | gridViewData.setAdapter(historyDataAdapter);
246 |
247 |
248 | LayoutInflater mInflater = LayoutInflater.from(context);
249 | if (hotdata != null){
250 | for (int i = 0; i < hotdata.size(); i++)
251 | {
252 | TextView tv = (TextView) mInflater.inflate(R.layout.suosou_item,hotflowLayout, false);
253 | tv.setText(hotdata.get(i));
254 | tv.setOnClickListener(TextViewItemListener);
255 | tv.getBackground().setLevel(MyRandom(1,styleId));
256 | hotflowLayout.addView(tv);
257 | }
258 | }else {
259 | return;
260 | }
261 | }
262 |
263 |
264 |
265 | private void executeSearch_and_NotifyDataSetChanged(String str){
266 | if(sCBlistener!=null&&(!str.equals(""))){
267 | if (historyList.size() > 0 && historyList.get(0).equals(str)) {
268 | ll_clear.setVisibility(VISIBLE);
269 | }
270 | else
271 | {
272 | if (historyList.size() == countOldDataSize && historyList.size()>0)
273 | historyList.remove(historyList.size() - 1);
274 | //判断字符串是否在历史记录中 如果在就不添加,反之则添加
275 | if (historyList != null && !historyList.contains(str))
276 | {
277 | historyList.add(0, str);//把最新的添加到前面
278 | historyDataAdapter.notifyDataSetChanged();
279 | sCBlistener.SaveOldData(historyList);
280 | }else {
281 | historyList.remove(str);
282 | historyList.add(0, str);//把最新的添加到前面
283 | historyDataAdapter.notifyDataSetChanged();
284 | sCBlistener.SaveOldData(historyList);
285 | }
286 | }
287 | ll_clear.setVisibility(VISIBLE);
288 | et_searchtext_search.setText(str);
289 | sCBlistener.Search(str);
290 | et_searchtext_search.setCursorVisible(false);
291 | et_searchtext_search.setSelection(et_searchtext_search.getText().toString().length());
292 | }
293 | }
294 |
295 |
296 |
297 |
298 | /**
299 | * 生成随机数
300 | * @param max 最大值
301 | * @param min 最小值
302 | * @return
303 | */
304 | public int MyRandom(int min,int max){
305 | Random random = new Random();
306 | int s = random.nextInt(max)%(max-min+1) + min;
307 | return s;
308 | }
309 |
310 | private onSearchCallBackListener sCBlistener;
311 | /**
312 | * 设置接口回调
313 | * @param onSearchCallBackListener setCallBackListener接口
314 | */
315 | private void SetCallBackListener(onSearchCallBackListener onSearchCallBackListener){
316 | sCBlistener=onSearchCallBackListener;
317 | }
318 |
319 |
320 | /**
321 | * 调换集合中两个指定位置的元素, 若两个元素位置中间还有其他元素,需要实现中间元素的前移或后移的操作。
322 | * @param list 集合
323 | * @param oldPosition 需要调换的元素
324 | * @param newPosition 被调换的元素
325 | * @param
326 | */
327 | public static void swap(List list, int oldPosition, int newPosition){
328 | if(null == list){
329 | throw new IllegalStateException("集合不能为空");
330 | }
331 | T tempElement = list.get(oldPosition);
332 |
333 | // 向前移动,前面的元素需要向后移动
334 | if(oldPosition < newPosition){
335 | for(int i = oldPosition; i < newPosition; i++){
336 | list.set(i, list.get(i + 1));
337 | }
338 | list.set(newPosition, tempElement);
339 | }
340 | // 向后移动,后面的元素需要向前移动
341 | if(oldPosition > newPosition){
342 | for(int i = oldPosition; i > newPosition; i--){
343 | list.set(i, list.get(i - 1));
344 | }
345 | list.set(newPosition, tempElement);
346 | }
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/widget/SelfSearchGridView.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.ViewGroup;
6 | import android.widget.GridView;
7 |
8 | public class SelfSearchGridView extends GridView {
9 |
10 | public SelfSearchGridView(Context context) {
11 | super(context);
12 | }
13 |
14 | public SelfSearchGridView(Context context, AttributeSet attrs) {
15 | super(context, attrs);
16 | }
17 |
18 |
19 | public SelfSearchGridView(Context context, AttributeSet attrs, int defStyleAttr) {
20 | super(context, attrs, defStyleAttr);
21 | }
22 |
23 | @Override
24 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
25 |
26 | int heightSpec;
27 | if(getLayoutParams().height== ViewGroup.LayoutParams.WRAP_CONTENT)
28 | {
29 | heightSpec = MeasureSpec.makeMeasureSpec(
30 | Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
31 | //Integer.MAX_VALUE >> 2 == 2的31次方-1 表示的int的最大值
32 | }
33 | else {
34 | // Any other height should be respected as is.
35 | heightSpec = heightMeasureSpec;
36 | }
37 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/library/src/main/java/com/tangguna/searchbox/library/widget/SelfSearchListView.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.ViewGroup;
6 | import android.widget.ListView;
7 |
8 | public class SelfSearchListView extends ListView {
9 |
10 | public SelfSearchListView(Context context) {
11 | super(context);
12 | }
13 |
14 | public SelfSearchListView(Context context, AttributeSet attrs) {
15 | super(context, attrs);
16 | }
17 |
18 | public SelfSearchListView(Context context, AttributeSet attrs, int defStyleAttr) {
19 | super(context, attrs, defStyleAttr);
20 | }
21 |
22 | @Override
23 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
24 |
25 | int heightSpec;
26 | if(getLayoutParams().height== ViewGroup.LayoutParams.WRAP_CONTENT)
27 | {
28 | heightSpec = MeasureSpec.makeMeasureSpec(
29 | Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
30 | //Integer.MAX_VALUE >> 2 == 2的31次方-1 表示的int的最大值
31 | }
32 | else {
33 | // Any other height should be respected as is.
34 | heightSpec = heightMeasureSpec;
35 | }
36 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/explore_search_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/library/src/main/res/drawable-xhdpi/explore_search_close.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/explore_search_close_nt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/library/src/main/res/drawable-xhdpi/explore_search_close_nt.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/explore_search_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/library/src/main/res/drawable-xhdpi/explore_search_icon.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/explore_search_icon_nt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/library/src/main/res/drawable-xhdpi/explore_search_icon_nt.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/icon_clear_data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/library/src/main/res/drawable-xhdpi/icon_clear_data.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable-xhdpi/icon_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangguna/SearchBox/42d5a5a93115841e7f9f79e78ba0f6b5bba283e9/library/src/main/res/drawable-xhdpi/icon_close.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable/bg_shadow_set_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/ll_clear_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/search.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
7 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 | -
21 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/search_baground_shap.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/search_title_baground_shap.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/search_title_baground_shap2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
19 |
20 |
21 |
22 |
23 |
34 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_back_or_search_button_shap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
7 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 | -
21 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_gray_1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 | -
10 |
11 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_gray_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 | -
10 |
11 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_gray_3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 | -
10 |
11 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_gray_4.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 | -
10 |
11 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_gray_5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
8 |
9 | -
10 |
11 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_gray_state_pressed_shap.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_bg_level.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/sousuo_clearolddata_shap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
7 |
8 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 | -
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/msearch_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 |
28 |
38 |
39 |
40 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/msearchlayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
18 |
19 |
20 |
25 |
32 |
36 |
41 |
42 |
43 |
46 |
55 |
67 |
68 |
72 |
76 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/search_olddata_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/searchlistlayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
18 |
19 |
20 |
26 |
33 |
37 |
42 |
43 |
44 |
47 |
56 |
68 |
69 |
73 |
77 |
83 |
84 |
85 |
86 |
96 |
101 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/suosou_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/library/src/main/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ff145f8f
4 | #c2979797
5 | #00000000
6 | #ff828282
7 | #353232
8 |
9 |
10 |
11 | #d6d6d6
12 |
13 | #f2f2f2
14 | #cacaca
15 | #f2f6e9
16 | #b8ce8e
17 | #e8f6f6
18 | #92dbde
19 | #f9eaeb
20 | #fba1a8
21 | #f8f2ec
22 | #f9c189
23 |
24 |
25 |
26 |
27 |
28 | #f34336
29 | #e81f63
30 | #374046
31 | #9c28af
32 | #673ab6
33 | #3f51b4
34 | #2296f2
35 | #04a9f3
36 | #02bcd4
37 | #029789
38 | #4cae50
39 | #8bc24a
40 | #cddc3a
41 | #ffeb3c
42 | #ffc109
43 | #fe9802
44 | #fe5723
45 | #795548
46 | #9f9f9f
47 | #607d8b
48 |
49 |
50 |
51 | #ffea4f15
52 | #ff9c00
53 | #ff987b
54 | #00ff00
55 | #00ffff
56 | #0000ff
57 | #ff85c5
58 |
59 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SearchmList
3 | 热门搜索
4 | 取消
5 | 搜索
6 | 热门搜索
7 | 历史搜索
8 | 清除历史
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/library/src/main/res/values/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/test/java/com/tangguna/searchbox/library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.tangguna.searchbox.library;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------