├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── fj │ │ └── hoverdropdownmenu │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── fj │ │ │ └── hoverdropdownmenu │ │ │ └── demo │ │ │ ├── MainActivity.java │ │ │ ├── bean │ │ │ ├── DropdownItemObject.java │ │ │ ├── TopicLabelObject.java │ │ │ └── TopicObject.java │ │ │ └── view │ │ │ ├── DividerItemDecoration.java │ │ │ ├── DropdownButton.java │ │ │ ├── DropdownListItemView.java │ │ │ └── DropdownListView.java │ └── res │ │ ├── anim │ │ ├── dropdown_in.xml │ │ ├── dropdown_mask_out.xml │ │ └── dropdown_out.xml │ │ ├── drawable-xhdpi │ │ ├── back.png │ │ ├── button_retry.xml │ │ ├── ic_btn_retry_normal.png │ │ ├── ic_btn_retry_press.png │ │ ├── ic_clock.png │ │ ├── ic_dropdown_actived.png │ │ ├── ic_dropdown_normal.png │ │ ├── ic_exception_no_network.png │ │ ├── ic_task_comment.png │ │ ├── ic_task_status_list_check.png │ │ ├── image.png │ │ └── list_item_selector.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── dropdown_tab_button.xml │ │ ├── dropdown_tab_list.xml │ │ ├── dropdown_tab_list_divider.xml │ │ ├── dropdown_tab_list_item.xml │ │ └── item_demo.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── fj │ └── hoverdropdownmenu │ └── demo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 栗子——嵌套组合实现筛选菜单滑动吸顶悬停 2 | 3 | --- 4 | 5 | > ### 栗子惯例,先上GIF 6 | 7 | ![栗子.gif](http://upload-images.jianshu.io/upload_images/2071764-e6ff8674caec4bba.gif) 8 | 9 | --- 10 | 11 | 好了,现在来说下这个栗子了,在以往实现这种效果是很麻烦的,现在就不同了,自从新特性控件出来后,各种happy,可以轻松实现各种炫酷效果! 12 | 13 | --- 14 | 15 | > ### 使用到的控件 16 | 17 | 使用前需要在Gradle加入Support Design Library: 18 | **compile 'com.android.support:design:25.0.1'** 19 | 20 | #### CoordinatorLayout 21 | `CoordinatorLayout`通过协调子布局的形式,产生联动效果。通过设置子View的Behaviors来协调子View。 22 | 23 | #### AppBarLayout 24 | `AppBarLayout`中的一个属性`android:fitsSystemWindows="true"`,是为了调整系统窗口布局以适应布局。 25 | `AppBarLayout`里面的View,是通过`app:layout_scrollFlags`属性来控制,其中有4种Flag的类型: 26 | 27 | - `Scroll`:向下滚动时,被指定了这个属性的View会被滚出屏幕范围直到完全不可见的位置。 28 | - `enterAlways`:向上滚动时,这个View会随着滚动手势出现,直到恢复原来的位置。 29 | - `enterAlwaysCollapsed`: 当视图已经设置minHeight属性又使用此标志时,视图只能以最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。 30 | - `exitUntilCollapsed`: 滚动退出屏幕,最后折叠在顶端。 31 | 32 | #### CollapsingToolbarLayout 33 | 用来协调`AppBarLayout`来实现滚动隐藏`ToolBar`的效果。 34 | 35 | #### Toolbar 36 | Toolbar在v7包中,设置`layout_collapseMode`协调`CollapsingToolbarLayout`达到滑动视图的视觉差效果: 37 | 38 | - `pin`:固定模式,在折叠的时候最后固定在顶端。 39 | - `parallax`:视差模式,在折叠的时候会有个视差折叠的效果。 40 | 41 | --- 42 | 43 | > ### main.xml 44 | ``` 45 | 46 | 51 | 56 | 64 | 71 | 75 | 76 | 87 | 88 | 93 | 98 | 103 | 107 | 112 | 113 | 117 | 118 | 119 | 123 | 127 | 132 | 137 | 142 | 147 | 148 | 149 | 150 | ``` 151 | 152 | --- 153 | 154 | 155 | **分析说明:** 156 | 1. 最外层是由一个`CoordinatorLayout`嵌套 157 | 2. 内层是由`AppBarLayout`和`FrameLayout`组成 158 | 3. `AppBarLayout`里的view是通过`layout_scrollFlags`来控制 159 | 4. `FrameLayout`里的view是通过`layout_behavior`来控制的,只要设置其`@string/appbar_scrolling_view_behavior`属性就ok了 160 | 5. `FrameLayout`里的布局是由`RecyclerView`和灰色透明的view,以及一组`DropdownListView`组成,这就是我选择这个筛选控件的原因,可以拆分出来独立的组件,而不是组合起来的一个新控件。 161 | 162 | --- 163 | 164 | **JAVA代码中都是些简单的数据绑定,及一些设置,具体的可以看代码,有问题的话可以联系我~** 165 | 166 | --- 167 | 168 | > ### 总结 169 | > 学会新控件的使用这是最基本的,然后实现一些炫酷的效果~ 170 | 171 | --- 172 | 173 | 参考如下,感谢作者: 174 | 参考:[过滤功能的下拉菜单FilterDropDownMenu](https://github.com/leerduo/FilterDropDownMenu) 175 | 176 | --- 177 | 178 | > **个人博客:[WWW.FJ917.COM](http://www.fj917.com)**
179 | > **简书:[www.jianshu.com/u/3d2770e6e489](http://www.jianshu.com/u/3d2770e6e489)**
180 | > **CSDN:[blog.csdn.net/fj917](http://blog.csdn.net/fj917)** 181 | 182 | 183 | |欢迎加入QQ交流群657206000[点我加入](http://shang.qq.com/wpa/qunwpa?idkey=9b454a6f01bd94d97e4c3f2771447a989ec77794eb5a563422263153c00f700d)| 184 | |:---:| 185 | |![QQ交流群:657206000](http://upload-images.jianshu.io/upload_images/2071764-bce605159bbceb2a.png)| -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "fj.hoverdropdownmenu.demo" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | repositories { 22 | flatDir { 23 | dirs 'libs' 24 | } 25 | maven { url "https://jitpack.io" } 26 | } 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 30 | exclude group: 'com.android.support', module: 'support-annotations' 31 | }) 32 | compile 'com.android.support:appcompat-v7:25.3.1' 33 | testCompile 'junit:junit:4.12' 34 | 35 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:v1.7.9' 36 | compile 'com.android.support:design:25.3.1' 37 | compile 'com.android.support:recyclerview-v7:25.3.1' 38 | } 39 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\android_studio\android_studio\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/fj/hoverdropdownmenu/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo; 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 | * Instrumentation 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() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("fj.hoverdropdownmenu.demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.design.widget.CollapsingToolbarLayout; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.view.View; 12 | import android.view.WindowManager; 13 | import android.view.animation.Animation; 14 | import android.view.animation.AnimationUtils; 15 | 16 | import com.chad.library.adapter.base.BaseQuickAdapter; 17 | import com.chad.library.adapter.base.BaseViewHolder; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import fj.hoverdropdownmenu.demo.bean.DropdownItemObject; 23 | import fj.hoverdropdownmenu.demo.view.DividerItemDecoration; 24 | import fj.hoverdropdownmenu.demo.view.DropdownButton; 25 | import fj.hoverdropdownmenu.demo.view.DropdownListView; 26 | 27 | /** 28 | * ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ 29 | * ┃ ╭﹉﹊﹉╮ ╔═════╗╔═════╗╔═════╗┃ 30 | * ┃╭╯老斯基㊣╠╣淡漠de人生╠╣2017-01-07╠╣ 欢迎关注 ╣┃ 31 | * ┃╰⊙┈┈┈⊙╯╚◎═══◎╝╚◎═══◎╝╚◎═══◎╝┃ 32 | * ┣━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┫ 33 | * ┃GitHub┃https://github.com/FJ917 ┃ 34 | * ┃简 书┃http://www.jianshu.com/users/3d2770e6e489 ┃ 35 | * ┃Q Q┃511334686 ┃ 36 | * ┗━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ 37 | */ 38 | public class MainActivity extends AppCompatActivity implements DropdownListView.Container { 39 | 40 | CollapsingToolbarLayout collapsingToolbar; 41 | DropdownButton chooseType; 42 | DropdownButton chooseLanguage; 43 | RecyclerView mRecyclerView; 44 | View mask; 45 | DropdownListView dropdownType; 46 | DropdownListView dropdownLanguage; 47 | 48 | private DropdownListView currentDropdownList; 49 | Animation dropdown_in, dropdown_out, dropdown_mask_out; 50 | 51 | private List chooseTypeData = new ArrayList<>();//选择类型 52 | private List chooseLanguageData = new ArrayList<>();//选择语言 53 | 54 | private List mData; 55 | private DemoAdapter mAdapter; 56 | @Override 57 | protected void onCreate(Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | setContentView(R.layout.activity_main); 60 | 61 | collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbar); 62 | chooseType = (DropdownButton) findViewById(R.id.chooseType); 63 | chooseLanguage = (DropdownButton) findViewById(R.id.chooseLanguage); 64 | mRecyclerView = (RecyclerView) findViewById(R.id.mRecyclerView); 65 | mask = findViewById(R.id.mask); 66 | dropdownType = (DropdownListView) findViewById(R.id.dropdownType); 67 | dropdownLanguage = (DropdownListView) findViewById(R.id.dropdownLanguage); 68 | dropdownLanguage = (DropdownListView) findViewById(R.id.dropdownLanguage); 69 | 70 | setTitle("淡漠de人生"); 71 | collapsingToolbar.setTitle("淡漠de人生"); 72 | collapsingToolbar.setExpandedTitleColor(Color.parseColor("#00ffffff"));//设置还没收缩时状态下字体颜色 73 | collapsingToolbar.setCollapsedTitleTextColor(Color.WHITE);//设置收缩后Toolbar上字体的 74 | 75 | dropdown_in = AnimationUtils.loadAnimation(this, R.anim.dropdown_in); 76 | dropdown_out = AnimationUtils.loadAnimation(this,R.anim.dropdown_out); 77 | dropdown_mask_out = AnimationUtils.loadAnimation(this,R.anim.dropdown_mask_out); 78 | init(); 79 | mask.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | hide(); 83 | } 84 | }); 85 | 86 | mData = new ArrayList<>(); 87 | for(int i=0; i<30;i++){ 88 | mData.add("标题"+i); 89 | } 90 | mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); 91 | mAdapter = new DemoAdapter(this, R.layout.item_demo, mData); 92 | initAdapter(); 93 | } 94 | 95 | @Override 96 | public void show(DropdownListView view) { 97 | if (currentDropdownList != null) { 98 | currentDropdownList.clearAnimation(); 99 | currentDropdownList.startAnimation(dropdown_out); 100 | currentDropdownList.setVisibility(View.GONE); 101 | currentDropdownList.button.setChecked(false); 102 | } 103 | currentDropdownList = view; 104 | mask.clearAnimation(); 105 | mask.setVisibility(View.VISIBLE); 106 | currentDropdownList.clearAnimation(); 107 | currentDropdownList.startAnimation(dropdown_in); 108 | currentDropdownList.setVisibility(View.VISIBLE); 109 | currentDropdownList.button.setChecked(true); 110 | } 111 | 112 | @Override 113 | public void hide() { 114 | if (currentDropdownList != null) { 115 | currentDropdownList.clearAnimation(); 116 | currentDropdownList.startAnimation(dropdown_out); 117 | currentDropdownList.button.setChecked(false); 118 | mask.clearAnimation(); 119 | mask.startAnimation(dropdown_mask_out); 120 | } 121 | currentDropdownList = null; 122 | } 123 | 124 | @Override 125 | public void onSelectionChanged(DropdownListView view) { 126 | if (view == dropdownType) { 127 | 128 | } 129 | } 130 | 131 | void reset() { 132 | chooseType.setChecked(false); 133 | chooseLanguage.setChecked(false); 134 | 135 | dropdownType.setVisibility(View.GONE); 136 | dropdownLanguage.setVisibility(View.GONE); 137 | mask.setVisibility(View.GONE); 138 | 139 | dropdownType.clearAnimation(); 140 | dropdownLanguage.clearAnimation(); 141 | mask.clearAnimation(); 142 | } 143 | 144 | void init() { 145 | reset(); 146 | chooseTypeData.add(new DropdownItemObject("全部分类", 0, "全部分类")); 147 | chooseTypeData.add(new DropdownItemObject("分类1", 1, "分类1")); 148 | chooseTypeData.add(new DropdownItemObject("分类2", 2, "分类2")); 149 | chooseTypeData.add(new DropdownItemObject("分类3", 3, "分类3")); 150 | chooseTypeData.add(new DropdownItemObject("分类4", 4, "分类4")); 151 | dropdownType.bind(chooseTypeData, chooseType, this, 0); 152 | 153 | chooseLanguageData.add(new DropdownItemObject("全部语言", 0, "全部语言")); 154 | chooseLanguageData.add(new DropdownItemObject("语言1", 1, "语言1")); 155 | chooseLanguageData.add(new DropdownItemObject("语言2", 2, "语言2")); 156 | chooseLanguageData.add(new DropdownItemObject("语言3", 3, "语言3")); 157 | chooseLanguageData.add(new DropdownItemObject("语言4", 4, "语言4")); 158 | dropdownLanguage.bind(chooseLanguageData, chooseLanguage, this, 0); 159 | 160 | dropdown_mask_out.setAnimationListener(new Animation.AnimationListener() { 161 | @Override 162 | public void onAnimationStart(Animation animation) { 163 | 164 | } 165 | 166 | @Override 167 | public void onAnimationEnd(Animation animation) { 168 | if (currentDropdownList == null) { 169 | reset(); 170 | } 171 | } 172 | 173 | @Override 174 | public void onAnimationRepeat(Animation animation) { 175 | 176 | } 177 | }); 178 | } 179 | 180 | /** 181 | * 设置RecyclerView属性 182 | */ 183 | private void initAdapter() { 184 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 185 | mAdapter.openLoadAnimation(); 186 | mRecyclerView.setAdapter(mAdapter);//设置adapter 187 | //设置item点击事件 188 | mAdapter.setOnRecyclerViewItemClickListener(new BaseQuickAdapter.OnRecyclerViewItemClickListener() { 189 | @Override 190 | public void onItemClick(View view, int position) { 191 | 192 | } 193 | }); 194 | } 195 | 196 | class DemoAdapter extends BaseQuickAdapter { 197 | int mLayoutId; 198 | public DemoAdapter(Context context, int LayoutId, List str) { 199 | super(context, LayoutId, str); 200 | mLayoutId = LayoutId; 201 | } 202 | 203 | @Override 204 | public void convert(BaseViewHolder helper, String str) { 205 | helper.setText(R.id.tvTitle,str); 206 | } 207 | } 208 | 209 | 210 | } 211 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/bean/DropdownItemObject.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.bean; 2 | 3 | public class DropdownItemObject { 4 | 5 | public int id; 6 | public String text; 7 | public String value; 8 | public String suffix; 9 | 10 | public DropdownItemObject(String text, int id, String value) { 11 | this.text = text; 12 | this.id = id; 13 | this.value = value; 14 | } 15 | 16 | public String getSuffix() { 17 | return suffix; 18 | } 19 | 20 | public void setSuffix(String suffix) { 21 | this.suffix = suffix; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/bean/TopicLabelObject.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.bean; 2 | 3 | public class TopicLabelObject { 4 | 5 | public int id; 6 | public int count; 7 | public String name; 8 | 9 | public TopicLabelObject(int id, int count, String name) { 10 | this.id = id; 11 | this.count = count; 12 | this.name = name; 13 | } 14 | 15 | public int getId() { 16 | return id; 17 | } 18 | 19 | public void setId(int id) { 20 | this.id = id; 21 | } 22 | 23 | public int getCount() { 24 | return count; 25 | } 26 | 27 | public void setCount(int count) { 28 | this.count = count; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/bean/TopicObject.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.bean; 2 | 3 | 4 | public class TopicObject { 5 | 6 | private int id; 7 | 8 | private int icon; 9 | 10 | private String desc; 11 | 12 | private String name; 13 | 14 | private String time; 15 | 16 | private int commentCount; 17 | 18 | public TopicLabelObject labels; 19 | 20 | 21 | public TopicObject(int icon, String desc, String name, String time, int commentCount, TopicLabelObject labels) { 22 | this.icon = icon; 23 | this.desc = desc; 24 | this.name = name; 25 | this.time = time; 26 | this.commentCount = commentCount; 27 | this.labels = labels; 28 | } 29 | 30 | public int getId() { 31 | return id; 32 | } 33 | 34 | public void setId(int id) { 35 | this.id = id; 36 | } 37 | 38 | public int getIcon() { 39 | return icon; 40 | } 41 | 42 | public void setIcon(int icon) { 43 | this.icon = icon; 44 | } 45 | 46 | public String getDesc() { 47 | return desc; 48 | } 49 | 50 | public void setDesc(String desc) { 51 | this.desc = desc; 52 | } 53 | 54 | public String getName() { 55 | return name; 56 | } 57 | 58 | public void setName(String name) { 59 | this.name = name; 60 | } 61 | 62 | public String getTime() { 63 | return time; 64 | } 65 | 66 | public void setTime(String time) { 67 | this.time = time; 68 | } 69 | 70 | public int getCommentCount() { 71 | return commentCount; 72 | } 73 | 74 | public void setCommentCount(int commentCount) { 75 | this.commentCount = commentCount; 76 | } 77 | 78 | public TopicLabelObject getLabels() { 79 | return labels; 80 | } 81 | 82 | public void setLabels(TopicLabelObject labels) { 83 | this.labels = labels; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/view/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.view; 2 | /* 3 | * Copyright (C) 2014 The Android Open Source Project 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * limitations under the License. 7 | */ 8 | 9 | import android.content.Context; 10 | import android.content.res.TypedArray; 11 | import android.graphics.Canvas; 12 | import android.graphics.Rect; 13 | import android.graphics.drawable.Drawable; 14 | import android.support.v7.widget.LinearLayoutManager; 15 | import android.support.v7.widget.RecyclerView; 16 | import android.view.View; 17 | 18 | 19 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 20 | 21 | private static final int[] ATTRS = new int[]{ 22 | android.R.attr.listDivider 23 | }; 24 | 25 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 26 | 27 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 28 | 29 | private Drawable mDivider; 30 | 31 | private int mOrientation; 32 | 33 | public DividerItemDecoration(Context context, int orientation) { 34 | final TypedArray a = context.obtainStyledAttributes(ATTRS); 35 | mDivider = a.getDrawable(0); 36 | a.recycle(); 37 | setOrientation(orientation); 38 | } 39 | 40 | public void setOrientation(int orientation) { 41 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 42 | throw new IllegalArgumentException("invalid orientation"); 43 | } 44 | mOrientation = orientation; 45 | } 46 | 47 | @Override 48 | public void onDraw(Canvas c, RecyclerView parent) { 49 | if (mOrientation == VERTICAL_LIST) { 50 | drawVertical(c, parent); 51 | } else { 52 | drawHorizontal(c, parent); 53 | } 54 | 55 | } 56 | 57 | 58 | public void drawVertical(Canvas c, RecyclerView parent) { 59 | final int left = parent.getPaddingLeft(); 60 | final int right = parent.getWidth() - parent.getPaddingRight(); 61 | 62 | final int childCount = parent.getChildCount(); 63 | for (int i = 0; i < childCount; i++) { 64 | final View child = parent.getChildAt(i); 65 | RecyclerView v = new RecyclerView(parent.getContext()); 66 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 67 | .getLayoutParams(); 68 | final int top = child.getBottom() + params.bottomMargin; 69 | final int bottom = top + mDivider.getIntrinsicHeight(); 70 | mDivider.setBounds(left, top, right, bottom); 71 | mDivider.draw(c); 72 | } 73 | } 74 | 75 | public void drawHorizontal(Canvas c, RecyclerView parent) { 76 | final int top = parent.getPaddingTop(); 77 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 78 | 79 | final int childCount = parent.getChildCount(); 80 | for (int i = 0; i < childCount; i++) { 81 | final View child = parent.getChildAt(i); 82 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 83 | .getLayoutParams(); 84 | final int left = child.getRight() + params.rightMargin; 85 | final int right = left + mDivider.getIntrinsicHeight(); 86 | mDivider.setBounds(left, top, right, bottom); 87 | mDivider.draw(c); 88 | } 89 | } 90 | 91 | @Override 92 | public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { 93 | if (mOrientation == VERTICAL_LIST) { 94 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); 95 | } else { 96 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/view/DropdownButton.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.widget.RelativeLayout; 9 | import android.widget.TextView; 10 | 11 | import fj.hoverdropdownmenu.demo.R; 12 | 13 | 14 | public class DropdownButton extends RelativeLayout { 15 | TextView textView; 16 | View bottomLine; 17 | 18 | public DropdownButton(Context context) { 19 | this(context, null); 20 | } 21 | 22 | public DropdownButton(Context context, AttributeSet attrs) { 23 | this(context, attrs, 0); 24 | } 25 | 26 | public DropdownButton(Context context, AttributeSet attrs, int defStyleAttr) { 27 | super(context, attrs, defStyleAttr); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | View view = LayoutInflater.from(getContext()).inflate(R.layout.dropdown_tab_button,this, true); 33 | textView = (TextView) view.findViewById(R.id.textView); 34 | bottomLine = view.findViewById(R.id.bottomLine); 35 | } 36 | 37 | 38 | public void setText(CharSequence text) { 39 | textView.setText(text); 40 | } 41 | 42 | public void setChecked(boolean checked) { 43 | Drawable icon; 44 | if (checked) { 45 | icon = getResources().getDrawable(R.drawable.ic_dropdown_actived); 46 | textView.setTextColor(getResources().getColor(R.color.green)); 47 | bottomLine.setVisibility(VISIBLE); 48 | } else { 49 | icon = getResources().getDrawable(R.drawable.ic_dropdown_normal); 50 | textView.setTextColor(getResources().getColor(R.color.font_black_content)); 51 | bottomLine.setVisibility(GONE); 52 | } 53 | textView.setCompoundDrawablesWithIntrinsicBounds(null, null, icon, null); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/view/DropdownListItemView.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.util.AttributeSet; 6 | import android.widget.TextView; 7 | 8 | import fj.hoverdropdownmenu.demo.R; 9 | 10 | 11 | public class DropdownListItemView extends TextView { 12 | public DropdownListItemView(Context context) { 13 | this(context,null); 14 | } 15 | 16 | public DropdownListItemView(Context context, AttributeSet attrs) { 17 | this(context, attrs, 0); 18 | } 19 | public DropdownListItemView(Context context, AttributeSet attrs, int defStyleAttr) { 20 | super(context, attrs, defStyleAttr); 21 | } 22 | 23 | public void bind(CharSequence text, boolean checked){ 24 | setText(text); 25 | if (checked){ 26 | Drawable icon = getResources().getDrawable(R.drawable.ic_task_status_list_check); 27 | setCompoundDrawablesWithIntrinsicBounds(null,null,icon,null); 28 | }else{ 29 | setCompoundDrawablesWithIntrinsicBounds(null,null,null,null); 30 | } 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/fj/hoverdropdownmenu/demo/view/DropdownListView.java: -------------------------------------------------------------------------------- 1 | package fj.hoverdropdownmenu.demo.view; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.widget.LinearLayout; 9 | import android.widget.ScrollView; 10 | 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | 14 | import fj.hoverdropdownmenu.demo.R; 15 | import fj.hoverdropdownmenu.demo.bean.DropdownItemObject; 16 | 17 | public class DropdownListView extends ScrollView { 18 | public LinearLayout linearLayout; 19 | 20 | public DropdownItemObject current; 21 | 22 | List list; 23 | 24 | public DropdownButton button; 25 | 26 | public DropdownListView(Context context) { 27 | this(context, null); 28 | } 29 | 30 | public DropdownListView(Context context, AttributeSet attrs) { 31 | this(context, attrs, 0); 32 | } 33 | 34 | public DropdownListView(Context context, AttributeSet attrs, int defStyleAttr) { 35 | super(context, attrs, defStyleAttr); 36 | init(); 37 | } 38 | 39 | private void init() { 40 | View view = LayoutInflater.from(getContext()).inflate(R.layout.dropdown_tab_list, this,true); 41 | linearLayout = (LinearLayout) view.findViewById(R.id.linearLayout); 42 | } 43 | 44 | 45 | public void flush() { 46 | for (int i = 0, n = linearLayout.getChildCount(); i < n; i++) { 47 | View view = linearLayout.getChildAt(i); 48 | if (view instanceof DropdownListItemView) { 49 | DropdownListItemView itemView = (DropdownListItemView) view; 50 | DropdownItemObject data = (DropdownItemObject) itemView.getTag(); 51 | if (data == null) { 52 | return; 53 | } 54 | boolean checked = data == current; 55 | String suffix = data.getSuffix(); 56 | itemView.bind(TextUtils.isEmpty(suffix) ? data.text : data.text + suffix, checked); 57 | if (checked) button.setText(data.text); 58 | } 59 | 60 | } 61 | } 62 | 63 | public void bind(List list, 64 | DropdownButton button, 65 | final Container container, 66 | int selectedId 67 | ) { 68 | current = null; 69 | this.list = list; 70 | this.button = button; 71 | LinkedList cachedDividers = new LinkedList<>(); 72 | LinkedList cachedViews = new LinkedList<>(); 73 | for (int i = 0, n = linearLayout.getChildCount(); i < n; i++) { 74 | View view = linearLayout.getChildAt(i); 75 | if (view instanceof DropdownListItemView) { 76 | cachedViews.add((DropdownListItemView) view); 77 | } else { 78 | cachedDividers.add(view); 79 | } 80 | } 81 | 82 | linearLayout.removeAllViews(); 83 | LayoutInflater inflater = LayoutInflater.from(getContext()); 84 | boolean isFirst = true; 85 | for (DropdownItemObject item : list) { 86 | if (isFirst) { 87 | isFirst = false; 88 | } else { 89 | View divider = cachedDividers.poll(); 90 | if (divider == null) { 91 | divider = inflater.inflate(R.layout.dropdown_tab_list_divider, linearLayout, false); 92 | } 93 | linearLayout.addView(divider); 94 | } 95 | DropdownListItemView view = cachedViews.poll(); 96 | if (view == null) { 97 | view = (DropdownListItemView) inflater.inflate(R.layout.dropdown_tab_list_item, linearLayout, false); 98 | } 99 | view.setTag(item); 100 | view.setOnClickListener(new OnClickListener() { 101 | @Override 102 | public void onClick(View v) { 103 | DropdownItemObject data = (DropdownItemObject) v.getTag(); 104 | if (data == null) return; 105 | DropdownItemObject oldOne = current; 106 | current = data; 107 | flush(); 108 | container.hide(); 109 | if (oldOne != current) { 110 | container.onSelectionChanged(DropdownListView.this); 111 | } 112 | } 113 | }); 114 | linearLayout.addView(view); 115 | if (item.id == selectedId && current == null) { 116 | current = item; 117 | } 118 | } 119 | 120 | button.setOnClickListener(new OnClickListener() { 121 | @Override 122 | public void onClick(View v) { 123 | if (getVisibility() == VISIBLE) { 124 | container.hide(); 125 | } else { 126 | container.show(DropdownListView.this); 127 | } 128 | } 129 | }); 130 | 131 | if (current == null && list.size() > 0) { 132 | current = list.get(0); 133 | } 134 | flush(); 135 | } 136 | 137 | 138 | public static interface Container { 139 | void show(DropdownListView listView); 140 | 141 | void hide(); 142 | 143 | void onSelectionChanged(DropdownListView view); 144 | } 145 | 146 | 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dropdown_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dropdown_mask_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dropdown_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/button_retry.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_btn_retry_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_btn_retry_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_btn_retry_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_btn_retry_press.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_dropdown_actived.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_dropdown_actived.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_dropdown_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_dropdown_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_exception_no_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_exception_no_network.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_task_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_task_comment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_task_status_list_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/ic_task_status_list_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/drawable-xhdpi/image.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/list_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 21 | 22 | 29 | 30 | 34 | 35 | 36 | 37 | 48 | 49 | 50 | 51 | 56 | 57 | 62 | 63 | 68 | 69 | 73 | 74 | 79 | 80 | 81 | 82 | 86 | 87 | 88 | 89 | 90 | 94 | 95 | 99 | 100 | 105 | 106 | 111 | 112 | 117 | 118 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dropdown_tab_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | 18 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dropdown_tab_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dropdown_tab_list_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dropdown_tab_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FJ917/FJHoverDropDownMenuDemo/e48ad9aca2bbd7dc90b09187078402acb04ff070/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF3BBD79 4 | #FF3BBD79 5 | #FF4081 6 | 7 | #FF3BBD79 8 | #222222 9 | #fff6f6f6 10 | #ffe4e4e4 11 | #ffd5d5d5 12 | #ff666666 13 | #ffffffff 14 | #999999 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FJHoverDropDownMenuDemo 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |