├── .gitignore ├── DropDownMenu.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── build │ └── outputs │ │ └── apk │ │ └── app-debug.apk ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yyy │ │ └── djk │ │ └── dropdownmenu │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── yyy │ │ └── djk │ │ └── dropdownmenu │ │ ├── ConstellationAdapter.java │ │ ├── GirdDropDownAdapter.java │ │ ├── ListDropDownAdapter.java │ │ └── MainActivity.java │ └── res │ ├── drawable │ ├── check_bg.xml │ ├── ok_bg.xml │ └── uncheck_bg.xml │ ├── layout │ ├── activity_main.xml │ ├── custom_layout.xml │ ├── item_constellation_layout.xml │ ├── item_default_drop_down.xml │ ├── item_list_drop_down.xml │ └── tab_text.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ ├── drop_down_checked.png │ ├── drop_down_selected_icon.png │ ├── drop_down_unselected_icon.png │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── interger.xml │ ├── strings.xml │ └── styles.xml ├── art ├── download.png └── simple.gif ├── build.gradle ├── dropdown_demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── library.iml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yyydjk │ │ └── library │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── yyydjk │ │ │ └── library │ │ │ └── DropDownMenu.java │ └── res │ │ ├── anim │ │ ├── dd_mask_in.xml │ │ ├── dd_mask_out.xml │ │ ├── dd_menu_in.xml │ │ └── dd_menu_out.xml │ │ ├── layout │ │ └── tab_item.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── yyydjk │ └── library │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | 9 | .idea -------------------------------------------------------------------------------- /DropDownMenu.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 扩展的思路 可以看我的[简书](http://www.jianshu.com/p/719267a0df32) 3 | 4 | ## 下载 5 | [demo.apk](app/build/outputs/apk/app-debug.apk) 6 | 7 | ## 特色 8 | * 支持多级菜单 9 | * 你可以完全自定义你的菜单样式,我这里只是封装了一些实用的方法,Tab的切换效果,菜单显示隐藏效果等 10 | * 非用popupWindow实现,无卡顿 11 | 12 | ## 截图 13 |
14 | 15 | ## 扩展 16 | 17 | 箭头居中而不是居最右
18 | 19 | 20 | icon方向属性
21 | 22 | 23 | 24 | 分隔线高度属性
25 | 26 | 27 | 28 | 为popupWindows集合的view增加了对LayoutParams的支持
29 | 30 | 31 | 32 | 支持手动添加非下拉tabView
33 | 34 | 35 | ## 使用 36 | 注意:`此布局需要作为根布局才可能覆盖内容区域` 37 | 38 | * 样式扩展 39 | 添加名为tab_item.xml到你的布局文件,在要显示内容的TextView上设置id为R.id.tv_tab。tab_item.xml中 任意布局即可。
40 | tab_item.xml 41 | ```xml 42 | 47 | 58 | 59 | ``` 60 | * 手动添加非下拉tabView 61 | tab_text.xml设置样式/也可以代码生成,加载控件添加到DropDownMenu中
62 | tab_text 63 | ```xml 64 | 75 | ``` 76 | 调用添加,在setDropDownMenu之后添加 77 | ```java 78 | ... 79 | //init dropdownview 80 | mDropDownMenu.setDropDownMenu(Arrays.asList(headers), popupViews, contentView); 81 | //测试tabView扩展功能 82 | TextView textView= (TextView) getLayoutInflater().inflate(R.layout.tab_text,null); 83 | textView.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f)); 84 | textView.setText("所有"); 85 | mDropDownMenu.addTab(textView,0); 86 | textView.setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View view) { 89 | mDropDownMenu.closeMenu(); 90 | } 91 | }); 92 | ``` 93 | 94 | 如果你要了解更多,可以直接看源码 Example 95 | 96 | ## 关于我 97 | 98 | 简书 [keyboard3](http://www.jianshu.com/users/62329de8c8a6/latest_articles)
99 | 邮箱 keyboard3@icloud.com 100 | 101 | # 致谢 102 | 103 | - 感谢 [dongjunkun/DropDownMenu](https://github.com/dongjunkun/DropDownMenu) 104 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | build/outputs/logs 3 | build/outputs/apk/app-debug-unaligned.apk 4 | build/generated 5 | build/intermediates 6 | build/tmp -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.yyy.djk.dropdownmenu" 9 | minSdkVersion 14 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:24.2.1' 25 | compile 'com.jakewharton:butterknife:6.1.0' 26 | compile project(':library') 27 | } 28 | -------------------------------------------------------------------------------- /app/build/outputs/apk/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/build/outputs/apk/app-debug.apk -------------------------------------------------------------------------------- /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 D:\Android\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/com/yyy/djk/dropdownmenu/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.yyy.djk.dropdownmenu; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/yyy/djk/dropdownmenu/ConstellationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yyy.djk.dropdownmenu; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | 11 | import java.util.List; 12 | 13 | import butterknife.ButterKnife; 14 | import butterknife.InjectView; 15 | 16 | 17 | public class ConstellationAdapter extends BaseAdapter { 18 | 19 | private Context context; 20 | private List list; 21 | private int checkItemPosition = 0; 22 | 23 | public void setCheckItem(int position) { 24 | checkItemPosition = position; 25 | notifyDataSetChanged(); 26 | } 27 | 28 | public ConstellationAdapter(Context context, List list) { 29 | this.context = context; 30 | this.list = list; 31 | } 32 | 33 | @Override 34 | public int getCount() { 35 | return list.size(); 36 | } 37 | 38 | @Override 39 | public Object getItem(int position) { 40 | return null; 41 | } 42 | 43 | @Override 44 | public long getItemId(int position) { 45 | return position; 46 | } 47 | 48 | @Override 49 | public View getView(int position, View convertView, ViewGroup parent) { 50 | ViewHolder viewHolder; 51 | if (convertView != null) { 52 | viewHolder = (ViewHolder) convertView.getTag(); 53 | } else { 54 | convertView = LayoutInflater.from(context).inflate(R.layout.item_constellation_layout, null); 55 | viewHolder = new ViewHolder(convertView); 56 | convertView.setTag(viewHolder); 57 | } 58 | fillValue(position, viewHolder); 59 | return convertView; 60 | } 61 | 62 | private void fillValue(int position, ViewHolder viewHolder) { 63 | viewHolder.mText.setText(list.get(position)); 64 | if (checkItemPosition != -1) { 65 | if (checkItemPosition == position) { 66 | viewHolder.mText.setTextColor(context.getResources().getColor(R.color.drop_down_selected)); 67 | viewHolder.mText.setBackgroundResource(R.drawable.check_bg); 68 | } else { 69 | viewHolder.mText.setTextColor(context.getResources().getColor(R.color.drop_down_unselected)); 70 | viewHolder.mText.setBackgroundResource(R.drawable.uncheck_bg); 71 | } 72 | } 73 | } 74 | 75 | static class ViewHolder { 76 | @InjectView(R.id.text) 77 | TextView mText; 78 | 79 | ViewHolder(View view) { 80 | ButterKnife.inject(this, view); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/yyy/djk/dropdownmenu/GirdDropDownAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yyy.djk.dropdownmenu; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | 11 | import java.util.List; 12 | 13 | import butterknife.ButterKnife; 14 | import butterknife.InjectView; 15 | 16 | 17 | public class GirdDropDownAdapter extends BaseAdapter { 18 | 19 | private Context context; 20 | private List list; 21 | private int checkItemPosition = 0; 22 | 23 | public void setCheckItem(int position) { 24 | checkItemPosition = position; 25 | notifyDataSetChanged(); 26 | } 27 | 28 | public GirdDropDownAdapter(Context context, List list) { 29 | this.context = context; 30 | this.list = list; 31 | } 32 | 33 | @Override 34 | public int getCount() { 35 | return list.size(); 36 | } 37 | 38 | @Override 39 | public Object getItem(int position) { 40 | return null; 41 | } 42 | 43 | @Override 44 | public long getItemId(int position) { 45 | return position; 46 | } 47 | 48 | @Override 49 | public View getView(int position, View convertView, ViewGroup parent) { 50 | ViewHolder viewHolder; 51 | if (convertView != null) { 52 | viewHolder = (ViewHolder) convertView.getTag(); 53 | } else { 54 | convertView = LayoutInflater.from(context).inflate(R.layout.item_list_drop_down, null); 55 | viewHolder = new ViewHolder(convertView); 56 | convertView.setTag(viewHolder); 57 | } 58 | fillValue(position, viewHolder); 59 | return convertView; 60 | } 61 | 62 | private void fillValue(int position, ViewHolder viewHolder) { 63 | viewHolder.mText.setText(list.get(position)); 64 | if (checkItemPosition != -1) { 65 | if (checkItemPosition == position) { 66 | viewHolder.mText.setTextColor(context.getResources().getColor(R.color.drop_down_selected)); 67 | viewHolder.mText.setCompoundDrawablesWithIntrinsicBounds(null, null, context.getResources().getDrawable(R.mipmap.drop_down_checked), null); 68 | } else { 69 | viewHolder.mText.setTextColor(context.getResources().getColor(R.color.drop_down_unselected)); 70 | viewHolder.mText.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); 71 | } 72 | } 73 | } 74 | 75 | static class ViewHolder { 76 | @InjectView(R.id.text) 77 | TextView mText; 78 | 79 | ViewHolder(View view) { 80 | ButterKnife.inject(this, view); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/yyy/djk/dropdownmenu/ListDropDownAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yyy.djk.dropdownmenu; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | 11 | 12 | import java.util.List; 13 | 14 | import butterknife.ButterKnife; 15 | import butterknife.InjectView; 16 | 17 | 18 | public class ListDropDownAdapter extends BaseAdapter { 19 | 20 | private Context context; 21 | private List list; 22 | private int checkItemPosition = 0; 23 | 24 | public void setCheckItem(int position) { 25 | checkItemPosition = position; 26 | notifyDataSetChanged(); 27 | } 28 | 29 | public ListDropDownAdapter(Context context, List list) { 30 | this.context = context; 31 | this.list = list; 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return list.size(); 37 | } 38 | 39 | @Override 40 | public Object getItem(int position) { 41 | return null; 42 | } 43 | 44 | @Override 45 | public long getItemId(int position) { 46 | return position; 47 | } 48 | 49 | @Override 50 | public View getView(int position, View convertView, ViewGroup parent) { 51 | ViewHolder viewHolder; 52 | if (convertView != null) { 53 | viewHolder = (ViewHolder) convertView.getTag(); 54 | } else { 55 | convertView = LayoutInflater.from(context).inflate(R.layout.item_default_drop_down, null); 56 | viewHolder = new ViewHolder(convertView); 57 | convertView.setTag(viewHolder); 58 | } 59 | fillValue(position, viewHolder); 60 | return convertView; 61 | } 62 | 63 | private void fillValue(int position, ViewHolder viewHolder) { 64 | viewHolder.mText.setText(list.get(position)); 65 | if (checkItemPosition != -1) { 66 | if (checkItemPosition == position) { 67 | viewHolder.mText.setTextColor(context.getResources().getColor(R.color.drop_down_selected)); 68 | viewHolder.mText.setBackgroundResource(R.color.check_bg); 69 | } else { 70 | viewHolder.mText.setTextColor(context.getResources().getColor(R.color.drop_down_unselected)); 71 | viewHolder.mText.setBackgroundResource(R.color.white); 72 | } 73 | } 74 | } 75 | 76 | static class ViewHolder { 77 | @InjectView(R.id.text) 78 | TextView mText; 79 | 80 | ViewHolder(View view) { 81 | ButterKnife.inject(this, view); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/yyy/djk/dropdownmenu/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yyy.djk.dropdownmenu; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.TypedValue; 6 | import android.view.Gravity; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.AdapterView; 10 | import android.widget.FrameLayout; 11 | import android.widget.GridView; 12 | import android.widget.LinearLayout; 13 | import android.widget.ListView; 14 | import android.widget.TextView; 15 | 16 | import com.yyydjk.library.DropDownMenu; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Arrays; 20 | import java.util.List; 21 | 22 | import butterknife.ButterKnife; 23 | import butterknife.InjectView; 24 | 25 | public class MainActivity extends AppCompatActivity { 26 | 27 | @InjectView(R.id.dropDownMenu) 28 | DropDownMenu mDropDownMenu; 29 | private String headers[] = {"城市", "年龄", "性别", "星座"}; 30 | private List popupViews = new ArrayList<>(); 31 | 32 | private GirdDropDownAdapter cityAdapter; 33 | private ListDropDownAdapter ageAdapter; 34 | private ListDropDownAdapter sexAdapter; 35 | private ConstellationAdapter constellationAdapter; 36 | 37 | private String citys[] = {"不限", "武汉", "北京", "上海", "成都", "广州", "深圳", "重庆", "天津", "西安", "南京", "杭州"}; 38 | private String ages[] = {"不限", "18岁以下", "18-22岁", "23-26岁", "27-35岁", "35岁以上"}; 39 | private String sexs[] = {"不限", "男", "女"}; 40 | private String constellations[] = {"不限", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座", "水瓶座", "双鱼座"}; 41 | 42 | private int constellationPosition = 0; 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_main); 48 | ButterKnife.inject(this); 49 | initView(); 50 | } 51 | 52 | private void initView() { 53 | //测试tabView扩展功能 54 | final TextView textView = (TextView) getLayoutInflater().inflate(R.layout.tab_text, null); 55 | textView.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f)); 56 | textView.setTextColor(getResources().getColor(R.color.drop_down_selected)); 57 | textView.setText("所有"); 58 | 59 | //init city menu 60 | final ListView cityView = new ListView(this); 61 | cityAdapter = new GirdDropDownAdapter(this, Arrays.asList(citys)); 62 | cityView.setDividerHeight(0); 63 | cityView.setAdapter(cityAdapter); 64 | 65 | //init age menu 66 | final ListView ageView = new ListView(this); 67 | ageView.setDividerHeight(0); 68 | ageAdapter = new ListDropDownAdapter(this, Arrays.asList(ages)); 69 | ageView.setAdapter(ageAdapter); 70 | 71 | //init sex menu 72 | final ListView sexView = new ListView(this); 73 | sexView.setDividerHeight(0); 74 | sexAdapter = new ListDropDownAdapter(this, Arrays.asList(sexs)); 75 | sexView.setAdapter(sexAdapter); 76 | 77 | //init constellation 78 | final View constellationView = getLayoutInflater().inflate(R.layout.custom_layout, null); 79 | GridView constellation = ButterKnife.findById(constellationView, R.id.constellation); 80 | constellationAdapter = new ConstellationAdapter(this, Arrays.asList(constellations)); 81 | constellation.setAdapter(constellationAdapter); 82 | TextView ok = ButterKnife.findById(constellationView, R.id.ok); 83 | ok.setOnClickListener(new View.OnClickListener() { 84 | @Override 85 | public void onClick(View v) { 86 | mDropDownMenu.setTabText(constellationPosition == 0 ? headers[3] : constellations[constellationPosition]); 87 | mDropDownMenu.closeMenu(); 88 | } 89 | }); 90 | //添加时间 2017年1月5日21:28:22 91 | //keyboard3 为支持可以外部控制popViews里的View可以设置layoutParams。注意必须是FrameLayout的布局参数 92 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); 93 | layoutParams.setMargins(200, 100, 200, 0); 94 | cityView.setLayoutParams(layoutParams); 95 | //init popupViews 96 | popupViews.add(cityView); 97 | popupViews.add(ageView); 98 | popupViews.add(sexView); 99 | popupViews.add(constellationView); 100 | 101 | //add item click event 102 | cityView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 103 | @Override 104 | public void onItemClick(AdapterView parent, View view, int position, long id) { 105 | cityAdapter.setCheckItem(position); 106 | mDropDownMenu.setTabText(position == 0 ? headers[0] : citys[position]); 107 | mDropDownMenu.closeMenu(); 108 | textView.setTextColor(getResources().getColor(R.color.drop_down_unselected)); 109 | } 110 | }); 111 | 112 | ageView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 113 | @Override 114 | public void onItemClick(AdapterView parent, View view, int position, long id) { 115 | ageAdapter.setCheckItem(position); 116 | mDropDownMenu.setTabText(position == 0 ? headers[1] : ages[position]); 117 | mDropDownMenu.closeMenu(); 118 | textView.setTextColor(getResources().getColor(R.color.drop_down_unselected)); 119 | } 120 | }); 121 | 122 | sexView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 123 | @Override 124 | public void onItemClick(AdapterView parent, View view, int position, long id) { 125 | sexAdapter.setCheckItem(position); 126 | mDropDownMenu.setTabText(position == 0 ? headers[2] : sexs[position]); 127 | mDropDownMenu.closeMenu(); 128 | textView.setTextColor(getResources().getColor(R.color.drop_down_unselected)); 129 | } 130 | }); 131 | 132 | constellation.setOnItemClickListener(new AdapterView.OnItemClickListener() { 133 | @Override 134 | public void onItemClick(AdapterView parent, View view, int position, long id) { 135 | constellationAdapter.setCheckItem(position); 136 | constellationPosition = position; 137 | } 138 | }); 139 | 140 | //init context view 141 | TextView contentView = new TextView(this); 142 | contentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 143 | contentView.setText("内容显示区域"); 144 | contentView.setGravity(Gravity.CENTER); 145 | contentView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20); 146 | 147 | //初始化 dropdownview 148 | mDropDownMenu.setDropDownMenu(Arrays.asList(headers), popupViews, contentView); 149 | mDropDownMenu.addTab(textView, 4); 150 | textView.setOnClickListener(new View.OnClickListener() { 151 | @Override 152 | public void onClick(View view) { 153 | if (mDropDownMenu.isActive()) { 154 | mDropDownMenu.closeMenu(); 155 | textView.setTextColor(getResources().getColor(R.color.drop_down_selected)); 156 | } else { 157 | textView.setTextColor(getResources().getColor(R.color.drop_down_unselected)); 158 | } 159 | } 160 | }); 161 | mDropDownMenu.setOnItemMenuClickListener(new DropDownMenu.OnItemMenuClickListener() { 162 | @Override 163 | public void OnItemMenuClick(TextView tabView, int position) { 164 | textView.setTextColor(getResources().getColor(R.color.drop_down_unselected)); 165 | } 166 | }); 167 | } 168 | 169 | @Override 170 | public void onBackPressed() { 171 | //退出activity前关闭菜单 172 | if (mDropDownMenu.isShowing()) { 173 | mDropDownMenu.closeMenu(); 174 | } else { 175 | super.onBackPressed(); 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/check_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ok_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/uncheck_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/custom_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_constellation_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_default_drop_down.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 16 | 17 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_list_drop_down.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab_text.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/drop_down_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-xhdpi/drop_down_checked.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/drop_down_selected_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-xhdpi/drop_down_selected_icon.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/drop_down_unselected_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-xhdpi/drop_down_unselected_icon.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/app/src/main/res/mipmap-xxhdpi/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 | #ffffff 4 | #cccccc 5 | 6 | #7B1FA2 7 | #111111 8 | 9 | #88888888 10 | #f2f2f2 11 | #9C27B0 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/interger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 200 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DropDownMenu 3 | 4 | Settings 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /art/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/art/download.png -------------------------------------------------------------------------------- /art/simple.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/art/simple.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:2.2.3' 8 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' // Add this line 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | allprojects { 15 | repositories { 16 | jcenter() 17 | } 18 | } 19 | 20 | dependencies { 21 | } -------------------------------------------------------------------------------- /dropdown_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/dropdown_demo.gif -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyboard3/DropDownMenu/a0e823c82b72a47153ba1eb1cd8bbbe8abceb1d1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Oct 08 15:08:05 CST 2016 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-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | group = 'com.github.dongjunkun' 5 | 6 | android { 7 | compileSdkVersion 24 8 | buildToolsVersion "24.0.2" 9 | 10 | defaultConfig { 11 | minSdkVersion 11 12 | targetSdkVersion 24 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | testCompile 'junit:junit:4.12' 27 | compile 'com.android.support:appcompat-v7:24.2.1' 28 | } 29 | -------------------------------------------------------------------------------- /library/library.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /library/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 D:\Android\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 | -------------------------------------------------------------------------------- /library/src/androidTest/java/com/yyydjk/library/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.yyydjk.library; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/yyydjk/library/DropDownMenu.java: -------------------------------------------------------------------------------- 1 | package com.yyydjk.library; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.drawable.Drawable; 6 | import android.support.annotation.NonNull; 7 | import android.util.AttributeSet; 8 | import android.util.DisplayMetrics; 9 | import android.util.TypedValue; 10 | import android.view.Gravity; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.view.animation.AnimationUtils; 14 | import android.widget.FrameLayout; 15 | import android.widget.LinearLayout; 16 | import android.widget.TextView; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | class Orientation { 22 | Context mContext; 23 | private Drawable unSelectedDrawable; 24 | private Drawable selectedDrawable; 25 | private int orientation; 26 | 27 | public Orientation(Context context) { 28 | mContext = context; 29 | } 30 | 31 | public static final int left = 0; 32 | public static final int top = 1; 33 | public static final int right = 2; 34 | public static final int bottom = 3; 35 | 36 | public Drawable getLeft(boolean close) { 37 | return orientation == left ? (close ? unSelectedDrawable : selectedDrawable) : null; 38 | } 39 | 40 | public Drawable getTop(boolean close) { 41 | return orientation == top ? (close ? unSelectedDrawable : selectedDrawable) : null; 42 | } 43 | 44 | public Drawable getRight(boolean close) { 45 | return orientation == right ? (close ? unSelectedDrawable : selectedDrawable) : null; 46 | } 47 | 48 | public Drawable getBottom(boolean close) { 49 | return orientation == bottom ? (close ? unSelectedDrawable : selectedDrawable) : null; 50 | } 51 | 52 | /** 53 | * 初始化位置参数 54 | * 55 | * @param orientation 56 | * @param menuUnselectedIcon 57 | */ 58 | public void init(int orientation, int menuSelectedIcon, int menuUnselectedIcon) { 59 | 60 | unSelectedDrawable = mContext.getResources().getDrawable(menuUnselectedIcon); 61 | selectedDrawable = mContext.getResources().getDrawable(menuSelectedIcon); 62 | this.orientation = orientation; 63 | } 64 | } 65 | 66 | /** 67 | * Created by dongjunkun on 2015/6/17. 68 | */ 69 | public class DropDownMenu extends LinearLayout { 70 | //记录tabTexts的顺序 71 | List dropTabViews = new ArrayList<>(); 72 | //顶部菜单布局 73 | private LinearLayout tabMenuView; 74 | //底部容器,包含popupMenuViews,maskView 75 | private FrameLayout containerView; 76 | //弹出菜单父布局 77 | private FrameLayout popupMenuViews; 78 | //遮罩半透明View,点击可关闭DropDownMenu 79 | private View maskView; 80 | //tabMenuView里面选中的tab位置,-1表示未选中 81 | private int current_tab_position = -1; 82 | private float dividerHeight; 83 | //分割线颜色 84 | private int dividerColor = 0xffcccccc; 85 | //tab选中颜色 86 | private int textSelectedColor = 0xff890c85; 87 | //tab未选中颜色 88 | private int textUnselectedColor = 0xff111111; 89 | //遮罩颜色 90 | private int maskColor = 0x88888888; 91 | //tab字体大小 92 | private int menuTextSize = 14; 93 | //icon的方向 94 | private static int iconOrientation = Orientation.right;//默认右则 95 | private Orientation mOrientation; 96 | //tab选中图标 97 | private int menuSelectedIcon; 98 | //tab未选中图标 99 | private int menuUnselectedIcon; 100 | 101 | 102 | public DropDownMenu(Context context) { 103 | super(context, null); 104 | } 105 | 106 | public DropDownMenu(Context context, AttributeSet attrs) { 107 | this(context, attrs, 0); 108 | } 109 | 110 | public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) { 111 | super(context, attrs, defStyleAttr); 112 | 113 | setOrientation(VERTICAL); 114 | 115 | //为DropDownMenu添加自定义属性 116 | int menuBackgroundColor = 0xffffffff; 117 | int underlineColor = 0xffcccccc; 118 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu); 119 | underlineColor = a.getColor(R.styleable.DropDownMenu_ddunderlineColor, underlineColor); 120 | dividerColor = a.getColor(R.styleable.DropDownMenu_dddividerColor, dividerColor); 121 | textSelectedColor = a.getColor(R.styleable.DropDownMenu_ddtextSelectedColor, 122 | textSelectedColor); 123 | textUnselectedColor = a.getColor(R.styleable.DropDownMenu_ddtextUnselectedColor, 124 | textUnselectedColor); 125 | menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_ddmenuBackgroundColor, 126 | menuBackgroundColor); 127 | maskColor = a.getColor(R.styleable.DropDownMenu_ddmaskColor, maskColor); 128 | menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_ddmenuTextSize, 129 | menuTextSize); 130 | dividerHeight = a.getDimensionPixelSize(R.styleable.DropDownMenu_dddividerHeight, ViewGroup.LayoutParams.MATCH_PARENT); 131 | menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuSelectedIcon, 132 | menuSelectedIcon); 133 | menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuUnselectedIcon, 134 | menuUnselectedIcon); 135 | iconOrientation = a.getInt(R.styleable.DropDownMenu_ddmenuIconOrientation, iconOrientation); 136 | a.recycle(); 137 | //初始化位置参数 138 | mOrientation = new Orientation(getContext()); 139 | mOrientation.init(iconOrientation, menuSelectedIcon, menuUnselectedIcon); 140 | 141 | //初始化tabMenuView并添加到tabMenuView 142 | tabMenuView = new LinearLayout(context); 143 | LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup 144 | .LayoutParams.WRAP_CONTENT); 145 | tabMenuView.setOrientation(HORIZONTAL); 146 | tabMenuView.setBackgroundColor(menuBackgroundColor); 147 | tabMenuView.setLayoutParams(params); 148 | addView(tabMenuView, 0); 149 | 150 | //为tabMenuView添加下划线 151 | View underLine = new View(getContext()); 152 | underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 153 | dpTpPx(1.0f))); 154 | underLine.setBackgroundColor(underlineColor); 155 | addView(underLine, 1); 156 | 157 | //初始化containerView并将其添加到DropDownMenu 158 | containerView = new FrameLayout(context); 159 | containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams 160 | .MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); 161 | addView(containerView, 2); 162 | 163 | 164 | } 165 | 166 | 167 | /** 168 | * 初始化DropDownMenu 169 | * 170 | * @param tabTexts 171 | * @param popupViews 172 | * @param contentView 173 | */ 174 | public void setDropDownMenu(@NonNull List tabTexts, @NonNull List popupViews, 175 | @NonNull View contentView) { 176 | if (tabTexts.size() != popupViews.size()) { 177 | throw new IllegalArgumentException("params not match, tabTexts.size() should be equal" + 178 | " popupViews.size()"); 179 | } 180 | 181 | for (int i = 0; i < tabTexts.size(); i++) { 182 | addTab(tabTexts, i); 183 | } 184 | containerView.addView(contentView, 0); 185 | 186 | maskView = new View(getContext()); 187 | maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams 188 | .MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); 189 | maskView.setBackgroundColor(maskColor); 190 | maskView.setOnClickListener(new OnClickListener() { 191 | @Override 192 | public void onClick(View v) { 193 | closeMenu(); 194 | } 195 | }); 196 | containerView.addView(maskView, 1); 197 | maskView.setVisibility(GONE); 198 | 199 | popupMenuViews = new FrameLayout(getContext()); 200 | popupMenuViews.setVisibility(GONE); 201 | containerView.addView(popupMenuViews, 2); 202 | 203 | for (int i = 0; i < popupViews.size(); i++) { 204 | if (popupViews.get(i).getLayoutParams() == null) { 205 | popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams 206 | .MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 207 | } 208 | popupMenuViews.addView(popupViews.get(i), i); 209 | } 210 | 211 | } 212 | 213 | /** 214 | * 自定义插入的tabView,如果包含R.id.tv_tab就当做普通的tabtext会统一做变色处理和向下的角标处理 215 | * 216 | * @param tab 217 | * @param index 0start 218 | */ 219 | public void addTab(View tab, int index) { 220 | if (index == (tabMenuView.getChildCount() + 1) / 2) { 221 | addTabEnd(tab); 222 | return; 223 | } 224 | tabMenuView.addView(tab, index * 2); 225 | tabMenuView.addView(getDividerView(), index * 2 + 1); 226 | } 227 | 228 | public void addTabEnd(View tab) { 229 | tabMenuView.addView(getDividerView(), tabMenuView.getChildCount()); 230 | tabMenuView.addView(tab, tabMenuView.getChildCount()); 231 | } 232 | 233 | private void addTab(@NonNull List tabTexts, final int i) { 234 | final View tab = inflate(getContext(), R.layout.tab_item, null); 235 | tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f)); 236 | final TextView textView = getTabTextView(tab); 237 | textView.setText(tabTexts.get(i)); 238 | textView.setTextColor(textUnselectedColor); 239 | textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, menuTextSize); 240 | setTextDrawables(textView, true); 241 | tabMenuView.addView(tab); 242 | tab.setOnClickListener(new OnClickListener() { 243 | @Override 244 | public void onClick(View v) { 245 | if (itemMenuClickListener != null) { 246 | itemMenuClickListener.OnItemMenuClick(textView, i); 247 | } 248 | switchMenu(v); 249 | } 250 | }); 251 | 252 | //添加分割线 253 | if (i < tabTexts.size() - 1) { 254 | tabMenuView.addView(getDividerView()); 255 | } 256 | dropTabViews.add(tab); 257 | } 258 | 259 | private View getDividerView() { 260 | View view = new View(getContext()); 261 | double height = dividerHeight > 0 ? dpTpPx(dividerHeight) : dividerHeight; 262 | LayoutParams params = new LayoutParams(dpTpPx(0.5f), (int) height); 263 | params.gravity = Gravity.CENTER_VERTICAL; 264 | view.setLayoutParams(params); 265 | view.setBackgroundColor(dividerColor); 266 | return view; 267 | } 268 | 269 | /** 270 | * 获取tabView中id为tv_tab的textView 271 | * 272 | * @param tabView 273 | * @return 274 | */ 275 | private TextView getTabTextView(View tabView) { 276 | TextView tabtext = (TextView) tabView.findViewById(R.id.tv_tab); 277 | return tabtext; 278 | } 279 | 280 | /** 281 | * 改变tab文字 282 | * 283 | * @param text 284 | */ 285 | public void setTabText(String text) { 286 | if (current_tab_position != -1) { 287 | getTabTextView(tabMenuView.getChildAt(current_tab_position)).setText(text); 288 | } 289 | } 290 | 291 | public void setTabClickable(boolean clickable) { 292 | for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) { 293 | tabMenuView.getChildAt(i).setClickable(clickable); 294 | } 295 | } 296 | 297 | /** 298 | * 关闭菜单 299 | */ 300 | public void closeMenu() { 301 | if (current_tab_position != -1) { 302 | TextView textView = getTabTextView(tabMenuView.getChildAt(current_tab_position)); 303 | textView.setTextColor(textUnselectedColor); 304 | setTextDrawables(textView, true); 305 | popupMenuViews.setVisibility(View.GONE); 306 | popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim 307 | .dd_menu_out)); 308 | maskView.setVisibility(GONE); 309 | maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out)); 310 | current_tab_position = -1; 311 | } 312 | } 313 | 314 | public boolean isActive() { 315 | return current_tab_position != -1; 316 | } 317 | 318 | public void setTextDrawables(TextView textview, boolean close) { 319 | textview.setCompoundDrawablesWithIntrinsicBounds(mOrientation.getLeft(close), mOrientation.getTop(close), 320 | mOrientation.getRight(close), mOrientation.getBottom(close)); 321 | } 322 | 323 | /** 324 | * DropDownMenu是否处于可见状态 325 | * 326 | * @return 327 | */ 328 | public boolean isShowing() { 329 | return current_tab_position != -1; 330 | } 331 | 332 | /** 333 | * 切换菜单 334 | * 335 | * @param target 336 | */ 337 | private void switchMenu(View target) { 338 | System.out.println(current_tab_position); 339 | for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) { 340 | if (target == tabMenuView.getChildAt(i)) { 341 | if (current_tab_position == i) { 342 | closeMenu();//关闭 343 | } else {//打开 344 | if (current_tab_position == -1) { 345 | popupMenuViews.setVisibility(View.VISIBLE); 346 | popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R 347 | .anim.dd_menu_in)); 348 | maskView.setVisibility(VISIBLE); 349 | maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim 350 | .dd_mask_in)); 351 | } 352 | View listView = getListView(tabMenuView.getChildAt(i)); 353 | if (listView != null) { 354 | listView.setVisibility(View.VISIBLE); 355 | } 356 | current_tab_position = i; 357 | TextView textView = getTabTextView(tabMenuView.getChildAt(i)); 358 | textView.setTextColor(textSelectedColor); 359 | setTextDrawables(textView, false); 360 | } 361 | } else {//关闭 362 | TextView textView = getTabTextView(tabMenuView.getChildAt(i)); 363 | if (textView != null) { 364 | textView.setTextColor(textUnselectedColor); 365 | 366 | } 367 | View listView = getListView(tabMenuView.getChildAt(i)); 368 | if (listView != null) { 369 | if (textView != null) { 370 | setTextDrawables(textView, true); 371 | } 372 | listView.setVisibility(View.GONE); 373 | } 374 | } 375 | } 376 | } 377 | 378 | OnItemMenuClickListener itemMenuClickListener; 379 | 380 | public void setOnItemMenuClickListener(OnItemMenuClickListener listener) { 381 | itemMenuClickListener = listener; 382 | } 383 | 384 | public interface OnItemMenuClickListener { 385 | void OnItemMenuClick(TextView tabView, int position); 386 | } 387 | 388 | /** 389 | * 获取dropTabViews中对应popupMenuViews数组中的ListView 390 | * 391 | * @param view 392 | * @return 393 | */ 394 | private View getListView(View view) { 395 | if (dropTabViews.contains(view)) { 396 | int index = dropTabViews.indexOf(view); 397 | return popupMenuViews.getChildAt(index); 398 | } else { 399 | return null; 400 | } 401 | } 402 | 403 | public int dpTpPx(float value) { 404 | DisplayMetrics dm = getResources().getDisplayMetrics(); 405 | return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + 0.5); 406 | } 407 | } -------------------------------------------------------------------------------- /library/src/main/res/anim/dd_mask_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/res/anim/dd_mask_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/res/anim/dd_menu_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/res/anim/dd_menu_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/res/layout/tab_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 19 | -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.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 | -------------------------------------------------------------------------------- /library/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | #cccccc 5 | 6 | #7B1FA2 7 | #111111 8 | 9 | #88888888 10 | #f2f2f2 11 | #9C27B0 12 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Library 3 | 4 | -------------------------------------------------------------------------------- /library/src/test/java/com/yyydjk/library/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.yyydjk.library; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | --------------------------------------------------------------------------------