├── .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
│ ├── 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
├── 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
│ │ │ ├── DeviceUtils.java
│ │ │ └── DropDownMenu.java
│ └── res
│ │ ├── anim
│ │ ├── dd_mask_in.xml
│ │ ├── dd_mask_out.xml
│ │ ├── dd_menu_in.xml
│ │ └── dd_menu_out.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ └── colors.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 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://jitpack.io/#dongjunkun/DropDownMenu)
2 |
3 | ## 简介
4 | 一个实用的多条件筛选菜单,在很多App上都能看到这个效果,如美团,爱奇艺电影票等
5 |
6 | 我的博客 [自己造轮子--android常用多条件帅选菜单实现思路(类似美团,爱奇艺电影票下拉菜单)](http://www.jianshu.com/p/d9407f799d2d)
7 |
8 | ## 特色
9 | - 支持多级菜单
10 | - 你可以完全自定义你的菜单样式,我这里只是封装了一些实用的方法,Tab的切换效果,菜单显示隐藏效果等
11 | - 并非用popupWindow实现,无卡顿
12 |
13 | ## ScreenShot
14 |
15 |
16 | Download APK
17 |
18 | 或者扫描二维码
19 |
20 |
21 |
22 | ## Gradle Dependency
23 |
24 | ```
25 | allprojects {
26 | repositories {
27 | ...
28 | maven { url "https://jitpack.io" }
29 | }
30 | }
31 |
32 | dependencies {
33 | compile 'com.github.dongjunkun:DropDownMenu:1.0.4'
34 | }
35 | ```
36 |
37 | ## 使用
38 | 添加DropDownMenu 到你的布局文件,如下
39 | ```
40 |
56 | ```
57 | 我们只需要在java代码中调用下面的代码
58 |
59 | ```
60 | //tabs 所有标题,popupViews 所有菜单,contentView 内容
61 | mDropDownMenu.setDropDownMenu(tabs, popupViews, contentView);
62 | ```
63 | 如果你要了解更多,可以直接看源码 Example
64 |
65 | > 建议拷贝代码到项目中使用,拷贝DropDownMenu.java 以及res下的所有文件即可
66 |
67 | ## 关于我
68 | 简书[dongjunkun](http://www.jianshu.com/users/f07458c1a8f3/latest_articles)
69 |
--------------------------------------------------------------------------------
/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 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.yyy.djk.dropdownmenu"
9 | minSdkVersion 14
10 | targetSdkVersion 25
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:25.3.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/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/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 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/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.GridView;
11 | import android.widget.ListView;
12 | import android.widget.TextView;
13 |
14 | import com.yyydjk.library.DropDownMenu;
15 |
16 | import java.util.ArrayList;
17 | import java.util.Arrays;
18 | import java.util.List;
19 |
20 | import butterknife.ButterKnife;
21 | import butterknife.InjectView;
22 |
23 | public class MainActivity extends AppCompatActivity {
24 |
25 | @InjectView(R.id.dropDownMenu) DropDownMenu mDropDownMenu;
26 | private String headers[] = {"城市", "年龄", "性别", "星座"};
27 | private List popupViews = new ArrayList<>();
28 |
29 | private GirdDropDownAdapter cityAdapter;
30 | private ListDropDownAdapter ageAdapter;
31 | private ListDropDownAdapter sexAdapter;
32 | private ConstellationAdapter constellationAdapter;
33 |
34 | private String citys[] = {"不限", "武汉", "北京", "上海", "成都", "广州", "深圳", "重庆", "天津", "西安", "南京", "杭州"};
35 | private String ages[] = {"不限", "18岁以下", "18-22岁", "23-26岁", "27-35岁", "35岁以上"};
36 | private String sexs[] = {"不限", "男", "女"};
37 | private String constellations[] = {"不限", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座", "水瓶座", "双鱼座"};
38 |
39 | private int constellationPosition = 0;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_main);
45 | ButterKnife.inject(this);
46 | initView();
47 | }
48 |
49 | private void initView() {
50 | //init city menu
51 | final ListView cityView = new ListView(this);
52 | cityAdapter = new GirdDropDownAdapter(this, Arrays.asList(citys));
53 | cityView.setDividerHeight(0);
54 | cityView.setAdapter(cityAdapter);
55 |
56 | //init age menu
57 | final ListView ageView = new ListView(this);
58 | ageView.setDividerHeight(0);
59 | ageAdapter = new ListDropDownAdapter(this, Arrays.asList(ages));
60 | ageView.setAdapter(ageAdapter);
61 |
62 | //init sex menu
63 | final ListView sexView = new ListView(this);
64 | sexView.setDividerHeight(0);
65 | sexAdapter = new ListDropDownAdapter(this, Arrays.asList(sexs));
66 | sexView.setAdapter(sexAdapter);
67 |
68 | //init constellation
69 | final View constellationView = getLayoutInflater().inflate(R.layout.custom_layout, null);
70 | GridView constellation = ButterKnife.findById(constellationView, R.id.constellation);
71 | constellationAdapter = new ConstellationAdapter(this, Arrays.asList(constellations));
72 | constellation.setAdapter(constellationAdapter);
73 | TextView ok = ButterKnife.findById(constellationView, R.id.ok);
74 | ok.setOnClickListener(new View.OnClickListener() {
75 | @Override
76 | public void onClick(View v) {
77 | mDropDownMenu.setTabText(constellationPosition == 0 ? headers[3] : constellations[constellationPosition]);
78 | mDropDownMenu.closeMenu();
79 | }
80 | });
81 |
82 | //init popupViews
83 | popupViews.add(cityView);
84 | popupViews.add(ageView);
85 | popupViews.add(sexView);
86 | popupViews.add(constellationView);
87 |
88 | //add item click event
89 | cityView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
90 | @Override
91 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
92 | cityAdapter.setCheckItem(position);
93 | mDropDownMenu.setTabText(position == 0 ? headers[0] : citys[position]);
94 | mDropDownMenu.closeMenu();
95 | }
96 | });
97 |
98 | ageView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
99 | @Override
100 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
101 | ageAdapter.setCheckItem(position);
102 | mDropDownMenu.setTabText(position == 0 ? headers[1] : ages[position]);
103 | mDropDownMenu.closeMenu();
104 | }
105 | });
106 |
107 | sexView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
108 | @Override
109 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
110 | sexAdapter.setCheckItem(position);
111 | mDropDownMenu.setTabText(position == 0 ? headers[2] : sexs[position]);
112 | mDropDownMenu.closeMenu();
113 | }
114 | });
115 |
116 | constellation.setOnItemClickListener(new AdapterView.OnItemClickListener() {
117 | @Override
118 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
119 | constellationAdapter.setCheckItem(position);
120 | constellationPosition = position;
121 | }
122 | });
123 |
124 | //init context view
125 | TextView contentView = new TextView(this);
126 | contentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
127 | contentView.setText("内容显示区域");
128 | contentView.setGravity(Gravity.CENTER);
129 | contentView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
130 |
131 | //init dropdownview
132 | mDropDownMenu.setDropDownMenu(Arrays.asList(headers), popupViews, contentView);
133 | }
134 |
135 | @Override
136 | public void onBackPressed() {
137 | //退出activity前关闭菜单
138 | if (mDropDownMenu.isShowing()) {
139 | mDropDownMenu.closeMenu();
140 | } else {
141 | super.onBackPressed();
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/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 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/custom_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/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 |
6 |
7 |
17 |
18 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_list_drop_down.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/drop_down_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/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/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/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/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/app/src/main/res/mipmap-xhdpi/drop_down_unselected_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/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 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/art/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/art/download.png
--------------------------------------------------------------------------------
/art/simple.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/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.3.1'
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 | }
22 |
--------------------------------------------------------------------------------
/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/dongjunkun/DropDownMenu/63e308f94282fa23e4a8c043328033913c88214d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Apr 11 16:01:41 CST 2017
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-3.3-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 25
8 | buildToolsVersion "25.0.2"
9 |
10 | defaultConfig {
11 | minSdkVersion 11
12 | targetSdkVersion 25
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:25.3.1'
28 | }
29 |
--------------------------------------------------------------------------------
/library/library.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 |
--------------------------------------------------------------------------------
/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 |
2 |
3 |
--------------------------------------------------------------------------------
/library/src/main/java/com/yyydjk/library/DeviceUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Peng fei Pan
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.yyydjk.library;
18 |
19 | import android.annotation.TargetApi;
20 | import android.content.Context;
21 | import android.graphics.Point;
22 | import android.os.Build;
23 | import android.view.Display;
24 | import android.view.WindowManager;
25 |
26 | /**
27 | * 设备工具箱,提供与设备硬件相关的工具方法
28 | */
29 | public class DeviceUtils {
30 |
31 | /**
32 | * 获取屏幕尺寸
33 | */
34 | @SuppressWarnings("deprecation")
35 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
36 | public static Point getScreenSize(Context context){
37 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
38 | Display display = windowManager.getDefaultDisplay();
39 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2){
40 | return new Point(display.getWidth(), display.getHeight());
41 | }else{
42 | Point point = new Point();
43 | display.getSize(point);
44 | return point;
45 | }
46 | }
47 |
48 |
49 | }
--------------------------------------------------------------------------------
/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.support.annotation.NonNull;
6 | import android.text.TextUtils;
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.List;
19 |
20 |
21 | /**
22 | * Created by dongjunkun on 2015/6/17.
23 | */
24 | public class DropDownMenu extends LinearLayout {
25 |
26 | //顶部菜单布局
27 | private LinearLayout tabMenuView;
28 | //底部容器,包含popupMenuViews,maskView
29 | private FrameLayout containerView;
30 | //弹出菜单父布局
31 | private FrameLayout popupMenuViews;
32 | //遮罩半透明View,点击可关闭DropDownMenu
33 | private View maskView;
34 | //tabMenuView里面选中的tab位置,-1表示未选中
35 | private int current_tab_position = -1;
36 |
37 | //分割线颜色
38 | private int dividerColor = 0xffcccccc;
39 | //tab选中颜色
40 | private int textSelectedColor = 0xff890c85;
41 | //tab未选中颜色
42 | private int textUnselectedColor = 0xff111111;
43 | //遮罩颜色
44 | private int maskColor = 0x88888888;
45 | //tab字体大小
46 | private int menuTextSize = 14;
47 |
48 | //tab选中图标
49 | private int menuSelectedIcon;
50 | //tab未选中图标
51 | private int menuUnselectedIcon;
52 |
53 | private float menuHeighPercent = 0.5f;
54 |
55 |
56 | public DropDownMenu(Context context) {
57 | super(context, null);
58 | }
59 |
60 | public DropDownMenu(Context context, AttributeSet attrs) {
61 | this(context, attrs, 0);
62 | }
63 |
64 | public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) {
65 | super(context, attrs, defStyleAttr);
66 |
67 | setOrientation(VERTICAL);
68 |
69 | //为DropDownMenu添加自定义属性
70 | int menuBackgroundColor = 0xffffffff;
71 | int underlineColor = 0xffcccccc;
72 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu);
73 | underlineColor = a.getColor(R.styleable.DropDownMenu_ddunderlineColor, underlineColor);
74 | dividerColor = a.getColor(R.styleable.DropDownMenu_dddividerColor, dividerColor);
75 | textSelectedColor = a.getColor(R.styleable.DropDownMenu_ddtextSelectedColor, textSelectedColor);
76 | textUnselectedColor = a.getColor(R.styleable.DropDownMenu_ddtextUnselectedColor, textUnselectedColor);
77 | menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_ddmenuBackgroundColor, menuBackgroundColor);
78 | maskColor = a.getColor(R.styleable.DropDownMenu_ddmaskColor, maskColor);
79 | menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_ddmenuTextSize, menuTextSize);
80 | menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuSelectedIcon, menuSelectedIcon);
81 | menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuUnselectedIcon, menuUnselectedIcon);
82 | menuHeighPercent = a.getFloat(R.styleable.DropDownMenu_ddmenuMenuHeightPercent,menuHeighPercent);
83 | a.recycle();
84 |
85 | //初始化tabMenuView并添加到tabMenuView
86 | tabMenuView = new LinearLayout(context);
87 | LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
88 | tabMenuView.setOrientation(HORIZONTAL);
89 | tabMenuView.setBackgroundColor(menuBackgroundColor);
90 | tabMenuView.setLayoutParams(params);
91 | addView(tabMenuView, 0);
92 |
93 | //为tabMenuView添加下划线
94 | View underLine = new View(getContext());
95 | underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(1.0f)));
96 | underLine.setBackgroundColor(underlineColor);
97 | addView(underLine, 1);
98 |
99 | //初始化containerView并将其添加到DropDownMenu
100 | containerView = new FrameLayout(context);
101 | containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
102 | addView(containerView, 2);
103 |
104 | }
105 |
106 | /**
107 | * 初始化DropDownMenu
108 | *
109 | * @param tabTexts
110 | * @param popupViews
111 | * @param contentView
112 | */
113 | public void setDropDownMenu(@NonNull List tabTexts, @NonNull List popupViews, @NonNull View contentView) {
114 | if (tabTexts.size() != popupViews.size()) {
115 | throw new IllegalArgumentException("params not match, tabTexts.size() should be equal popupViews.size()");
116 | }
117 |
118 | for (int i = 0; i < tabTexts.size(); i++) {
119 | addTab(tabTexts, i);
120 | }
121 | containerView.addView(contentView, 0);
122 |
123 | maskView = new View(getContext());
124 | maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
125 | maskView.setBackgroundColor(maskColor);
126 | maskView.setOnClickListener(new OnClickListener() {
127 | @Override
128 | public void onClick(View v) {
129 | closeMenu();
130 | }
131 | });
132 | containerView.addView(maskView, 1);
133 | maskView.setVisibility(GONE);
134 | if (containerView.getChildAt(2) != null){
135 | containerView.removeViewAt(2);
136 | }
137 |
138 | popupMenuViews = new FrameLayout(getContext());
139 | popupMenuViews.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) (DeviceUtils.getScreenSize(getContext()).y*menuHeighPercent)));
140 | popupMenuViews.setVisibility(GONE);
141 | containerView.addView(popupMenuViews, 2);
142 |
143 | for (int i = 0; i < popupViews.size(); i++) {
144 | popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
145 | popupMenuViews.addView(popupViews.get(i), i);
146 | }
147 |
148 | }
149 |
150 | private void addTab(@NonNull List tabTexts, int i) {
151 | final TextView tab = new TextView(getContext());
152 | tab.setSingleLine();
153 | tab.setEllipsize(TextUtils.TruncateAt.END);
154 | tab.setGravity(Gravity.CENTER);
155 | tab.setTextSize(TypedValue.COMPLEX_UNIT_PX,menuTextSize);
156 | tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
157 | tab.setTextColor(textUnselectedColor);
158 | tab.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(menuUnselectedIcon), null);
159 | tab.setText(tabTexts.get(i));
160 | tab.setPadding(dpTpPx(5), dpTpPx(12), dpTpPx(5), dpTpPx(12));
161 | //添加点击事件
162 | tab.setOnClickListener(new OnClickListener() {
163 | @Override
164 | public void onClick(View v) {
165 | switchMenu(tab);
166 | }
167 | });
168 | tabMenuView.addView(tab);
169 | //添加分割线
170 | if (i < tabTexts.size() - 1) {
171 | View view = new View(getContext());
172 | view.setLayoutParams(new LayoutParams(dpTpPx(0.5f), ViewGroup.LayoutParams.MATCH_PARENT));
173 | view.setBackgroundColor(dividerColor);
174 | tabMenuView.addView(view);
175 | }
176 | }
177 |
178 | /**
179 | * 改变tab文字
180 | *
181 | * @param text
182 | */
183 | public void setTabText(String text) {
184 | if (current_tab_position != -1) {
185 | ((TextView) tabMenuView.getChildAt(current_tab_position)).setText(text);
186 | }
187 | }
188 |
189 | public void setTabClickable(boolean clickable) {
190 | for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
191 | tabMenuView.getChildAt(i).setClickable(clickable);
192 | }
193 | }
194 |
195 | /**
196 | * 关闭菜单
197 | */
198 | public void closeMenu() {
199 | if (current_tab_position != -1) {
200 | ((TextView) tabMenuView.getChildAt(current_tab_position)).setTextColor(textUnselectedColor);
201 | ((TextView) tabMenuView.getChildAt(current_tab_position)).setCompoundDrawablesWithIntrinsicBounds(null, null,
202 | getResources().getDrawable(menuUnselectedIcon), null);
203 | popupMenuViews.setVisibility(View.GONE);
204 | popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_out));
205 | maskView.setVisibility(GONE);
206 | maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out));
207 | current_tab_position = -1;
208 | }
209 |
210 | }
211 |
212 | /**
213 | * DropDownMenu是否处于可见状态
214 | *
215 | * @return
216 | */
217 | public boolean isShowing() {
218 | return current_tab_position != -1;
219 | }
220 |
221 | /**
222 | * 切换菜单
223 | *
224 | * @param target
225 | */
226 | private void switchMenu(View target) {
227 | System.out.println(current_tab_position);
228 | for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
229 | if (target == tabMenuView.getChildAt(i)) {
230 | if (current_tab_position == i) {
231 | closeMenu();
232 | } else {
233 | if (current_tab_position == -1) {
234 | popupMenuViews.setVisibility(View.VISIBLE);
235 | popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));
236 | maskView.setVisibility(VISIBLE);
237 | maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));
238 | popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
239 | } else {
240 | popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
241 | }
242 | current_tab_position = i;
243 | ((TextView) tabMenuView.getChildAt(i)).setTextColor(textSelectedColor);
244 | ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,
245 | getResources().getDrawable(menuSelectedIcon), null);
246 | }
247 | } else {
248 | ((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);
249 | ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,
250 | getResources().getDrawable(menuUnselectedIcon), null);
251 | popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);
252 | }
253 | }
254 | }
255 |
256 | public int dpTpPx(float value) {
257 | DisplayMetrics dm = getResources().getDisplayMetrics();
258 | return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + 0.5);
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/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/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------