├── .gitignore ├── README-CN.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── jkb │ │ └── slidemenulayout │ │ ├── MainActivity.java │ │ ├── adapter │ │ ├── ContentAdapter.java │ │ ├── FriendAdapter.java │ │ ├── SlideLeftAdapter.java │ │ ├── SlideRightMenuAdapter.java │ │ └── TabTwoAdapter.java │ │ └── ui │ │ ├── ChatFragment.java │ │ ├── FriendFragment.java │ │ ├── TabOneFragment.java │ │ └── TabTwoFragment.java │ └── res │ ├── drawable-xxhdpi │ ├── ic_action_conversations.png │ └── ic_action_menu.png │ ├── layout │ ├── activity_main.xml │ ├── content_menu_left.xml │ ├── content_menu_right.xml │ ├── frg_chat.xml │ ├── frg_friend.xml │ ├── frg_tab_one.xml │ ├── frg_tab_two.xml │ ├── item_friend.xml │ └── item_tab_two.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-v19 │ └── style.xml │ ├── values-v20 │ └── style.xml │ ├── values-v21 │ └── style.xml │ ├── values-v22 │ └── style.xml │ ├── values-v23 │ └── style.xml │ ├── values-v24 │ └── style.xml │ ├── values-v25 │ └── style.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ ├── style.xml │ └── styles.xml ├── build.gradle ├── config.gradle ├── gif ├── demo.gif └── demo2.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── sign ├── JustKiddingBaby.jks └── README.txt └── slidemenu ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── com │ └── jkb │ └── slidemenu │ ├── OnSlideChangedListener.java │ ├── SlideMenuAction.java │ └── SlideMenuLayout.java └── res └── values ├── attrs.xml └── strings.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | /.idea -------------------------------------------------------------------------------- /README-CN.md: -------------------------------------------------------------------------------- 1 | # SlideMenuLayout 2 | ## 简介 3 | 一个支持左右滑动并带有视差滑动效果的安卓滑动菜单控件。 4 | [![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html) 5 | 6 | [![SDK](https://img.shields.io/badge/API-12%2B-green.svg?style=flat)](https://android-arsenal.com/api?level=11) 7 | 8 | ## 演示 9 | 封装不同场景下的滑动嵌套 10 | 11 | 12 | ## 特性 13 | - [x] **支持滑动方向的配置** 14 | - [x] **直接作为控件使用** 15 | - [x] **处理各个场景下的滑动冲突** 16 | - [x] **侧滑菜单打开时候点击主体布局关闭侧滑菜单(可配置)** 17 | - [x] **侧滑菜单打开/关闭的时候主体布局暗度自动变化(可配置)** 18 | - [x] **支持滑动视差效果(可配置)** 19 | 20 | ## 最新版本 21 | |模块|slideMenuLayout| 22 | |---|---| 23 | |最新版本|![Download](https://api.bintray.com/packages/jkb/maven/slidemenu/images/download.svg)| 24 | 25 | ## 集成 26 | #### Maven集成 27 | ```xml 28 | 29 | com.justkiddingbaby 30 | slidemenu 31 | 最新版本 32 | pom 33 | 34 | ``` 35 | #### JCenter集成 36 | 第一步 在项目build.gradle中添加 37 | ```gradle 38 | repositories { 39 | jcenter() 40 | } 41 | ``` 42 | 第一步 在module的build.gradle中添加 43 | ```gradle 44 | compile 'com.justkiddingbaby:slidemenu:最新版本' 45 | ``` 46 | 47 | ## 属性说明 48 | |属性|说明|值| 49 | |---|---|---| 50 | |[slideMode](/slidemenu/src/main/res/values/attrs.xml)|滑动模式|left right both none| 51 | |[slidePadding](/slidemenu/src/main/res/values/attrs.xml)|滑动菜单打开时候主视图预留边界|dimension| 52 | |[slideTime](/slidemenu/src/main/res/values/attrs.xml)|滑动菜单单开的时间,默认800ms|integer| 53 | |[parallax](/slidemenu/src/main/res/values/attrs.xml)|是否允許滑动视差效果,默认true|boolean| 54 | |[contentAlpha](/slidemenu/src/main/res/values/attrs.xml)|设置侧滑菜单打开时候ContentView的阴影透明度(范围0 92 | 93 | 94 | 95 | 96 | ``` 97 | #### 注意 98 | **[SlideMenuLayout](/slidemenu/src/main/java/com/jkb/slidemenu/SlideMenuLayout.java)中布局的顺序是侧滑菜单布局在前,主体内容在后(为了防止右滑菜单重叠问题)。** 99 | 要是slideMode为both时,则SlideMenuLayout必须要有三个子视图,否则会抛出异常。 100 | 101 | ## 发布历史 102 | #### v1.3.0(2017/12/25) 103 | 1、添加特性:添加禁止拖动菜单(只能通过打开/关闭/切换方法打开)支持. 104 | 2、添加特性:添加菜单打开变化时候的监听器. 105 | #### v1.2.2(2017/12/18) 106 | 1、修复[issue#5](https://github.com/JustKiddingBaby/SlideMenuLayout/issues/5) 107 | #### v1.2.1(2017/9/18) 108 | 1、当`contentToggle`属性的值为`true`时,拦截`content view`的touch事件. 109 | #### v1.2.0(2017/8/20) 110 | 1、添加特性:侧滑菜单打开时候点击主体布局关闭侧滑菜单(可配置). 111 | 2、添加特性:侧滑菜单打开/关闭的时候主体布局暗度自动变化(可配置). 112 | 3、添加特性:支持滑动视差效果(可配置). 113 | #### v1.0.1(2017/6/9) 114 | 1、修改最低版本SDK为12. 115 | #### v1.0.0(2017/6/8) 116 | 1、发布SlideMenuLayout,处理各个场景下的滑动冲突。 117 | 2、封装demo。 118 | 119 | ## License 120 | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/License_icon-mit-88x31-2.svg/128px-License_icon-mit-88x31-2.svg.png) 121 | 122 | 本框架遵循MIT开源协议. 浏览[LICENSE](https://opensource.org/licenses/MIT)查看更多信息. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SlideMenuLayout 2 | ## Introduction 3 | An android slide menu that supports left and right swipes and slides with parallax. 4 | 一个支持左右滑动并带有视差滑动效果的安卓滑动菜单控件。([中文版入口](README-CN.md)) 5 | [![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html) 6 | 7 | [![SDK](https://img.shields.io/badge/API-12%2B-green.svg?style=flat)](https://android-arsenal.com/api?level=11) 8 | 9 | ## Demo 10 | Encapsulate the sliding nesting of different scenarios. 11 | 12 | 13 | ## Features 14 | - [x] **Support for sliding direction configuration** 15 | - [x] **Can be used as ``ViewGroup``** 16 | - [x] **Handle the sliding conflicts in each scenarios** 17 | - [x] **Option to click on content view to close menu when it's opening** 18 | - [x] **Option to dim the content view automatically** 19 | - [x] **Option to toggle the parallax effect** 20 | 21 | ## Version 22 | |name|SlideMenuLayout| 23 | |---|---| 24 | |latest|![Download](https://api.bintray.com/packages/jkb/maven/slidemenu/images/download.svg)| 25 | 26 | ## Configure 27 | #### Maven 28 | ```xml 29 | 30 | com.justkiddingbaby 31 | slidemenu 32 | the latest version 33 | pom 34 | 35 | ``` 36 | #### JCenter 37 | First. add to project build.gradle 38 | ```gradle 39 | repositories { 40 | jcenter() 41 | } 42 | ``` 43 | Second. add to module build.gradle 44 | ```gradle 45 | compile 'com.justkiddingbaby:slidemenu:the latest version' 46 | ``` 47 | 48 | ## Attributes instruction 49 | |attribute|instruction|value| 50 | |---|---|---| 51 | |[slideMode](/slidemenu/src/main/res/values/attrs.xml)|sliding mode|left right both none| 52 | |[slidePadding](/slidemenu/src/main/res/values/attrs.xml)|the content view padding when slide menu is opened|dimension| 53 | |[slideTime](/slidemenu/src/main/res/values/attrs.xml)|the time of slide menu open,the default value is 800ms|integer| 54 | |[parallax](/slidemenu/src/main/res/values/attrs.xml)|option to toggle the parallax effect,default is true|boolean| 55 | |[contentAlpha](/slidemenu/src/main/res/values/attrs.xml)|the alpha of shadow for `ContentView` when menu is opened.(0 93 | 94 | 95 | 96 | 97 | ``` 98 | #### Mind 99 | **when you use [SlideMenuLayout](/slidemenu/src/main/java/com/jkb/slidemenu/SlideMenuLayout.java) in layout,it can only host three child view,and the left slide menu view and the right slide menu view must add before the content view (for prevent the right slide menu from overlapping).** 100 | if slideMode is both then the SlideViewLayout must host three child views. 101 | 102 | ## Release history 103 | #### v1.3.0(2017/12/25) 104 | 1、Add feature: Enables or disables dragging for this view. 105 | 2、Add feature: Add listener to register a callback to be invoked when this slide is changed. 106 | #### v1.2.2(2017/12/18) 107 | 1、Fix [issue#5](https://github.com/JustKiddingBaby/SlideMenuLayout/issues/5) 108 | #### v1.2.1(2017/9/18) 109 | 1、Intercept the touch action of `content view` when `contentToggle` attribute's value is true. 110 | #### v1.2.0(2017/8/20) 111 | 1、Add feature: Option to click on content view to close menu when it's opening. 112 | 2、Add feature: Option to dim the content view automatically. 113 | 3、Add feature: Option to toggle the parallax effect. 114 | #### v1.0.1(2017/6/29) 115 | 1、Update minSdkVersion to SDK 12. 116 | #### v1.0.0(2017/6/8) 117 | 1、Release SlideMenuLayout,Handle the sliding conflicts in each scenarios. 118 | 2、Encapsulation demo. 119 | 120 | ## License 121 | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/License_icon-mit-88x31-2.svg/128px-License_icon-mit-88x31-2.svg.png) 122 | 123 | This library is available under the MIT license. See the [LICENSE](https://opensource.org/licenses/MIT) file for more info. -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | 5 | compileSdkVersion rootProject.ext.android.compileSdkVersion 6 | buildToolsVersion rootProject.ext.android.buildToolsVersion 7 | 8 | defaultConfig { 9 | applicationId rootProject.ext.app.applicationId 10 | minSdkVersion rootProject.ext.android.minSdkVersion 11 | targetSdkVersion rootProject.ext.android.targetSdkVersion 12 | versionCode rootProject.ext.app.versionCode 13 | versionName rootProject.ext.app.versionName 14 | } 15 | 16 | compileOptions { 17 | sourceCompatibility rootProject.ext.android.sourceCompatibilityVersion 18 | targetCompatibility rootProject.ext.android.targetCompatibilityVersion 19 | } 20 | 21 | signingConfigs { 22 | myConfig { 23 | storeFile file(rootProject.ext.store.storeKey) 24 | storePassword rootProject.ext.store.storePassword 25 | keyAlias rootProject.ext.store.keyAlias 26 | keyPassword rootProject.ext.store.keyPassword 27 | v2SigningEnabled false 28 | } 29 | } 30 | 31 | buildTypes { 32 | release { 33 | minifyEnabled true 34 | //是否清理无用资源 35 | shrinkResources true 36 | //是否启用zipAlign压缩 37 | zipAlignEnabled true 38 | signingConfig signingConfigs.myConfig 39 | versionNameSuffix rootProject.ext.app.versionNameSuffix 40 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 41 | } 42 | debug { 43 | signingConfig signingConfigs.myConfig 44 | versionNameSuffix rootProject.ext.app.versionNameSuffix 45 | } 46 | } 47 | 48 | lintOptions { 49 | abortOnError false 50 | } 51 | } 52 | 53 | dependencies { 54 | compile rootProject.ext.dependencies.design 55 | compile project(":slidemenu") 56 | } 57 | -------------------------------------------------------------------------------- /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 /home/yangjing/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.design.widget.TabLayout; 6 | import android.support.v4.view.ViewPager; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.view.WindowManager; 13 | 14 | import com.jkb.slidemenu.OnSlideChangedListener; 15 | import com.jkb.slidemenu.SlideMenuLayout; 16 | import com.jkb.slidemenulayout.adapter.ContentAdapter; 17 | import com.jkb.slidemenulayout.adapter.SlideLeftAdapter; 18 | import com.jkb.slidemenulayout.adapter.SlideRightMenuAdapter; 19 | 20 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 21 | 22 | private String TAG = this.getClass().getSimpleName(); 23 | //ui 24 | private SlideMenuLayout slideMenuLayout; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main); 30 | initStatusBar(); 31 | initView(); 32 | } 33 | 34 | /** 35 | * 初始化View 36 | */ 37 | private void initView() { 38 | slideMenuLayout = (SlideMenuLayout) findViewById(R.id.mainSlideMenu); 39 | 40 | //right 41 | TabLayout slideTabLayout = (TabLayout) findViewById(R.id.fmr_tab); 42 | ViewPager slideViewPager = (ViewPager) findViewById(R.id.fmr_vp); 43 | slideTabLayout.addTab(slideTabLayout.newTab()); 44 | slideTabLayout.addTab(slideTabLayout.newTab()); 45 | slideViewPager.setAdapter(new SlideRightMenuAdapter(getSupportFragmentManager())); 46 | slideTabLayout.setupWithViewPager(slideViewPager); 47 | //left 48 | RecyclerView leftRecyclerView = (RecyclerView) findViewById(R.id.cml_rv); 49 | leftRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 50 | SlideLeftAdapter slideLeftAdapter = new SlideLeftAdapter(this); 51 | leftRecyclerView.setAdapter(slideLeftAdapter); 52 | //content 53 | TabLayout contentTabLayout = (TabLayout) findViewById(R.id.am_tab); 54 | ViewPager contentViewPager = (ViewPager) findViewById(R.id.am_vp); 55 | contentTabLayout.addTab(contentTabLayout.newTab()); 56 | contentTabLayout.addTab(contentTabLayout.newTab()); 57 | contentViewPager.setAdapter(new ContentAdapter(getSupportFragmentManager())); 58 | contentTabLayout.setupWithViewPager(contentViewPager); 59 | 60 | findViewById(R.id.fm_leftMenu).setOnClickListener(this); 61 | findViewById(R.id.fm_rightMenu).setOnClickListener(this); 62 | slideMenuLayout.addOnSlideChangedListener(new OnSlideChangedListener() { 63 | @Override 64 | public void onSlideChanged(SlideMenuLayout slideMenu, boolean isLeftSlideOpen, boolean isRightSlideOpen) { 65 | Log.d(TAG, "onSlideChanged:isLeftSlideOpen=" + isLeftSlideOpen + ":isRightSlideOpen=" + isRightSlideOpen); 66 | } 67 | }); 68 | } 69 | 70 | /** 71 | * 初始化沉浸式状态栏 72 | */ 73 | private void initStatusBar() { 74 | //设置是否沉浸式 75 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; 76 | int flag_translucent_status = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 77 | //透明状态栏 78 | getWindow().setFlags(flag_translucent_status, flag_translucent_status); 79 | } 80 | 81 | @Override 82 | public void onClick(View v) { 83 | switch (v.getId()) { 84 | case R.id.fm_leftMenu: 85 | slideMenuLayout.toggleLeftSlide(); 86 | break; 87 | case R.id.fm_rightMenu: 88 | slideMenuLayout.toggleRightSlide(); 89 | break; 90 | } 91 | } 92 | 93 | @Override 94 | public void onBackPressed() { 95 | if (slideMenuLayout.isLeftSlideOpen() || slideMenuLayout.isRightSlideOpen()) { 96 | slideMenuLayout.closeLeftSlide(); 97 | slideMenuLayout.closeRightSlide(); 98 | } else { 99 | super.onBackPressed(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/adapter/ContentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | 7 | import com.jkb.slidemenulayout.ui.ChatFragment; 8 | import com.jkb.slidemenulayout.ui.FriendFragment; 9 | import com.jkb.slidemenulayout.ui.TabOneFragment; 10 | import com.jkb.slidemenulayout.ui.TabTwoFragment; 11 | 12 | /** 13 | * 右滑菜单适配器 14 | * Created by yangjing on 17-6-7. 15 | */ 16 | 17 | public class ContentAdapter extends FragmentPagerAdapter { 18 | 19 | private String[] menuNames = new String[]{ 20 | "One", "Two" 21 | }; 22 | 23 | public ContentAdapter(FragmentManager fm) { 24 | super(fm); 25 | } 26 | 27 | @Override 28 | public Fragment getItem(int position) { 29 | if (position == 0) { 30 | return TabOneFragment.newInstance(); 31 | } else { 32 | return TabTwoFragment.newInstance(); 33 | } 34 | } 35 | 36 | @Override 37 | public int getCount() { 38 | return menuNames.length; 39 | } 40 | 41 | @Override 42 | public CharSequence getPageTitle(int position) { 43 | return menuNames[position]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/adapter/FriendAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.jkb.slidemenulayout.R; 11 | 12 | /** 13 | * 好友列表的数据适配器 14 | * Created by yangjing on 17-6-8. 15 | */ 16 | 17 | public class FriendAdapter extends RecyclerView.Adapter { 18 | 19 | private Context context; 20 | 21 | public FriendAdapter(Context context) { 22 | this.context = context; 23 | } 24 | 25 | @Override 26 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 27 | View view = LayoutInflater.from(context).inflate(R.layout.item_friend, parent, false); 28 | return new ViewHolder(view); 29 | } 30 | 31 | @Override 32 | public void onBindViewHolder(ViewHolder holder, int position) { 33 | holder.tvFriend.setText("friend" + position); 34 | } 35 | 36 | @Override 37 | public int getItemCount() { 38 | return 20; 39 | } 40 | 41 | class ViewHolder extends RecyclerView.ViewHolder { 42 | 43 | TextView tvFriend; 44 | 45 | public ViewHolder(View itemView) { 46 | super(itemView); 47 | tvFriend = (TextView) itemView.findViewById(R.id.if_tv); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/adapter/SlideLeftAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.jkb.slidemenulayout.R; 11 | 12 | /** 13 | * 好友列表的数据适配器 14 | * Created by yangjing on 17-6-8. 15 | */ 16 | 17 | public class SlideLeftAdapter extends RecyclerView.Adapter { 18 | 19 | private Context context; 20 | 21 | public SlideLeftAdapter(Context context) { 22 | this.context = context; 23 | } 24 | 25 | @Override 26 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 27 | View view = LayoutInflater.from(context).inflate(R.layout.item_friend, parent, false); 28 | return new ViewHolder(view); 29 | } 30 | 31 | @Override 32 | public void onBindViewHolder(ViewHolder holder, int position) { 33 | holder.tvFriend.setText("menu" + position); 34 | } 35 | 36 | @Override 37 | public int getItemCount() { 38 | return 20; 39 | } 40 | 41 | class ViewHolder extends RecyclerView.ViewHolder { 42 | 43 | TextView tvFriend; 44 | 45 | public ViewHolder(View itemView) { 46 | super(itemView); 47 | tvFriend = (TextView) itemView.findViewById(R.id.if_tv); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/adapter/SlideRightMenuAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | 7 | import com.jkb.slidemenulayout.ui.ChatFragment; 8 | import com.jkb.slidemenulayout.ui.FriendFragment; 9 | 10 | /** 11 | * 右滑菜单适配器 12 | * Created by yangjing on 17-6-7. 13 | */ 14 | 15 | public class SlideRightMenuAdapter extends FragmentPagerAdapter { 16 | 17 | private String[] menuNames = new String[]{ 18 | "chat", "friend" 19 | }; 20 | 21 | public SlideRightMenuAdapter(FragmentManager fm) { 22 | super(fm); 23 | } 24 | 25 | @Override 26 | public Fragment getItem(int position) { 27 | if (position == 0) { 28 | return ChatFragment.newInstance(); 29 | } else { 30 | return FriendFragment.newInstance(); 31 | } 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return menuNames.length; 37 | } 38 | 39 | @Override 40 | public CharSequence getPageTitle(int position) { 41 | return menuNames[position]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/adapter/TabTwoAdapter.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.jkb.slidemenulayout.R; 11 | 12 | /** 13 | * TabTwo的数据适配器 14 | * Created by yangjing on 17-6-8. 15 | */ 16 | 17 | public class TabTwoAdapter extends RecyclerView.Adapter { 18 | 19 | private Context context; 20 | 21 | public TabTwoAdapter(Context context) { 22 | this.context = context; 23 | } 24 | 25 | @Override 26 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 27 | View view = LayoutInflater.from(context).inflate(R.layout.item_tab_two, parent, false); 28 | return new ViewHolder(view); 29 | } 30 | 31 | @Override 32 | public void onBindViewHolder(ViewHolder holder, int position) { 33 | holder.tvFriend.setText("Tab two item" + position); 34 | } 35 | 36 | @Override 37 | public int getItemCount() { 38 | return 20; 39 | } 40 | 41 | class ViewHolder extends RecyclerView.ViewHolder { 42 | 43 | TextView tvFriend; 44 | 45 | public ViewHolder(View itemView) { 46 | super(itemView); 47 | tvFriend = (TextView) itemView.findViewById(R.id.if_tv); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/ui/ChatFragment.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.ui; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.jkb.slidemenulayout.R; 11 | 12 | /** 13 | * 好友列表 14 | * Created by yangjing on 17-6-7. 15 | */ 16 | 17 | public class ChatFragment extends Fragment { 18 | 19 | public static ChatFragment newInstance() { 20 | Bundle args = new Bundle(); 21 | ChatFragment fragment = new ChatFragment(); 22 | fragment.setArguments(args); 23 | return fragment; 24 | } 25 | 26 | @Nullable 27 | @Override 28 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 29 | View rootView = inflater.inflate(R.layout.frg_chat, container, false); 30 | return rootView; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/ui/FriendFragment.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.ui; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.jkb.slidemenulayout.R; 14 | import com.jkb.slidemenulayout.adapter.FriendAdapter; 15 | 16 | /** 17 | * 好友列表 18 | * Created by yangjing on 17-6-7. 19 | */ 20 | 21 | public class FriendFragment extends Fragment { 22 | 23 | public static FriendFragment newInstance() { 24 | Bundle args = new Bundle(); 25 | FriendFragment fragment = new FriendFragment(); 26 | fragment.setArguments(args); 27 | return fragment; 28 | } 29 | 30 | //ui 31 | private Context mContext; 32 | 33 | @Nullable 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 36 | View rootView = inflater.inflate(R.layout.frg_friend, container, false); 37 | RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.ff_rv); 38 | recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)); 39 | FriendAdapter friendAdapter = new FriendAdapter(mContext); 40 | recyclerView.setAdapter(friendAdapter); 41 | return rootView; 42 | } 43 | 44 | @Override 45 | public void onAttach(Context context) { 46 | super.onAttach(context); 47 | mContext = context; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/ui/TabOneFragment.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.ui; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.jkb.slidemenulayout.R; 11 | 12 | /** 13 | * TabOne 14 | * Created by yangjing on 17-6-7. 15 | */ 16 | 17 | public class TabOneFragment extends Fragment { 18 | 19 | public static TabOneFragment newInstance() { 20 | Bundle args = new Bundle(); 21 | TabOneFragment fragment = new TabOneFragment(); 22 | fragment.setArguments(args); 23 | return fragment; 24 | } 25 | 26 | @Nullable 27 | @Override 28 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 29 | View rootView = inflater.inflate(R.layout.frg_tab_one, container, false); 30 | return rootView; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/jkb/slidemenulayout/ui/TabTwoFragment.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenulayout.ui; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.jkb.slidemenulayout.R; 14 | import com.jkb.slidemenulayout.adapter.FriendAdapter; 15 | import com.jkb.slidemenulayout.adapter.TabTwoAdapter; 16 | 17 | /** 18 | * TabTwo 19 | * Created by yangjing on 17-6-7. 20 | */ 21 | 22 | public class TabTwoFragment extends Fragment { 23 | 24 | public static TabTwoFragment newInstance() { 25 | Bundle args = new Bundle(); 26 | TabTwoFragment fragment = new TabTwoFragment(); 27 | fragment.setArguments(args); 28 | return fragment; 29 | } 30 | 31 | //ui 32 | private Context mContext; 33 | 34 | @Nullable 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 37 | View rootView = inflater.inflate(R.layout.frg_tab_two, container, false); 38 | RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.ff_rv); 39 | recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)); 40 | TabTwoAdapter tabTwoAdapter = new TabTwoAdapter(mContext); 41 | recyclerView.setAdapter(tabTwoAdapter); 42 | return rootView; 43 | } 44 | 45 | @Override 46 | public void onAttach(Context context) { 47 | super.onAttach(context); 48 | mContext = context; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_conversations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/drawable-xxhdpi/ic_action_conversations.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/drawable-xxhdpi/ic_action_menu.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 35 | 36 | 39 | 40 | 49 | 50 | 59 | 60 | 69 | 70 | 71 | 72 | 84 | 85 | 86 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_menu_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_menu_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 20 | 31 | 32 | 33 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/frg_chat.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/frg_friend.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/frg_tab_one.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/frg_tab_two.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_friend.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_tab_two.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-v19/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-v20/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-v22/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-v23/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-v24/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values-v25/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #bd3e27 5 | #702314 6 | #bd3e27 7 | 8 | #00FFFFFF 9 | #e7e7e7 10 | #fdfdfe 11 | #333333 12 | #999999 13 | 14 | 15 | #FFFFFF 16 | #000000 17 | #C0C0C0 18 | #FF0000 19 | #2b8ad6 20 | #26292b 21 | 22 | 23 | #666666 24 | #999999 25 | #fbba39 26 | #83b6f7 27 | 28 | 29 | #1a000000 30 | #46000000 31 | #46FFFFFF 32 | #1EFFFFFF 33 | #99ffffff 34 | #55c0c0c0 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SlideMenuLayout 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 13 | 14 | 15 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | apply from: "config.gradle" 4 | 5 | buildscript { 6 | repositories { 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:2.3.2' 11 | 12 | classpath 'com.novoda:bintray-release:0.3.4' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | jcenter() 22 | maven { url 'https://jitpack.io' } 23 | } 24 | tasks.withType(Javadoc) { 25 | options.addStringOption('Xdoclint:none', '-quiet') 26 | options.addStringOption('encoding', 'UTF-8') 27 | } 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /config.gradle: -------------------------------------------------------------------------------- 1 | import java.util.regex.Matcher 2 | import java.util.regex.Pattern 3 | 4 | ext { 5 | app = [ 6 | appVerCode : 1, 7 | appVerName : "0.0.1" + "-${releaseTime()}", 8 | applicationId : "com.jkb.supportfragment.demo", 9 | versionNameSuffix: getCurrentVersionSuffix(), 10 | minSdkVersion : 14 11 | ] 12 | 13 | slidemenu = [ 14 | publishCode : 6, 15 | publishVersion: "1.3.0", 16 | 17 | userOrg : 'jkb', 18 | groupId : 'com.justkiddingbaby', 19 | artifactId : 'slidemenu', 20 | desc : 'An Android slide menu layout that support left slide and right slide.', 21 | website : 'https://github.com/YangJing96/SlideMenuLayout' 22 | ] 23 | 24 | android = [ 25 | minSdkVersion : 12, 26 | targetSdkVersion : 23, 27 | compileSdkVersion : 23, 28 | buildToolsVersion : "25.0.0", 29 | sourceCompatibilityVersion: JavaVersion.VERSION_1_7, 30 | targetCompatibilityVersion: JavaVersion.VERSION_1_7 31 | ] 32 | 33 | dependencies = [ 34 | appcompatV7: 'com.android.support:appcompat-v7:23.0.1', 35 | design : 'com.android.support:design:24.0.0', 36 | ] 37 | 38 | store = [ 39 | storeKey : '../sign/JustKiddingBaby.jks', 40 | storePassword: 'mimajiushiwo', 41 | keyAlias : 'JustKiddingBaby', 42 | keyPassword : 'mimajiushiwo' 43 | ] 44 | } 45 | 46 | def static releaseTime() { 47 | return new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+8")) 48 | } 49 | 50 | def getCurrentVersionSuffix() { 51 | def currentFlavor = getCurrentFlavor() 52 | if (currentFlavor == "prod") { 53 | return "-prod" 54 | } else if (currentFlavor == "uat") { 55 | return "-uat" 56 | } else if (currentFlavor == "dev") { 57 | return "-dev" 58 | } 59 | } 60 | 61 | def getCurrentFlavor() { 62 | String taskRequestName = getGradle().getStartParameter().getTaskRequests().toString() 63 | Pattern pattern; 64 | if (taskRequestName.contains("assemble")) { 65 | pattern = Pattern.compile("assemble(\\w+)(Release|Debug)") 66 | } else { 67 | pattern = Pattern.compile("generate(\\w+)(Release|Debug)") 68 | } 69 | Matcher matcher = pattern.matcher(taskRequestName) 70 | if (matcher.find()) { 71 | return matcher.group(1).toLowerCase() 72 | } else { 73 | return ""; 74 | } 75 | } -------------------------------------------------------------------------------- /gif/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/gif/demo.gif -------------------------------------------------------------------------------- /gif/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/gif/demo2.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 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 07 14:54:00 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 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':slidemenu' 2 | -------------------------------------------------------------------------------- /sign/JustKiddingBaby.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JingYeoh/SlideMenuLayout/4428467efc11cc62ba2aee15a38ec666fbfd8722/sign/JustKiddingBaby.jks -------------------------------------------------------------------------------- /sign/README.txt: -------------------------------------------------------------------------------- 1 | Password:mimajiushiwo 2 | Alians:JustKiddingBaby 3 | Password:mimajiushiwo -------------------------------------------------------------------------------- /slidemenu/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /slidemenu/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release' 3 | 4 | 5 | publish { 6 | userOrg = rootProject.ext.slidemenu.userOrg 7 | groupId = rootProject.ext.slidemenu.groupId 8 | artifactId = rootProject.ext.slidemenu.artifactId 9 | publishVersion = rootProject.ext.slidemenu.publishVersion 10 | desc = rootProject.ext.slidemenu.desc 11 | website = rootProject.ext.slidemenu.website 12 | } 13 | 14 | android { 15 | 16 | compileSdkVersion rootProject.ext.android.compileSdkVersion 17 | buildToolsVersion rootProject.ext.android.buildToolsVersion 18 | 19 | defaultConfig { 20 | minSdkVersion rootProject.ext.android.minSdkVersion 21 | targetSdkVersion rootProject.ext.android.targetSdkVersion 22 | versionCode rootProject.ext.slidemenu.publishCode 23 | versionName rootProject.ext.slidemenu.publishVersion 24 | } 25 | 26 | compileOptions { 27 | sourceCompatibility rootProject.ext.android.sourceCompatibilityVersion 28 | targetCompatibility rootProject.ext.android.targetCompatibilityVersion 29 | } 30 | 31 | buildTypes { 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | 38 | lintOptions { 39 | abortOnError false 40 | } 41 | } 42 | 43 | dependencies { 44 | compile rootProject.ext.dependencies.appcompatV7 45 | } 46 | -------------------------------------------------------------------------------- /slidemenu/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 /home/yangjing/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /slidemenu/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /slidemenu/src/main/java/com/jkb/slidemenu/OnSlideChangedListener.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenu; 2 | 3 | /** 4 | * 侧滑菜单变化时候的监听器. 5 | * 6 | * @author JingYeoh 7 | * Email me 8 | * Github 9 | * Blog 10 | * @since Dec 25,2017 11 | */ 12 | 13 | public interface OnSlideChangedListener { 14 | 15 | /** 16 | * 侧滑菜单状态变化 17 | * 18 | * @param slideMenu 侧滑菜单{@link SlideMenuLayout} 19 | * @param isLeftSlideOpen 左滑菜单是否打开 20 | * @param isRightSlideOpen 右滑菜单是否打开 21 | */ 22 | void onSlideChanged(SlideMenuLayout slideMenu, boolean isLeftSlideOpen, boolean isRightSlideOpen); 23 | } 24 | -------------------------------------------------------------------------------- /slidemenu/src/main/java/com/jkb/slidemenu/SlideMenuAction.java: -------------------------------------------------------------------------------- 1 | package com.jkb.slidemenu; 2 | 3 | import android.support.annotation.ColorRes; 4 | import android.support.annotation.FloatRange; 5 | import android.support.annotation.IntDef; 6 | import android.view.View; 7 | 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | 11 | /** 12 | * 侧滑菜单的动作 13 | * Created by JustKiddingBaby on 2017/6/3. 14 | */ 15 | 16 | public interface SlideMenuAction { 17 | 18 | /** 19 | * 只支持左侧滑 20 | */ 21 | int SLIDE_MODE_LEFT = 1001; 22 | /** 23 | * 只支持右侧滑 24 | */ 25 | int SLIDE_MODE_RIGHT = 1002; 26 | /** 27 | * 支持左侧滑和右侧滑 28 | */ 29 | int SLIDE_MODE_LEFT_RIGHT = 1003; 30 | /** 31 | * 左滑右滑均不支持 32 | */ 33 | int SLIDE_MODE_NONE = 1004; 34 | 35 | /** 36 | * set slide mode.(设置Slide模式) 37 | * 38 | * @param slideMode {@link #SLIDE_MODE_LEFT},{@link #SLIDE_MODE_LEFT_RIGHT}, 39 | * {@link #SLIDE_MODE_RIGHT},{@link #SLIDE_MODE_NONE} 40 | */ 41 | void setSlideMode(@SlideMode int slideMode); 42 | 43 | /** 44 | * 设置侧滑菜单打开时候距离主视图的padding 45 | * 46 | * @param slidePadding 单位px 47 | */ 48 | void setSlidePadding(int slidePadding); 49 | 50 | /** 51 | * 设置滑动菜单打开的时间 52 | * 53 | * @param slideTime 单位ms 54 | */ 55 | void setSlideTime(int slideTime); 56 | 57 | /** 58 | * 设置视差效果开关 59 | * 60 | * @param parallax 视差效果开关,Default:true 61 | */ 62 | void setParallaxSwitch(boolean parallax); 63 | 64 | /** 65 | * 设置在侧滑菜单打开时候的ContentView的透明度,该值会在侧滑的时候不断变化,从1.0变化至设置的值. 66 | * 67 | * @param contentAlpha 0 3) { 122 | throw new IllegalStateException("SlideMenuLayout can host only three direct child"); 123 | } 124 | super.addView(child); 125 | } 126 | 127 | @Override 128 | public void addView(View child, int index) { 129 | if (getChildCount() > 3) { 130 | throw new IllegalStateException("SlideMenuLayout can host only three direct child"); 131 | } 132 | super.addView(child, index); 133 | } 134 | 135 | @Override 136 | public void addView(View child, LayoutParams params) { 137 | if (getChildCount() > 3) { 138 | throw new IllegalStateException("SlideMenuLayout can host only three direct child"); 139 | } 140 | super.addView(child, params); 141 | } 142 | 143 | @Override 144 | public void addView(View child, int index, LayoutParams params) { 145 | if (getChildCount() > 3) { 146 | throw new IllegalStateException("SlideMenuLayout can host only three direct child"); 147 | } 148 | super.addView(child, index, params); 149 | } 150 | 151 | @Override 152 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 153 | //默认全屏 154 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 155 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 156 | int widthResult = 0; 157 | if (widthMode == MeasureSpec.EXACTLY) { 158 | widthResult = widthSize; 159 | } else { 160 | widthResult = screenWidth; 161 | } 162 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 163 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 164 | int heightResult = 0; 165 | if (heightMode == MeasureSpec.EXACTLY) { 166 | heightResult = heightSize; 167 | } else { 168 | heightResult = screenHeight; 169 | } 170 | //初始化侧滑菜单 171 | initSlideView(widthResult, heightResult); 172 | 173 | measureSlideChild(mContentView, widthMeasureSpec, heightMeasureSpec); 174 | measureSlideChild(mLeftView, widthMeasureSpec, heightMeasureSpec); 175 | measureSlideChild(mRightView, widthMeasureSpec, heightMeasureSpec); 176 | 177 | setMeasuredDimension(mContentWidth, mContentHeight); 178 | } 179 | 180 | @Override 181 | protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 182 | boolean result = super.drawChild(canvas, child, drawingTime); 183 | if (child == mContentView) { 184 | int rX = Math.abs(getScrollX()); 185 | int alpha = 0; 186 | if (rX == 0) { 187 | alpha = 0; 188 | } else if (rX >= mSlideWidth) { 189 | alpha = (int) ((1.0f - mContentAlpha) * 255); 190 | } else { 191 | alpha = (int) (Math.abs((1.0f - mContentAlpha) / mSlideWidth) * rX * 255); 192 | } 193 | alpha = alpha < 0 ? 255 : alpha; 194 | alpha = alpha > 255 ? 255 : alpha; 195 | 196 | mContentShadowPaint.setAlpha(alpha); 197 | canvas.drawRect(mContentView.getLeft(), mContentView.getTop(), mContentView.getRight(), 198 | mContentView.getBottom(), mContentShadowPaint);//画出阴影 199 | } 200 | return result; 201 | } 202 | 203 | @Override 204 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 205 | if (mLeftView != null) { 206 | mLeftView.layout(-mSlideWidth, 0, 0, mContentHeight); 207 | } 208 | if (mRightView != null) { 209 | mRightView.layout(mContentWidth, 0, mContentWidth + mSlideWidth, mContentHeight); 210 | } 211 | if (mContentView != null) { 212 | mContentView.layout(0, 0, mContentWidth, mContentHeight); 213 | } 214 | } 215 | 216 | @Override 217 | public void computeScroll() { 218 | super.computeScroll(); 219 | if (mScroller.computeScrollOffset()) { 220 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 221 | if (mLeftView != null) { 222 | leftMenuParallax(); 223 | } 224 | if (mRightView != null) { 225 | rightMenuParallax(); 226 | } 227 | postInvalidate(); 228 | changeContentViewAlpha(); 229 | } 230 | } 231 | 232 | @Override 233 | public boolean onInterceptTouchEvent(MotionEvent ev) { 234 | boolean intercept = false; 235 | int x = (int) ev.getX(); 236 | int y = (int) ev.getY(); 237 | switch (ev.getAction()) { 238 | case MotionEvent.ACTION_DOWN: 239 | intercept = false; 240 | break; 241 | case MotionEvent.ACTION_MOVE: 242 | int deltaX = (int) ev.getX() - mLastXIntercept; 243 | int deltaY = (int) ev.getY() - mLastYIntercept; 244 | if (Math.abs(deltaX) > Math.abs(deltaY)) {//横向滑动 245 | if (mTriggerSlideLeft) { 246 | intercept = x > mSlideWidth; 247 | } else if (mTriggerSlideRight) { 248 | intercept = x < mSlidePadding; 249 | } else { 250 | //当手指在边缘地区的时候拦截事件 251 | //以下判断条件主要为了区分边界滑动 252 | if (mSlideMode == SLIDE_MODE_LEFT && deltaX > 0) {//左滑 253 | intercept = x <= mSlidePadding / 2; 254 | } else if (mSlideMode == SLIDE_MODE_RIGHT && deltaX < 0) {//右滑 255 | intercept = x >= mSlideWidth - mSlidePadding / 2; 256 | } else if (mSlideMode == SLIDE_MODE_LEFT_RIGHT) {//双向滑动 257 | if (deltaX > 0) intercept = x <= mSlidePadding / 2; 258 | if (deltaX < 0) intercept = x >= mSlideWidth - mSlidePadding / 2; 259 | } else { 260 | intercept = false; 261 | } 262 | } 263 | } else {//纵向滑动 264 | intercept = false; 265 | } 266 | break; 267 | case MotionEvent.ACTION_UP: 268 | // intercept = false; 269 | //点击ContentView后关闭侧滑菜单 270 | intercept = touchContentViewToCloseSlide(); 271 | break; 272 | } 273 | mLastX = x; 274 | mLastXIntercept = x; 275 | mLastYIntercept = y; 276 | return intercept; 277 | } 278 | 279 | @Override 280 | public boolean onTouchEvent(MotionEvent event) { 281 | if (!mAllowDragging) return false; 282 | int action = event.getAction(); 283 | switch (action) { 284 | case MotionEvent.ACTION_DOWN: 285 | mLastX = (int) event.getX(); 286 | break; 287 | case MotionEvent.ACTION_MOVE: 288 | int currentX = (int) event.getX(); 289 | //拿到x方向的偏移量 290 | int dx = currentX - mLastX; 291 | if (dx < 0) {//向左滑动 292 | scrollLeft(dx); 293 | } else {//向右滑动 294 | scrollRight(dx); 295 | } 296 | mLastX = currentX; 297 | mDx = dx; 298 | break; 299 | case MotionEvent.ACTION_UP: 300 | case MotionEvent.ACTION_CANCEL: 301 | if (mDx > 0) {//右滑 302 | inertiaScrollRight(); 303 | } else { 304 | inertiaScrollLeft(); 305 | } 306 | mDx = 0; 307 | break; 308 | } 309 | return true; 310 | } 311 | 312 | /** 313 | * 点击ContentView后关闭侧滑菜单 314 | */ 315 | private boolean touchContentViewToCloseSlide() { 316 | if (!mContentToggle) return false; 317 | if (Math.abs(getScrollX()) < mSlideWidth) return false; 318 | int dX = getScrollX(); 319 | if (dX < 0) {//左滑菜单打开 320 | if (mLastX > mSlideWidth) { 321 | closeLeftSlide(); 322 | } else { 323 | return false; 324 | } 325 | } else if (dX > 0) { 326 | if (mLastX < (mContentWidth - mSlideWidth)) { 327 | closeRightSlide(); 328 | } else { 329 | return false; 330 | } 331 | } 332 | return true; 333 | } 334 | 335 | /** 336 | * 惯性左滑 337 | */ 338 | private void inertiaScrollLeft() { 339 | if (mSlideMode == SLIDE_MODE_RIGHT) { 340 | if (getScrollX() >= mSlideWidth / 2) { 341 | openRightSlide(); 342 | } else { 343 | if (!mTriggerSlideRight) { 344 | closeRightSlide(); 345 | } 346 | } 347 | } else if (mSlideMode == SLIDE_MODE_LEFT) { 348 | if (-getScrollX() <= mSlideWidth / 2) { 349 | closeLeftSlide(); 350 | } else { 351 | if (mTriggerSlideLeft) { 352 | openLeftSlide(); 353 | } 354 | } 355 | } else if (mSlideMode == SLIDE_MODE_LEFT_RIGHT) { 356 | if (!mTriggerSlideLeft && !mTriggerSlideRight) {//左右滑动菜单都关闭状态 357 | if (getScrollX() >= mSlideWidth / 2) { 358 | openRightSlide(); 359 | } else { 360 | closeRightSlide(); 361 | } 362 | } else if (mTriggerSlideLeft || getScrollX() < 0) { 363 | if (-getScrollX() <= mSlideWidth / 2) { 364 | closeLeftSlide(); 365 | } else { 366 | openLeftSlide(); 367 | } 368 | } 369 | } 370 | } 371 | 372 | /** 373 | * 惯性右滑 374 | */ 375 | private void inertiaScrollRight() { 376 | if (mSlideMode == SLIDE_MODE_LEFT) { 377 | if (-getScrollX() >= mSlideWidth / 2) { 378 | openLeftSlide(); 379 | } else { 380 | if (!mTriggerSlideLeft) { 381 | closeLeftSlide(); 382 | } 383 | } 384 | } else if (mSlideMode == SLIDE_MODE_RIGHT) { 385 | if (getScrollX() <= mSlideWidth / 2) { 386 | closeRightSlide(); 387 | } else { 388 | if (mTriggerSlideRight) { 389 | openRightSlide(); 390 | } 391 | } 392 | } else if (mSlideMode == SLIDE_MODE_LEFT_RIGHT) { 393 | if (!mTriggerSlideLeft && !mTriggerSlideRight) {//左右滑动菜单都关闭状态 394 | if (-getScrollX() >= mSlideWidth / 2) { 395 | openLeftSlide(); 396 | } else { 397 | closeLeftSlide(); 398 | } 399 | } else if (mTriggerSlideRight || getScrollX() > 0) { 400 | if (getScrollX() <= mSlideWidth / 2) { 401 | closeRightSlide(); 402 | } else { 403 | openRightSlide(); 404 | } 405 | } 406 | } 407 | } 408 | 409 | /** 410 | * 向左滑动 411 | */ 412 | private void scrollLeft(int dx) { 413 | if (mSlideMode == SLIDE_MODE_RIGHT) { 414 | //右滑菜单已经打开,不做操作 415 | if (mTriggerSlideRight || getScrollX() - dx >= mSlideWidth) { 416 | openRightSlide(); 417 | return; 418 | } 419 | rightMenuParallax(); 420 | } else if (mSlideMode == SLIDE_MODE_LEFT) { 421 | //左滑菜单未打开,不做操作 422 | if (!mTriggerSlideLeft || getScrollX() - dx >= 0) { 423 | closeLeftSlide(); 424 | return; 425 | } 426 | leftMenuParallax(); 427 | } else if (mSlideMode == SLIDE_MODE_LEFT_RIGHT) { 428 | //右滑菜单已经打开,不做操作 429 | if (mTriggerSlideRight || getScrollX() - dx >= mSlideWidth) { 430 | openRightSlide(); 431 | return; 432 | } 433 | leftMenuParallax(); 434 | rightMenuParallax(); 435 | } 436 | scrollBy(-dx, 0); 437 | changeContentViewAlpha(); 438 | } 439 | 440 | /** 441 | * 向右滑动 442 | */ 443 | private void scrollRight(int dx) { 444 | if (mSlideMode == SLIDE_MODE_LEFT) { 445 | //左滑菜单已经打开,不做操作 446 | if (mTriggerSlideLeft || getScrollX() - dx <= -mSlideWidth) { 447 | openLeftSlide(); 448 | return; 449 | } 450 | leftMenuParallax(); 451 | } else if (mSlideMode == SLIDE_MODE_RIGHT) { 452 | //右滑菜单未打开,不做操作 453 | if (!mTriggerSlideRight || getScrollX() - dx <= 0) { 454 | closeRightSlide(); 455 | return; 456 | } 457 | rightMenuParallax(); 458 | } else if (mSlideMode == SLIDE_MODE_LEFT_RIGHT) { 459 | //左滑菜单已经打开,不做操作 460 | if (mTriggerSlideLeft || getScrollX() - dx <= -mSlideWidth) { 461 | openLeftSlide(); 462 | return; 463 | } 464 | leftMenuParallax(); 465 | rightMenuParallax(); 466 | } 467 | scrollBy(-dx, 0); 468 | changeContentViewAlpha(); 469 | } 470 | 471 | /** 472 | * 改变ContentView的透明度 473 | */ 474 | private void changeContentViewAlpha() { 475 | /*int rX = Math.abs(getScrollX()); 476 | float alpha = 1.0f; 477 | if (rX == 0) { 478 | alpha = 1.0f; 479 | } else if (rX == mSlideWidth) { 480 | alpha = mContentAlpha; 481 | } else { 482 | alpha = Math.abs(1.0f - ((1.0f - mContentAlpha) / mSlideWidth) * rX); 483 | } 484 | alpha = alpha < 0.1f ? 0.1f : alpha; 485 | alpha = alpha > 1.0f ? 1.0f : alpha; 486 | mContentView.setAlpha(alpha);*/ 487 | postInvalidate(); 488 | } 489 | 490 | /** 491 | * 右滑菜单的视差效果 492 | */ 493 | private void rightMenuParallax() { 494 | if (!mParallax) return; 495 | int rightTranslationX = 2 * (-mSlideWidth + getScrollX()) / 3; 496 | //有菜单打开或者关闭的时候回恢复原位X 497 | if (getScrollX() == 0 || getScrollX() == mSlideWidth || getScrollX() == -mSlideWidth) { 498 | rightTranslationX = 0; 499 | } 500 | mRightView.setTranslationX(rightTranslationX); 501 | } 502 | 503 | /** 504 | * 左滑菜单的视差效果 505 | */ 506 | private void leftMenuParallax() { 507 | if (!mParallax) return; 508 | int leftTranslationX = 2 * (mSlideWidth + getScrollX()) / 3; 509 | //有菜单打开或者关闭的时候回恢复原位 510 | if (getScrollX() == 0 || getScrollX() >= mSlideWidth || getScrollX() <= -mSlideWidth) { 511 | leftTranslationX = 0; 512 | } 513 | mLeftView.setTranslationX(leftTranslationX); 514 | } 515 | 516 | /** 517 | * 缓慢滑动 518 | */ 519 | private void smoothScrollTo(int destX, int destY) { 520 | int scrollX = getScrollX(); 521 | int deltaX = destX - scrollX; 522 | float time = deltaX * 1.0f / (mSlideWidth * 1.0f / mSlideTime); 523 | time = Math.abs(time); 524 | mScroller.startScroll(scrollX, 0, deltaX, destY, (int) time); 525 | invalidate(); 526 | //Update listener 527 | if (mSlideChangedListener != null) { 528 | if (destX == -mSlideWidth) {//左滑打开 529 | mSlideChangedListener.onSlideChanged(this, true, false); 530 | } else if (destX == 0) {//关闭侧滑 531 | mSlideChangedListener.onSlideChanged(this, false, false); 532 | } else if (destX == mSlideWidth) {//右滑打开 533 | mSlideChangedListener.onSlideChanged(this, false, true); 534 | } 535 | } 536 | } 537 | 538 | /** 539 | * 测量子视图 540 | */ 541 | private void measureSlideChild(View childView, int widthMeasureSpec, int heightMeasureSpec) { 542 | if (childView == null) return; 543 | LayoutParams lp = childView.getLayoutParams(); 544 | int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, 545 | getPaddingLeft() + getPaddingRight(), lp.width); 546 | int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, 547 | getPaddingTop() + getPaddingBottom(), lp.height); 548 | childView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 549 | } 550 | 551 | /** 552 | * 初始化SlideMenu的视图 553 | */ 554 | private void initSlideView(int widthResult, int heightResult) { 555 | if (getChildCount() == 0) { 556 | throw new IllegalStateException("SlideMenuLayout must host one direct child"); 557 | } 558 | mSlideWidth = widthResult - mSlidePadding; 559 | mContentWidth = widthResult; 560 | mContentHeight = heightResult; 561 | switch (getChildCount()) { 562 | case 1: 563 | mSlideMode = SLIDE_MODE_NONE; 564 | mContentView = getChildAt(0); 565 | break; 566 | case 2: 567 | if (mSlideMode == SLIDE_MODE_LEFT) { 568 | mLeftView = getChildAt(0); 569 | mContentView = getChildAt(1); 570 | } else if (mSlideMode == SLIDE_MODE_RIGHT) { 571 | mRightView = getChildAt(0); 572 | mContentView = getChildAt(1); 573 | } else { 574 | throw new IllegalStateException("SlideMenuLayout must host only three direct child when slideMode" + 575 | " " + 576 | "is both"); 577 | } 578 | break; 579 | case 3: 580 | mLeftView = getChildAt(0); 581 | mRightView = getChildAt(1); 582 | mContentView = getChildAt(2); 583 | break; 584 | } 585 | if (mLeftView != null) { 586 | mLeftView.getLayoutParams().width = mSlideWidth; 587 | } 588 | if (mRightView != null) { 589 | mRightView.getLayoutParams().width = mSlideWidth; 590 | } 591 | 592 | LayoutParams contentParams = mContentView.getLayoutParams(); 593 | contentParams.width = widthResult; 594 | contentParams.height = heightResult; 595 | } 596 | 597 | @Override 598 | public void setSlideMode(@SlideMode int slideMode) { 599 | switch (slideMode) { 600 | case SLIDE_MODE_LEFT: 601 | closeRightSlide(); 602 | break; 603 | case SLIDE_MODE_RIGHT: 604 | closeLeftSlide(); 605 | break; 606 | case SLIDE_MODE_NONE: 607 | closeLeftSlide(); 608 | closeRightSlide(); 609 | break; 610 | } 611 | mSlideMode = slideMode; 612 | } 613 | 614 | @Override 615 | public void setSlidePadding(int slidePadding) { 616 | mSlidePadding = slidePadding; 617 | } 618 | 619 | @Override 620 | public void setSlideTime(int slideTime) { 621 | mSlideTime = slideTime; 622 | } 623 | 624 | @Override 625 | public void setParallaxSwitch(boolean parallax) { 626 | mParallax = parallax; 627 | } 628 | 629 | @Override 630 | public void setContentAlpha(@FloatRange(from = 0f, to = 1.0f) float contentAlpha) { 631 | mContentAlpha = contentAlpha; 632 | } 633 | 634 | @Override 635 | public void setContentShadowColor(@ColorRes int color) { 636 | mContentShadowColor = color; 637 | if (mContentShadowPaint == null) initContentShadowPaint(); 638 | mContentShadowPaint.setColor(ContextCompat.getColor(getContext(), mContentShadowColor)); 639 | postInvalidate(); 640 | } 641 | 642 | @Override 643 | public void setContentToggle(boolean contentToggle) { 644 | mContentToggle = contentToggle; 645 | } 646 | 647 | @Override 648 | public void setAllowTogging(boolean allowTogging) { 649 | this.mAllowDragging = allowTogging; 650 | } 651 | 652 | @Override 653 | public View getSlideLeftView() { 654 | return mLeftView; 655 | } 656 | 657 | @Override 658 | public View getSlideRightView() { 659 | return mRightView; 660 | } 661 | 662 | @Override 663 | public View getSlideContentView() { 664 | return mContentView; 665 | } 666 | 667 | @Override 668 | public void toggleLeftSlide() { 669 | if (mTriggerSlideLeft) { 670 | closeLeftSlide(); 671 | } else { 672 | openLeftSlide(); 673 | } 674 | } 675 | 676 | @Override 677 | public void openLeftSlide() { 678 | if (mSlideMode == SLIDE_MODE_RIGHT || mSlideMode == SLIDE_MODE_NONE) return; 679 | mTriggerSlideLeft = true; 680 | smoothScrollTo(-mSlideWidth, 0); 681 | } 682 | 683 | @Override 684 | public void closeLeftSlide() { 685 | if (mSlideMode == SLIDE_MODE_RIGHT || mSlideMode == SLIDE_MODE_NONE) return; 686 | mTriggerSlideLeft = false; 687 | smoothScrollTo(0, 0); 688 | } 689 | 690 | @Override 691 | public boolean isLeftSlideOpen() { 692 | return mTriggerSlideLeft; 693 | } 694 | 695 | @Override 696 | public void toggleRightSlide() { 697 | if (mTriggerSlideRight) { 698 | closeRightSlide(); 699 | } else { 700 | openRightSlide(); 701 | } 702 | } 703 | 704 | @Override 705 | public void openRightSlide() { 706 | if (mSlideMode == SLIDE_MODE_LEFT || mSlideMode == SLIDE_MODE_NONE) return; 707 | mTriggerSlideRight = true; 708 | smoothScrollTo(mSlideWidth, 0); 709 | } 710 | 711 | @Override 712 | public void closeRightSlide() { 713 | if (mSlideMode == SLIDE_MODE_LEFT || mSlideMode == SLIDE_MODE_NONE) return; 714 | mTriggerSlideRight = false; 715 | smoothScrollTo(0, 0); 716 | } 717 | 718 | @Override 719 | public boolean isRightSlideOpen() { 720 | return mTriggerSlideRight; 721 | } 722 | 723 | @Override 724 | public void addOnSlideChangedListener(OnSlideChangedListener listener) { 725 | mSlideChangedListener = listener; 726 | } 727 | } 728 | -------------------------------------------------------------------------------- /slidemenu/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 | -------------------------------------------------------------------------------- /slidemenu/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SlideMenu 3 | 4 | --------------------------------------------------------------------------------