├── .gitattributes ├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── slidbacklib │ │ ├── App.java │ │ ├── ListDataActivity.java │ │ ├── MainActivity.java │ │ ├── ScrollActivity.java │ │ ├── WebViewActivity.java │ │ ├── commonadapter │ │ ├── ListViewAdapter.java │ │ ├── RecyclerAdapter.java │ │ └── viewholders │ │ │ ├── GodViewHolder.java │ │ │ ├── RecyclerViewHolder.java │ │ │ └── ViewHolderImpl.java │ │ └── utils │ │ ├── SlideBackLayoutUtils.java │ │ └── StringUtils.java │ └── res │ ├── drawable-xxhdpi │ ├── icon_title_back.png │ ├── icon_titlebar_close.png │ ├── percent_arrow.png │ └── title_back_icon.png │ ├── drawable │ ├── person_item_selector.xml │ └── webview_progress_style.xml │ ├── layout │ ├── activity_list_data.xml │ ├── activity_main.xml │ ├── activity_scroll_view.xml │ ├── activity_web_view.xml │ └── item_list_data.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── config.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── sideBackLibrary ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── com │ └── slideback │ ├── ActivityHelper.java │ ├── SlideBackHelper.java │ ├── SlideConfig.java │ ├── callbak │ ├── OnInternalStateListener.java │ ├── OnSlideListener.java │ └── OnSlideListenerAdapter.java │ └── widget │ ├── CacheDrawView.java │ ├── ShadowView.java │ └── SlideBackLayout.java └── res ├── anim ├── anim_out_none.xml ├── sback_anim_activity_none.xml ├── sback_close_in.xml ├── sback_close_out.xml ├── sback_open_in.xml └── sback_open_out.xml ├── drawable └── sliding_back_shadow.xml ├── layout └── slide_back_default_layout.xml └── values ├── strings.xml └── styles.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android > Lint > Usability 39 | 40 | 41 | Code style issuesJava 42 | 43 | 44 | Encapsulation issuesJava 45 | 46 | 47 | Java 48 | 49 | 50 | Naming conventionsJava 51 | 52 | 53 | Resource management issuesJava 54 | 55 | 56 | 57 | 58 | Android 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 80 | 81 | 82 | 83 | 84 | 1.8 85 | 86 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | buildToolsVersion "26.0.2" 6 | defaultConfig { 7 | applicationId "com.slidbacklib" 8 | minSdkVersion 14 9 | targetSdkVersion 27 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile(rootProject.ext.dependencies["appcompat-v7"]) { 26 | exclude module: 'support-v4' 27 | } 28 | compile(rootProject.ext.dependencies["constraint-layout"]) { 29 | exclude module: 'support-annotations' 30 | exclude module: 'appcompat-v7' 31 | exclude module: 'support-v4' 32 | } 33 | compile rootProject.ext.dependencies["recyclerview-v7"] 34 | 35 | // compile rootProject.ext.dependencies["butterknife"] 36 | 37 | //滑动返回 38 | compile project(':sideBackLibrary') 39 | 40 | } 41 | -------------------------------------------------------------------------------- /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 E:\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 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/App.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.slideback.ActivityHelper; 7 | 8 | /** 9 | * =============================== 10 | * 描 述: 11 | * 作 者:pjw 12 | * 创建日期:2017/12/26 16:20 13 | * =============================== 14 | */ 15 | public class App extends Application { 16 | 17 | private ActivityHelper mActivityHelper; 18 | 19 | //当前app实例对象 20 | public static App sApp; 21 | //全局上下文对象 22 | public static Context sContext; 23 | 24 | 25 | @Override 26 | public void onCreate() { 27 | super.onCreate(); 28 | sApp = this; 29 | sContext = this; 30 | getActivityHelper(); 31 | } 32 | 33 | public ActivityHelper getActivityHelper() { 34 | if (mActivityHelper == null) { 35 | mActivityHelper = new ActivityHelper(); 36 | registerActivityLifecycleCallbacks(mActivityHelper); 37 | } 38 | return mActivityHelper; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/ListDataActivity.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | 10 | import com.slidbacklib.commonadapter.RecyclerAdapter; 11 | import com.slidbacklib.commonadapter.viewholders.RecyclerViewHolder; 12 | import com.slidbacklib.utils.SlideBackLayoutUtils; 13 | import com.slidbacklib.utils.StringUtils; 14 | 15 | /** 16 | * =============================== 17 | * 描 述: 18 | * 作 者:pjw 19 | * 创建日期:2017/12/26 16:01 20 | * =============================== 21 | */ 22 | public class ListDataActivity extends AppCompatActivity { 23 | 24 | @Override 25 | protected void onCreate(@Nullable Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_list_data); 28 | RecyclerView rvRecycler = (RecyclerView) findViewById(R.id.rvRecycler); 29 | rvRecycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 30 | RecyclerAdapter adapter = new RecyclerAdapter(R.layout.item_list_data) { 31 | @Override 32 | protected void onBindData(RecyclerViewHolder recyclerViewHolder, int i, String s) { 33 | } 34 | }; 35 | 36 | adapter.setOnItemClickListener(new RecyclerAdapter.OnItemClickListener() { 37 | @Override 38 | public void onItemClick(int i) { 39 | startActivity(new Intent(ListDataActivity.this, ScrollActivity.class)); 40 | } 41 | }); 42 | rvRecycler.setAdapter(adapter); 43 | adapter.clear(); 44 | adapter.addItems(StringUtils.getDatas(30)); 45 | 46 | SlideBackLayoutUtils.sideBack(this); 47 | } 48 | 49 | @Override 50 | protected void onDestroy() { 51 | SlideBackLayoutUtils.onDestroy(this); 52 | super.onDestroy(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.slidbacklib.utils.SlideBackLayoutUtils; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_main); 16 | 17 | findViewById(R.id.tvText).setOnClickListener(new View.OnClickListener() { 18 | @Override 19 | public void onClick(View v) { 20 | startActivity(new Intent(MainActivity.this, ListDataActivity.class)); 21 | } 22 | }); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/ScrollActivity.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | 9 | import com.slidbacklib.utils.SlideBackLayoutUtils; 10 | 11 | /** 12 | * =============================== 13 | * 描 述: 14 | * 作 者:pjw 15 | * 创建日期:2017/12/26 16:06 16 | * =============================== 17 | */ 18 | public class ScrollActivity extends AppCompatActivity { 19 | 20 | @Override 21 | protected void onCreate(@Nullable Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_scroll_view); 24 | findViewById(R.id.iView).setOnClickListener(new View.OnClickListener() { 25 | @Override 26 | public void onClick(View v) { 27 | // startActivity(new Intent(ScrollActivity.this, MainActivity.class)); 28 | startActivity(new Intent(ScrollActivity.this, WebViewActivity.class)); 29 | } 30 | }); 31 | // findViewById(R.id.iView1).setOnClickListener(new View.OnClickListener() { 32 | // @Override 33 | // public void onClick(View v) { 34 | // startActivity(new Intent(ScrollActivity.this, WebViewActivity.class)); 35 | // } 36 | // }); 37 | SlideBackLayoutUtils.sideBack(this); 38 | } 39 | 40 | 41 | @Override 42 | protected void onDestroy() { 43 | SlideBackLayoutUtils.onDestroy(this); 44 | super.onDestroy(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/WebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib; 2 | 3 | import android.content.Intent; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.webkit.WebChromeClient; 10 | import android.webkit.WebSettings; 11 | import android.webkit.WebView; 12 | import android.webkit.WebViewClient; 13 | import android.widget.ProgressBar; 14 | import android.widget.RelativeLayout; 15 | import android.widget.TextView; 16 | 17 | import com.slidbacklib.utils.SlideBackLayoutUtils; 18 | 19 | import static com.slidbacklib.R.id.tv_title_bar_right_text; 20 | 21 | /** 22 | * =============================== 23 | * 描 述: 24 | * 作 者:pjw 25 | * 创建日期:2017/12/26 16:09 26 | * =============================== 27 | */ 28 | public class WebViewActivity extends AppCompatActivity { 29 | 30 | TextView tvTitleBarRightText; 31 | WebView cdWebView; 32 | ProgressBar webviewProgressBar; 33 | RelativeLayout cdRootView; 34 | 35 | @Override 36 | protected void onCreate(@Nullable Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_web_view); 39 | 40 | cdWebView = (WebView) findViewById(R.id.cd_web_view); 41 | tvTitleBarRightText = (TextView) findViewById(R.id.tv_title_bar_right_text); 42 | webviewProgressBar = (ProgressBar) findViewById(R.id.webview_progress_bar); 43 | cdRootView = (RelativeLayout) findViewById(R.id.cd_root_view); 44 | findViewById(R.id.iv_web_title_bar_back).setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | finish(); 48 | } 49 | }); 50 | initData(); 51 | SlideBackLayoutUtils.sideBack(this); 52 | } 53 | 54 | private void initData() { 55 | initWebView(); 56 | cdWebView.setWebViewClient(mWebViewClient); 57 | cdWebView.setWebChromeClient(mWebChromeClient); 58 | cdWebView.loadUrl("https://www.baidu.com/"); 59 | 60 | tvTitleBarRightText.setVisibility(View.VISIBLE); 61 | tvTitleBarRightText.setText("跳转页面"); 62 | tvTitleBarRightText.setOnClickListener(new View.OnClickListener() { 63 | @Override 64 | public void onClick(View v) { 65 | startActivity(new Intent(WebViewActivity.this, MainActivity.class)); 66 | } 67 | }); 68 | } 69 | 70 | private void initWebView() { 71 | WebSettings webSetting = cdWebView.getSettings(); 72 | webSetting.setJavaScriptEnabled(true); 73 | webSetting.setJavaScriptCanOpenWindowsAutomatically(true); 74 | webSetting.setAllowUniversalAccessFromFileURLs(true); 75 | webSetting.setAllowFileAccess(true); 76 | webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); 77 | webSetting.setSupportZoom(false); 78 | webSetting.setBuiltInZoomControls(true); 79 | webSetting.setUseWideViewPort(true); 80 | webSetting.setSupportMultipleWindows(true); 81 | // webSetting.setLoadWithOverviewMode(true); 82 | webSetting.setAppCacheEnabled(true); 83 | webSetting.setDatabaseEnabled(true); 84 | webSetting.setDomStorageEnabled(true); 85 | // webSetting.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); 86 | webSetting.setGeolocationEnabled(true); 87 | webSetting.setAppCacheMaxSize(Long.MAX_VALUE); 88 | // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY); 89 | webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND); 90 | // webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH); 91 | webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE); 92 | webSetting.setLoadWithOverviewMode(true); 93 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 94 | webSetting.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); 95 | } 96 | } 97 | 98 | /** 99 | * 设置WebChromeClient 100 | * 处理进度条和标题显示 101 | */ 102 | private WebChromeClient mWebChromeClient = new WebChromeClient() { 103 | @Override 104 | public void onProgressChanged(WebView webView, int newProgress) { 105 | if (webviewProgressBar != null) { 106 | if (newProgress == 100) { 107 | webviewProgressBar.setProgress(100); 108 | webviewProgressBar.setVisibility(View.GONE); 109 | } else { 110 | if (!webviewProgressBar.isShown()) { 111 | webviewProgressBar.setVisibility(View.VISIBLE); 112 | } 113 | webviewProgressBar.setProgress(newProgress); 114 | } 115 | } 116 | super.onProgressChanged(webView, newProgress); 117 | } 118 | 119 | // public void openFileChooser(ValueCallback filePathCallback) { 120 | // mFilePathCallback = filePathCallback; 121 | // openSelectImageDialog(); 122 | // } 123 | // 124 | // public void openFileChooser(ValueCallback filePathCallback, String acceptType) { 125 | // mFilePathCallback = filePathCallback; 126 | // openSelectImageDialog(); 127 | // } 128 | // 129 | // public void openFileChooser(ValueCallback filePathCallback, String acceptType, String capture) { 130 | // mFilePathCallback = filePathCallback; 131 | // openSelectImageDialog(); 132 | // } 133 | // 134 | // @Override 135 | // public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { 136 | // mFilePathCallbacks = filePathCallback; 137 | // openSelectImageDialog(); 138 | // return true; 139 | // } 140 | }; 141 | 142 | /** 143 | * 设置WebViewClient 144 | * 处理Url拦截事项 145 | */ 146 | private WebViewClient mWebViewClient = new WebViewClient() { 147 | @Override 148 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 149 | view.loadUrl(url); 150 | return true; 151 | } 152 | }; 153 | 154 | @Override 155 | protected void onDestroy() { 156 | 157 | if (cdWebView != null) { 158 | cdWebView.destroy(); 159 | } 160 | if (cdRootView != null && cdWebView != null) { 161 | cdRootView.removeView(cdWebView); 162 | cdRootView.removeAllViews(); 163 | cdWebView = null; 164 | cdRootView = null; 165 | } 166 | SlideBackLayoutUtils.onDestroy(this); 167 | super.onDestroy(); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/commonadapter/ListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.commonadapter; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.widget.BaseAdapter; 6 | 7 | import com.slidbacklib.commonadapter.viewholders.GodViewHolder; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * 适用于ListView的 通用 Adapter 14 | */ 15 | public abstract class ListViewAdapter extends BaseAdapter { 16 | /** 17 | * 数据集 18 | */ 19 | protected final List mDataSet = new ArrayList<>(); 20 | /** 21 | * Item Layout 22 | */ 23 | private int mItemLayoutId; 24 | 25 | /** 26 | * 27 | * @param layoutId 28 | */ 29 | public ListViewAdapter(int layoutId) { 30 | mItemLayoutId = layoutId; 31 | } 32 | 33 | public ListViewAdapter(int layoutId, List datas) { 34 | mItemLayoutId = layoutId; 35 | mDataSet.addAll(datas) ; 36 | } 37 | 38 | /** 39 | * @param item 40 | */ 41 | public void addItem(D item) { 42 | mDataSet.add(item); 43 | notifyDataSetChanged(); 44 | } 45 | 46 | /** 47 | * @param items 48 | */ 49 | public void addItems(List items) { 50 | mDataSet.addAll(items); 51 | notifyDataSetChanged(); 52 | } 53 | 54 | /** 55 | * @param item 56 | */ 57 | public void addItemToHead(D item) { 58 | mDataSet.add(0, item); 59 | notifyDataSetChanged(); 60 | } 61 | 62 | /** 63 | * @param items 64 | */ 65 | public void addItemsToHead(List items) { 66 | mDataSet.addAll(0, items); 67 | notifyDataSetChanged(); 68 | } 69 | 70 | /** 71 | * @param position 72 | */ 73 | public void remove(int position) { 74 | mDataSet.remove(position); 75 | notifyDataSetChanged(); 76 | } 77 | 78 | /** 79 | * @param item 80 | */ 81 | public void remove(D item) { 82 | mDataSet.remove(item); 83 | notifyDataSetChanged(); 84 | } 85 | 86 | /** 87 | * clear all data 88 | */ 89 | public void clear() { 90 | mDataSet.clear(); 91 | notifyDataSetChanged(); 92 | } 93 | 94 | /** 95 | * @return 96 | */ 97 | @Override 98 | public int getCount() { 99 | return mDataSet.size(); 100 | } 101 | 102 | /** 103 | * @param position 104 | * @return 105 | */ 106 | @Override 107 | public D getItem(int position) { 108 | return mDataSet.get(position); 109 | } 110 | 111 | /** 112 | * @param position 113 | * @return 114 | */ 115 | @Override 116 | public long getItemId(int position) { 117 | return position; 118 | } 119 | 120 | /** 121 | * 根据View Type返回布局资源 122 | * 123 | * @param type 124 | * @return 125 | */ 126 | protected int getItemLayout(int type) { 127 | return mItemLayoutId; 128 | } 129 | 130 | /** 131 | * 封装getView逻辑,将根据viewType获取布局资源、解析布局资源、创建ViewHolder等逻辑封装起来,简化使用流程 132 | * 133 | * @param position 134 | * @param convertView 135 | * @param parent 136 | * @return 137 | */ 138 | @Override 139 | public View getView(int position, View convertView, ViewGroup parent) { 140 | int viewType = getItemViewType( position ) ; 141 | GodViewHolder viewHolder = GodViewHolder.get(convertView, parent, getItemLayout(viewType)); 142 | // 绑定数据 143 | onBindData(viewHolder, position, getItem(position)); 144 | return viewHolder.getItemView(); 145 | } 146 | 147 | /** 148 | * 绑定数据到Item View上 149 | * 150 | * @param viewHolder 151 | * @param position 数据的位置 152 | * @param item 数据项 153 | */ 154 | protected abstract void onBindData(GodViewHolder viewHolder, int position, D item); 155 | 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/commonadapter/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.commonadapter; 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 | 9 | import com.slidbacklib.commonadapter.viewholders.RecyclerViewHolder; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * 用于RecyclerView的Adapter 16 | */ 17 | public abstract class RecyclerAdapter extends RecyclerView.Adapter { 18 | 19 | /** 20 | * 数据集 21 | */ 22 | protected final List mDataSet = new ArrayList<>(); 23 | /** 24 | * 单击事件 25 | */ 26 | protected OnItemClickListener mOnItemClickListener; 27 | /** 28 | * Item Layout的资源id 29 | */ 30 | private int mItemLayoutId; 31 | 32 | /** 33 | * @param layoutId 布局id 34 | */ 35 | public RecyclerAdapter(int layoutId) { 36 | mItemLayoutId = layoutId; 37 | } 38 | 39 | /** 40 | * @param layoutId 布局id 41 | * @param datas 数据集 42 | */ 43 | public RecyclerAdapter(int layoutId, List datas) { 44 | mItemLayoutId = layoutId; 45 | addItems(datas); 46 | } 47 | 48 | /** 49 | * 追加单个数据 50 | * 51 | * @param item 52 | */ 53 | public void addItem(D item) { 54 | mDataSet.add(item); 55 | notifyDataSetChanged(); 56 | } 57 | 58 | 59 | /** 60 | * 追加数据集 61 | * 62 | * @param items 63 | */ 64 | public void addItems(List items) { 65 | mDataSet.addAll(items); 66 | notifyDataSetChanged(); 67 | } 68 | 69 | /** 70 | * 添加单个数据到列表头部 71 | * 72 | * @param item 73 | */ 74 | public void addItemToHead(D item) { 75 | mDataSet.add(0, item); 76 | notifyDataSetChanged(); 77 | } 78 | 79 | /** 80 | * 添加数据集到列表头部 81 | * 82 | * @param items 83 | */ 84 | public void addItemsToHead(List items) { 85 | mDataSet.addAll(0, items); 86 | notifyDataSetChanged(); 87 | } 88 | 89 | /** 90 | * 移除某个数据 91 | * 92 | * @param position 93 | */ 94 | public void remove(int position) { 95 | mDataSet.remove(position); 96 | notifyDataSetChanged(); 97 | } 98 | 99 | /** 100 | * 移除某个数据项 101 | * 102 | * @param item 103 | */ 104 | public void remove(D item) { 105 | mDataSet.remove(item); 106 | notifyDataSetChanged(); 107 | } 108 | 109 | /** 110 | * clear all data 111 | */ 112 | public void clear() { 113 | mDataSet.clear(); 114 | notifyDataSetChanged(); 115 | } 116 | 117 | /** 118 | * 获取指定位置的数据项 119 | * 120 | * @param position 121 | * @return 122 | */ 123 | public D getItem(int position) { 124 | return mDataSet.get(position); 125 | } 126 | 127 | @Override 128 | public int getItemCount() { 129 | return mDataSet.size(); 130 | } 131 | 132 | @Override 133 | public void onBindViewHolder(RecyclerViewHolder holder, int position) { 134 | final D item = getItem(position); 135 | // 绑定数据 136 | onBindData(holder, position, item); 137 | // 设置单击事件 138 | setupItemClickListener(holder, position); 139 | } 140 | 141 | /** 142 | * 解析布局资源 143 | * 144 | * @param viewGroup 145 | * @param viewType 146 | * @return 147 | */ 148 | protected View inflateItemView(ViewGroup viewGroup, int viewType) { 149 | int itemLayout = getItemLayout(viewType); 150 | Context context = viewGroup.getContext(); 151 | return LayoutInflater.from(context).inflate(itemLayout, viewGroup, false); 152 | } 153 | 154 | @Override 155 | public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 156 | return new RecyclerViewHolder(inflateItemView(parent, viewType)); 157 | } 158 | 159 | /** 160 | * 根据Type返回布局资源 161 | * 162 | * @param type 163 | * @return 164 | */ 165 | protected int getItemLayout(int type) { 166 | return mItemLayoutId; 167 | } 168 | 169 | 170 | /** 171 | * 绑定数据到Item View上 172 | * 173 | * @param viewHolder 174 | * @param position 数据的位置 175 | * @param item 数据项 176 | */ 177 | protected abstract void onBindData(RecyclerViewHolder viewHolder, int position, D item); 178 | 179 | 180 | /** 181 | * @param viewHolder 182 | * @param position 183 | */ 184 | protected void setupItemClickListener(RecyclerViewHolder viewHolder, final int position) { 185 | viewHolder.itemView.setOnClickListener(new View.OnClickListener() { 186 | @Override 187 | public void onClick(View v) { 188 | if (mOnItemClickListener != null) { 189 | mOnItemClickListener.onItemClick(position); 190 | } 191 | } 192 | }); 193 | } 194 | 195 | /** 196 | * 设置点击事件 197 | * 198 | * @param listener 199 | */ 200 | public void setOnItemClickListener(OnItemClickListener listener) { 201 | this.mOnItemClickListener = listener; 202 | } 203 | 204 | /** 205 | * 点击事件Listener 206 | */ 207 | public static interface OnItemClickListener { 208 | void onItemClick(int position); 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/commonadapter/viewholders/GodViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.commonadapter.viewholders; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.drawable.Drawable; 7 | import android.net.Uri; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.AdapterView; 12 | 13 | /** 14 | * 15 | * 16 | */ 17 | public class GodViewHolder { 18 | /** 19 | * ViewHolder实现类,桥接模式适配AbsListView与RecyclerView的二维变化 20 | */ 21 | ViewHolderImpl mHolderImpl ; 22 | 23 | 24 | /** 25 | * @param itemView 26 | */ 27 | GodViewHolder(View itemView) { 28 | mHolderImpl = new ViewHolderImpl( itemView ) ; 29 | } 30 | 31 | /** 32 | * @param viewId 33 | * @param 34 | * @return 35 | */ 36 | public T findViewById(int viewId) { 37 | return mHolderImpl.findViewById(viewId); 38 | } 39 | 40 | public Context getContext() { 41 | return mHolderImpl.mItemView.getContext() ; 42 | } 43 | 44 | /** 45 | * 获取GodViewHolder 46 | * 47 | * @param convertView 48 | * @param parent 49 | * @param layoutId 50 | * @return 51 | */ 52 | public static GodViewHolder get(View convertView, ViewGroup parent, int layoutId) { 53 | GodViewHolder viewHolder = null; 54 | if (convertView == null) { 55 | convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); 56 | viewHolder = new GodViewHolder(convertView); 57 | convertView.setTag(viewHolder); 58 | } else { 59 | viewHolder = (GodViewHolder) convertView.getTag(); 60 | } 61 | 62 | return viewHolder; 63 | } 64 | 65 | 66 | public View getItemView() { 67 | return mHolderImpl.getItemView(); 68 | } 69 | 70 | public GodViewHolder setText(int viewId, int stringId) { 71 | mHolderImpl.setText(viewId, stringId); 72 | return this; 73 | } 74 | 75 | public GodViewHolder setText(int viewId, String text) { 76 | mHolderImpl.setText(viewId, text); 77 | return this; 78 | } 79 | 80 | public GodViewHolder setTextColor(int viewId, int color) { 81 | mHolderImpl.setTextColor(viewId, color); 82 | return this; 83 | } 84 | 85 | /** 86 | * @param viewId 87 | * @param color 88 | */ 89 | public GodViewHolder setBackgroundColor(int viewId, int color) { 90 | mHolderImpl.setBackgroundColor(viewId, color); 91 | return this; 92 | } 93 | 94 | 95 | /** 96 | * @param viewId 97 | * @param resId 98 | */ 99 | public GodViewHolder setBackgroundResource(int viewId, int resId) { 100 | mHolderImpl.setBackgroundResource(viewId, resId); 101 | return this; 102 | } 103 | 104 | 105 | /** 106 | * @param viewId 107 | * @param drawable 108 | */ 109 | public GodViewHolder setBackgroundDrawable(int viewId, Drawable drawable) { 110 | mHolderImpl.setBackgroundDrawable(viewId, drawable); 111 | return this; 112 | } 113 | 114 | /** 115 | * @param viewId 116 | * @param drawable 117 | */ 118 | @TargetApi(16) 119 | public GodViewHolder setBackground(int viewId, Drawable drawable) { 120 | mHolderImpl.setBackground(viewId, drawable); 121 | return this; 122 | } 123 | 124 | 125 | public GodViewHolder setImageBitmap(int viewId, Bitmap bitmap) { 126 | mHolderImpl.setImageBitmap(viewId, bitmap); 127 | return this; 128 | } 129 | 130 | 131 | public GodViewHolder setImageResource(int viewId, int resId) { 132 | mHolderImpl.setImageResource(viewId, resId); 133 | return this; 134 | } 135 | 136 | public GodViewHolder setImageDrawable(int viewId, Drawable drawable) { 137 | mHolderImpl.setImageDrawable(viewId, drawable); 138 | return this; 139 | } 140 | 141 | 142 | public GodViewHolder setImageDrawable(int viewId, Uri uri) { 143 | mHolderImpl.setImageDrawable(viewId, uri); 144 | return this; 145 | } 146 | 147 | 148 | @TargetApi(16) 149 | public GodViewHolder setImageAlpha(int viewId, int alpha) { 150 | mHolderImpl.setImageAlpha(viewId, alpha); 151 | return this; 152 | } 153 | 154 | public GodViewHolder setChecked(int viewId, boolean checked) { 155 | mHolderImpl.setChecked(viewId, checked); 156 | return this; 157 | } 158 | 159 | 160 | public GodViewHolder setProgress(int viewId, int progress) { 161 | mHolderImpl.setProgress(viewId, progress); 162 | return this; 163 | } 164 | 165 | public GodViewHolder setProgress(int viewId, int progress, int max) { 166 | mHolderImpl.setProgress(viewId, progress, max); 167 | return this; 168 | } 169 | 170 | public GodViewHolder setMax(int viewId, int max) { 171 | mHolderImpl.setMax(viewId, max); 172 | return this; 173 | } 174 | 175 | public GodViewHolder setRating(int viewId, float rating) { 176 | mHolderImpl.setRating(viewId, rating); 177 | return this; 178 | } 179 | 180 | 181 | public GodViewHolder setRating(int viewId, float rating, int max) { 182 | mHolderImpl.setRating(viewId, rating, max); 183 | return this; 184 | } 185 | 186 | public GodViewHolder setVisibility(int viewId, int visible) { 187 | mHolderImpl.setVisibility(viewId, visible); 188 | return this; 189 | } 190 | 191 | public GodViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { 192 | mHolderImpl.setOnClickListener(viewId, listener); 193 | return this; 194 | } 195 | 196 | public GodViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) { 197 | mHolderImpl.setOnTouchListener(viewId, listener); 198 | return this; 199 | } 200 | 201 | public GodViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) { 202 | mHolderImpl.setOnLongClickListener(viewId, listener); 203 | return this; 204 | } 205 | 206 | public GodViewHolder setOnItemClickListener(int viewId, AdapterView.OnItemClickListener listener) { 207 | mHolderImpl.setOnItemClickListener(viewId, listener); 208 | return this; 209 | } 210 | 211 | 212 | public GodViewHolder setOnItemLongClickListener(int viewId, AdapterView.OnItemLongClickListener listener) { 213 | mHolderImpl.setOnItemLongClickListener(viewId, listener); 214 | return this; 215 | } 216 | 217 | 218 | public GodViewHolder setOnItemSelectedClickListener(int viewId, AdapterView.OnItemSelectedListener listener) { 219 | mHolderImpl.setOnItemSelectedClickListener(viewId, listener); 220 | return this; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/commonadapter/viewholders/RecyclerViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.commonadapter.viewholders; 2 | import android.annotation.TargetApi; 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | import android.net.Uri; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | 11 | /** 12 | * 适用于RecyclerView的ViewHolder 13 | */ 14 | public class RecyclerViewHolder extends RecyclerView.ViewHolder { 15 | /** 16 | * ViewHolder实现类,桥接模式适配AbsListView与RecyclerView的二维变化 17 | */ 18 | ViewHolderImpl mHolderImpl ; 19 | 20 | /** 21 | * 22 | * @param itemView 23 | */ 24 | public RecyclerViewHolder(View itemView) { 25 | super(itemView); 26 | mHolderImpl = new ViewHolderImpl( itemView ) ; 27 | } 28 | 29 | public Context getContext() { 30 | return mHolderImpl.mItemView.getContext() ; 31 | } 32 | 33 | /** 34 | * @param viewId 35 | * @param 36 | * @return 37 | */ 38 | public T findViewById(int viewId) { 39 | return mHolderImpl.findViewById(viewId); 40 | } 41 | 42 | public View getItemView() { 43 | return mHolderImpl.getItemView(); 44 | } 45 | 46 | public RecyclerViewHolder setText(int viewId, int stringId) { 47 | mHolderImpl.setText(viewId, stringId); 48 | return this; 49 | } 50 | 51 | public RecyclerViewHolder setText(int viewId, String text) { 52 | mHolderImpl.setText(viewId, text); 53 | return this; 54 | } 55 | 56 | public RecyclerViewHolder setTextColor(int viewId, int color) { 57 | mHolderImpl.setTextColor(viewId, color); 58 | return this; 59 | } 60 | 61 | /** 62 | * @param viewId 63 | * @param color 64 | */ 65 | public RecyclerViewHolder setBackgroundColor(int viewId, int color) { 66 | mHolderImpl.setBackgroundColor(viewId, color); 67 | return this; 68 | } 69 | 70 | 71 | /** 72 | * @param viewId 73 | * @param resId 74 | */ 75 | public RecyclerViewHolder setBackgroundResource(int viewId, int resId) { 76 | mHolderImpl.setBackgroundResource(viewId, resId); 77 | return this; 78 | } 79 | 80 | 81 | /** 82 | * @param viewId 83 | * @param drawable 84 | */ 85 | public RecyclerViewHolder setBackgroundDrawable(int viewId, Drawable drawable) { 86 | mHolderImpl.setBackgroundDrawable(viewId, drawable); 87 | return this; 88 | } 89 | 90 | /** 91 | * @param viewId 92 | * @param drawable 93 | */ 94 | @TargetApi(16) 95 | public RecyclerViewHolder setBackground(int viewId, Drawable drawable) { 96 | mHolderImpl.setBackground(viewId, drawable); 97 | return this; 98 | } 99 | 100 | 101 | public RecyclerViewHolder setImageBitmap(int viewId, Bitmap bitmap) { 102 | mHolderImpl.setImageBitmap(viewId, bitmap); 103 | return this; 104 | } 105 | 106 | 107 | public RecyclerViewHolder setImageResource(int viewId, int resId) { 108 | mHolderImpl.setImageResource(viewId, resId); 109 | return this; 110 | } 111 | 112 | public RecyclerViewHolder setImageDrawable(int viewId, Drawable drawable) { 113 | mHolderImpl.setImageDrawable(viewId, drawable); 114 | return this; 115 | } 116 | 117 | 118 | public RecyclerViewHolder setImageDrawable(int viewId, Uri uri) { 119 | mHolderImpl.setImageDrawable(viewId, uri); 120 | return this; 121 | } 122 | 123 | 124 | @TargetApi(16) 125 | public RecyclerViewHolder setImageAlpha(int viewId, int alpha) { 126 | mHolderImpl.setImageAlpha(viewId, alpha); 127 | return this; 128 | } 129 | 130 | public RecyclerViewHolder setChecked(int viewId, boolean checked) { 131 | mHolderImpl.setChecked(viewId, checked); 132 | return this; 133 | } 134 | 135 | 136 | public RecyclerViewHolder setProgress(int viewId, int progress) { 137 | mHolderImpl.setProgress(viewId, progress); 138 | return this; 139 | } 140 | 141 | public RecyclerViewHolder setProgress(int viewId, int progress, int max) { 142 | mHolderImpl.setProgress(viewId, progress, max); 143 | return this; 144 | } 145 | 146 | public RecyclerViewHolder setMax(int viewId, int max) { 147 | mHolderImpl.setMax(viewId, max); 148 | return this; 149 | } 150 | 151 | public RecyclerViewHolder setRating(int viewId, float rating) { 152 | mHolderImpl.setRating(viewId, rating); 153 | return this; 154 | } 155 | 156 | public RecyclerViewHolder setVisibility(int viewId, int visible) { 157 | mHolderImpl.setVisibility(viewId, visible); 158 | return this; 159 | } 160 | 161 | 162 | public RecyclerViewHolder setRating(int viewId, float rating, int max) { 163 | mHolderImpl.setRating(viewId, rating, max); 164 | return this; 165 | } 166 | 167 | public RecyclerViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { 168 | mHolderImpl.setOnClickListener(viewId, listener); 169 | return this; 170 | } 171 | 172 | public RecyclerViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) { 173 | mHolderImpl.setOnTouchListener(viewId, listener); 174 | return this; 175 | } 176 | 177 | 178 | public RecyclerViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) { 179 | mHolderImpl.setOnLongClickListener(viewId, listener); 180 | return this; 181 | } 182 | 183 | public RecyclerViewHolder setOnItemClickListener(int viewId, AdapterView.OnItemClickListener listener) { 184 | mHolderImpl.setOnItemClickListener(viewId, listener); 185 | return this; 186 | } 187 | 188 | 189 | public RecyclerViewHolder setOnItemLongClickListener(int viewId, AdapterView.OnItemLongClickListener listener) { 190 | mHolderImpl.setOnItemLongClickListener(viewId, listener); 191 | return this; 192 | } 193 | 194 | 195 | public RecyclerViewHolder setOnItemSelectedClickListener(int viewId, AdapterView.OnItemSelectedListener listener) { 196 | mHolderImpl.setOnItemSelectedClickListener(viewId, listener); 197 | return this; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/commonadapter/viewholders/ViewHolderImpl.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.commonadapter.viewholders; 2 | 3 | import android.annotation.TargetApi; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | import android.net.Uri; 7 | import android.util.SparseArray; 8 | import android.view.View; 9 | import android.widget.AdapterView; 10 | import android.widget.Checkable; 11 | import android.widget.ImageView; 12 | import android.widget.ProgressBar; 13 | import android.widget.RatingBar; 14 | import android.widget.TextView; 15 | 16 | /** 17 | * ViewHolder操作子视图的实现类 18 | */ 19 | public class ViewHolderImpl { 20 | 21 | /** 22 | * 缓存子视图,key为view id, 值为View。 23 | */ 24 | private SparseArray mCahceViews = new SparseArray(); 25 | /** 26 | * Item View 27 | */ 28 | View mItemView; 29 | 30 | /** 31 | * @param itemView 32 | */ 33 | ViewHolderImpl(View itemView) { 34 | mItemView = itemView; 35 | } 36 | 37 | public View getItemView() { 38 | return mItemView; 39 | } 40 | 41 | /** 42 | * @param viewId 43 | * @param 44 | * @return 45 | */ 46 | public T findViewById(int viewId) { 47 | View target = mCahceViews.get(viewId); 48 | if (target == null) { 49 | target = mItemView.findViewById(viewId); 50 | mCahceViews.put(viewId, target); 51 | } 52 | return (T) target; 53 | } 54 | 55 | 56 | public void setText(int viewId, int stringId) { 57 | TextView textView = findViewById(viewId); 58 | textView.setText(stringId); 59 | } 60 | 61 | public void setText(int viewId, String text) { 62 | TextView textView = findViewById(viewId); 63 | textView.setText(text); 64 | } 65 | 66 | public void setTextColor(int viewId, int color) { 67 | TextView textView = findViewById(viewId); 68 | textView.setTextColor(color); 69 | } 70 | 71 | /** 72 | * @param viewId 73 | * @param color 74 | */ 75 | public void setBackgroundColor(int viewId, int color) { 76 | View target = findViewById(viewId); 77 | target.setBackgroundColor(color); 78 | 79 | } 80 | 81 | 82 | /** 83 | * @param viewId 84 | * @param resId 85 | */ 86 | public void setBackgroundResource(int viewId, int resId) { 87 | View target = findViewById(viewId); 88 | target.setBackgroundResource(resId); 89 | } 90 | 91 | 92 | /** 93 | * @param viewId 94 | * @param drawable 95 | */ 96 | public void setBackgroundDrawable(int viewId, Drawable drawable) { 97 | View target = findViewById(viewId); 98 | target.setBackgroundDrawable(drawable); 99 | } 100 | 101 | /** 102 | * @param viewId 103 | * @param drawable 104 | */ 105 | @TargetApi(16) 106 | public void setBackground(int viewId, Drawable drawable) { 107 | View target = findViewById(viewId); 108 | target.setBackground(drawable); 109 | } 110 | 111 | 112 | public void setImageBitmap(int viewId, Bitmap bitmap) { 113 | ImageView target = findViewById(viewId); 114 | target.setImageBitmap(bitmap); 115 | } 116 | 117 | 118 | public void setImageResource(int viewId, int resId) { 119 | ImageView target = findViewById(viewId); 120 | target.setImageResource(resId); 121 | } 122 | 123 | 124 | public void setImageDrawable(int viewId, Drawable drawable) { 125 | ImageView target = findViewById(viewId); 126 | target.setImageDrawable(drawable); 127 | } 128 | 129 | 130 | public void setImageDrawable(int viewId, Uri uri) { 131 | ImageView target = findViewById(viewId); 132 | target.setImageURI(uri); 133 | } 134 | 135 | 136 | @TargetApi(16) 137 | public void setImageAlpha(int viewId, int alpha) { 138 | ImageView target = findViewById(viewId); 139 | target.setImageAlpha(alpha); 140 | } 141 | 142 | public void setChecked(int viewId, boolean checked) { 143 | Checkable checkable = findViewById(viewId); 144 | checkable.setChecked(checked); 145 | } 146 | 147 | 148 | public void setProgress(int viewId, int progress) { 149 | ProgressBar view = findViewById(viewId); 150 | view.setProgress(progress); 151 | } 152 | 153 | public void setProgress(int viewId, int progress, int max) { 154 | ProgressBar view = findViewById(viewId); 155 | view.setMax(max); 156 | view.setProgress(progress); 157 | } 158 | 159 | public void setMax(int viewId, int max) { 160 | ProgressBar view = findViewById(viewId); 161 | view.setMax(max); 162 | } 163 | 164 | public void setRating(int viewId, float rating) { 165 | RatingBar view = findViewById(viewId); 166 | view.setRating(rating); 167 | } 168 | 169 | public void setVisibility(int viewId, int visible) { 170 | View view = findViewById(viewId); 171 | view.setVisibility(visible); 172 | } 173 | 174 | 175 | public void setRating(int viewId, float rating, int max) { 176 | RatingBar view = findViewById(viewId); 177 | view.setMax(max); 178 | view.setRating(rating); 179 | } 180 | 181 | public void setOnClickListener(int viewId, View.OnClickListener listener) { 182 | View view = findViewById(viewId); 183 | view.setOnClickListener(listener); 184 | 185 | } 186 | 187 | public void setOnTouchListener(int viewId, View.OnTouchListener listener) { 188 | View view = findViewById(viewId); 189 | view.setOnTouchListener(listener); 190 | } 191 | 192 | 193 | public void setOnLongClickListener(int viewId, View.OnLongClickListener listener) { 194 | View view = findViewById(viewId); 195 | view.setOnLongClickListener(listener); 196 | } 197 | 198 | public void setOnItemClickListener(int viewId, AdapterView.OnItemClickListener listener) { 199 | AdapterView view = findViewById(viewId); 200 | view.setOnItemClickListener(listener); 201 | } 202 | 203 | 204 | public void setOnItemLongClickListener(int viewId, AdapterView.OnItemLongClickListener listener) { 205 | AdapterView view = findViewById(viewId); 206 | view.setOnItemLongClickListener(listener); 207 | } 208 | 209 | 210 | public void setOnItemSelectedClickListener(int viewId, AdapterView.OnItemSelectedListener listener) { 211 | AdapterView view = findViewById(viewId); 212 | view.setOnItemSelectedListener(listener); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/utils/SlideBackLayoutUtils.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.utils; 2 | 3 | import android.app.Activity; 4 | 5 | import com.slidbacklib.App; 6 | import com.slideback.SlideBackHelper; 7 | import com.slideback.SlideConfig; 8 | import com.slideback.callbak.OnSlideListenerAdapter; 9 | import com.slideback.widget.SlideBackLayout; 10 | 11 | import java.util.HashMap; 12 | 13 | /** 14 | * =============================== 15 | * 描 述:SlideBackLayoutUtils 16 | * 作 者:pjw 17 | * 创建日期:2017/12/20 17:28 18 | * =============================== 19 | */ 20 | public class SlideBackLayoutUtils { 21 | 22 | private static HashMap mBackLayoutHashMap = new HashMap<>(3); 23 | 24 | /** 25 | * 设置侧滑返回,默认配置 26 | */ 27 | public static void sideBack(Activity activity) { 28 | sideBack(activity, getDefaultSlideConfig(), null); 29 | } 30 | 31 | public static void sideBack(Activity activity, SlideConfig slideConfig, OnSlideListenerAdapter adapter) { 32 | SlideBackHelper slideBackHelper = new SlideBackHelper(); 33 | SlideBackLayout slideBackLayout = slideBackHelper.attach( 34 | // 当前Activity 35 | activity, 36 | //ActivityHelper 37 | App.sApp.getActivityHelper(), 38 | // 参数的配置 39 | slideConfig, 40 | // 滑动的监听 41 | adapter); 42 | if (slideBackLayout == null) return; 43 | //添加到集合中 44 | mBackLayoutHashMap.put(activity, slideBackLayout); 45 | //添加到栈 46 | App.sApp.getActivityHelper().setActivityInfo(activity, slideBackLayout, slideBackHelper); 47 | // //边缘响应的最大值 48 | // slideBackLayout.setEdgeRangePercent(0.2f); 49 | // //非快速滑动,关闭页面的最小值 50 | // slideBackLayout.setSlideOutRangePercent(0.3f); 51 | // //是否关闭全局侧滑,默认开启全局侧滑 52 | // slideBackLayout.edgeOnly(true); 53 | // //是否关闭侧滑,默认开启侧滑 54 | // slideBackLayout.lock(false); 55 | } 56 | 57 | /** 58 | * 获取默认配置 59 | */ 60 | public static SlideConfig getDefaultSlideConfig() { 61 | // 参数的配置 62 | return new SlideConfig() 63 | // 屏幕是否旋转 64 | .setRotateScreen(false) 65 | // 是否关闭全局侧滑 66 | .setEdgeOnly(true) 67 | // 是否关闭侧滑 68 | .setLock(false) 69 | // 边缘响应滑动区域的最大值 0~1 70 | .setEdgePercent(0.2f) 71 | // 非快速滑动,关闭页面的最小值 0~1 72 | .setSlideOutPercent(0.4f); 73 | } 74 | 75 | public static void onDestroy(Activity activity) { 76 | //Activity销毁调用方法 77 | SlideBackLayout slideBackLayout = mBackLayoutHashMap.get(activity); 78 | if (slideBackLayout != null) { 79 | slideBackLayout.isComingToFinish(); 80 | mBackLayoutHashMap.remove(activity); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/slidbacklib/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.slidbacklib.utils; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * =============================== 7 | * 描 述: 8 | * 作 者:pjw 9 | * 创建日期:2017/11/1 13:48 10 | * =============================== 11 | */ 12 | public class StringUtils { 13 | 14 | public static ArrayList getDatas(int count) { 15 | ArrayList arrayList = new ArrayList<>(count); 16 | for (int i = 0; i < count; i++) { 17 | arrayList.add("i:" + i); 18 | } 19 | return arrayList; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_title_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/drawable-xxhdpi/icon_title_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_titlebar_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/drawable-xxhdpi/icon_titlebar_close.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/percent_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/drawable-xxhdpi/percent_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/title_back_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/drawable-xxhdpi/title_back_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/person_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/webview_progress_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_list_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_scroll_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 17 | 18 | 21 | 22 | 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 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_web_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 23 | 24 | 31 | 32 | 41 | 42 | 53 | 54 | 62 | 63 | 76 | 77 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 102 | 103 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_list_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 26 | 27 | 39 | 40 | 46 | 47 | 52 | 53 | 54 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | 8 | #FFFBFBFB 9 | #FFFFFFFF 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SlidBackLib 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /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 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | } 21 | tasks.withType(JavaCompile) { 22 | options.encoding = "UTF-8" 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /config.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | android = [ 3 | compileSdkVersion: 26, 4 | buildToolsVersion: "26.0.2", 5 | minSdkVersion : 14, 6 | targetSdkVersion : 26, 7 | versionCode : 171031, 8 | versionName : "0.0.1" 9 | ] 10 | version = [ 11 | androidSupportSdkVersion: "26.+", 12 | retrofitSdkVersion : "2.2.0", 13 | dagger2SdkVersion : "2.9", 14 | butterknifeSdkVersion : "8.7.0", 15 | rxlifecycleSdkVersion : "1.0", 16 | rxlifecycle2SdkVersion : "2.0.1", 17 | espressoSdkVersion : "2.2.2", 18 | canarySdkVersion : "1.5" 19 | ] 20 | 21 | dependencies = [ 22 | //support 23 | "appcompat-v7" : "com.android.support:appcompat-v7:${version["androidSupportSdkVersion"]}", 24 | "design" : "com.android.support:design:${version["androidSupportSdkVersion"]}", 25 | "support-v4" : "com.android.support:support-v4:${version["androidSupportSdkVersion"]}", 26 | "cardview-v7" : "com.android.support:cardview-v7:${version["androidSupportSdkVersion"]}", 27 | "annotations" : "com.android.support:support-annotations:${version["androidSupportSdkVersion"]}", 28 | "recyclerview-v7" : "com.android.support:recyclerview-v7:${version["androidSupportSdkVersion"]}", 29 | "support-core-ui" : "com.android.support:support-core-ui:${version["androidSupportSdkVersion"]}", 30 | "support-compat" : "com.android.support:support-compat:${version["androidSupportSdkVersion"]}", 31 | 32 | //network 33 | "retrofit" : "com.squareup.retrofit2:retrofit:${version["retrofitSdkVersion"]}", 34 | "retrofit-converter-gson" : "com.squareup.retrofit2:converter-gson:${version["retrofitSdkVersion"]}", 35 | "retrofit-adapter-rxjava" : "com.squareup.retrofit2:adapter-rxjava:${version["retrofitSdkVersion"]}", 36 | "retrofit-adapter-rxjava2" : "com.squareup.retrofit2:adapter-rxjava2:${version["retrofitSdkVersion"]}", 37 | "okhttp3" : "com.squareup.okhttp3:okhttp:3.7.0", 38 | "okhttp-urlconnection" : "com.squareup.okhttp:okhttp-urlconnection:2.0.0", 39 | "glide" : "com.github.bumptech.glide:glide:3.8.0", 40 | "picasso" : "com.squareup.picasso:picasso:2.5.2", 41 | 42 | //view 43 | "autolayout" : "com.zhy:autolayout:1.4.5", 44 | "butterknife" : "com.jakewharton:butterknife:${version["butterknifeSdkVersion"]}", 45 | "annotationProcessor" : "com.jakewharton:butterknife-compiler:${version["butterknifeSdkVersion"]}", 46 | "butterknife-compiler" : "com.jakewharton:butterknife-compiler:${version["butterknifeSdkVersion"]}", 47 | "pickerview" : "com.bigkoo:pickerview:2.0.8", 48 | "photoview" : "com.github.chrisbanes.photoview:library:1.2.3", 49 | "numberprogressbar" : "com.daimajia.numberprogressbar:library:1.2@aar", 50 | "nineoldandroids" : "com.nineoldandroids:library:2.4.0", 51 | "loading-indicator" : 'com.wang.avi:library:2.1.3', 52 | "paginate" : "com.github.markomilos:paginate:0.5.1", 53 | "constraint-layout" : 'com.android.support.constraint:constraint-layout:1.0.2', 54 | 55 | //rx1 56 | "rxandroid" : "io.reactivex:rxandroid:1.2.1", 57 | "rxjava" : "io.reactivex:rxjava:1.2.9", 58 | "rxlifecycle" : "com.trello:rxlifecycle:${version["rxlifecycleSdkVersion"]}", 59 | "rxlifecycle-components" : "com.trello:rxlifecycle-components:${version["rxlifecycleSdkVersion"]}", 60 | "rxcache" : "com.github.VictorAlbertos.RxCache:runtime:1.7.0-1.x", 61 | "rxcache-jolyglot-gson" : "com.github.VictorAlbertos.Jolyglot:gson:0.0.3", 62 | "rxbinding-recyclerview-v7": "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:1.0.1", 63 | "rxpermissions" : "com.tbruyelle.rxpermissions:rxpermissions:0.9.3@aar", 64 | "rxerrorhandler" : "me.jessyan:rxerrorhandler:1.0.1", 65 | 66 | //rx2 67 | "rxandroid2" : "io.reactivex.rxjava2:rxandroid:2.0.1", 68 | "rxjava2" : "io.reactivex.rxjava2:rxjava:2.1.0", 69 | "rxlifecycle2" : "com.trello.rxlifecycle2:rxlifecycle:${version["rxlifecycle2SdkVersion"]}", 70 | "rxlifecycle2-components" : "com.trello.rxlifecycle2:rxlifecycle-components:${version["rxlifecycle2SdkVersion"]}", 71 | "rxcache2" : "com.github.VictorAlbertos.RxCache:runtime:1.8.0-2.x", 72 | "rxpermissions2" : "com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar", 73 | "rxerrorhandler2" : "me.jessyan:rxerrorhandler:2.0.1", 74 | 75 | //tools 76 | "dagger2" : "com.google.dagger:dagger:${version["dagger2SdkVersion"]}", 77 | "dagger2-compiler" : "com.google.dagger:dagger-compiler:${version["dagger2SdkVersion"]}", 78 | "androideventbus" : "org.simple:androideventbus:1.0.5.1",//org.greenrobot:eventbus:3.0.0 79 | "otto" : "com.squareup:otto:1.3.8", 80 | "gson" : "com.google.code.gson:gson:2.8.0", 81 | "multidex" : "com.android.support:multidex:1.0.1", 82 | "javax.annotation" : "javax.annotation:jsr250-api:1.0", 83 | 84 | //test 85 | "junit" : "junit:junit:4.12", 86 | "androidJUnitRunner" : "android.support.test.runner.AndroidJUnitRunner", 87 | "runner" : "com.android.support.test:runner:0.5", 88 | "espresso-core" : "com.android.support.test.espresso:espresso-core:${version["espressoSdkVersion"]}", 89 | "espresso-contrib" : "com.android.support.test.espresso:espresso-contrib:${version["espressoSdkVersion"]}", 90 | "espresso-intents" : "com.android.support.test.espresso:espresso-intents:${version["espressoSdkVersion"]}", 91 | "mockito-core" : "org.mockito:mockito-core:1.+", 92 | "timber" : "com.jakewharton.timber:timber:4.5.1", 93 | "canary-debug" : "com.squareup.leakcanary:leakcanary-android:${version["canarySdkVersion"]}", 94 | "canary-release" : "com.squareup.leakcanary:leakcanary-android-no-op:${version["canarySdkVersion"]}", 95 | "umeng-analytics" : "com.umeng.analytics:analytics:6.0.1", 96 | 97 | //other 98 | "logger" : "com.orhanobut:logger:1.15", 99 | 100 | //bugLy 101 | "bugly-crashreport" : "com.tencent.bugly:crashreport:2.6.5", 102 | "bugly-nativecrashreport" : "com.tencent.bugly:nativecrashreport:3.3.0", 103 | "bugly-crashreport_upgrade": "com.tencent.bugly:crashreport_upgrade:1.3.1", 104 | 105 | //aop 106 | "aspectjrt" : "org.aspectj:aspectjrt:1.8.9", 107 | "aspectjtools" : "org.aspectj:aspectjtools:1.8.9", 108 | "aspectjweaver" : "org.aspectj:aspectjweaver:1.8.9", 109 | 110 | //location 111 | "location-gd" : "com.amap.api:location:3.3.0", 112 | "location-search-gd" : "com.amap.api:search:5.2.1" 113 | 114 | ] 115 | } -------------------------------------------------------------------------------- /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 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pujunwu/SlidBackLib/8ecfe6e85b7a186f27fd4666bb4587024962bab3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Dec 26 15:31:13 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', ':sideBackLibrary' 2 | -------------------------------------------------------------------------------- /sideBackLibrary/.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | 30 | # Android 31 | 32 | # Built application files 33 | *.apk 34 | *.ap_ 35 | 36 | # Files for the Dalvik VM 37 | *.dex 38 | 39 | # Java class files 40 | *.class 41 | 42 | # Generated files 43 | bin/ 44 | gen/ 45 | 46 | # Gradle files 47 | .gradle/ 48 | build/ 49 | /gradle/ 50 | /gradlew* 51 | /.idea 52 | /.idea/workspace.xml 53 | 54 | # Local configuration file (sdk path, etc) 55 | local.properties 56 | 57 | # Proguard folder generated by Eclipse 58 | proguard/ 59 | 60 | # Log Files 61 | *.log 62 | 63 | # Android Studio Navigation editor temp files 64 | .navigation/ 65 | /tbreader.iml 66 | 67 | # Android 68 | project.properties 69 | out 70 | captures 71 | 72 | # IntelliJ IDEA 73 | .idea 74 | *.iml 75 | *.ipl 76 | *.iws 77 | -------------------------------------------------------------------------------- /sideBackLibrary/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.android["compileSdkVersion"] 5 | buildToolsVersion rootProject.ext.android["buildToolsVersion"] 6 | 7 | defaultConfig { 8 | minSdkVersion rootProject.ext.android["minSdkVersion"] 9 | targetSdkVersion rootProject.ext.android["targetSdkVersion"] 10 | versionCode rootProject.ext.android["versionCode"] 11 | versionName rootProject.ext.android["versionName"] 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile rootProject.ext.dependencies["support-v4"] 24 | } 25 | -------------------------------------------------------------------------------- /sideBackLibrary/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 /Users/LeeHong/Develop/AndroidDev/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 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/ActivityHelper.java: -------------------------------------------------------------------------------- 1 | package com.slideback; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | 8 | import com.slideback.widget.SlideBackLayout; 9 | 10 | import java.util.Stack; 11 | 12 | /** 13 | * Created by Oubowu on 2016/9/20 3:28. 14 | */ 15 | public class ActivityHelper implements Application.ActivityLifecycleCallbacks { 16 | 17 | private static Stack mActivityStack; 18 | 19 | public ActivityHelper() { 20 | } 21 | 22 | @Override 23 | public void onActivityCreated(Activity activity, Bundle bundle) { 24 | if (mActivityStack == null) { 25 | mActivityStack = new Stack<>(); 26 | } 27 | mActivityStack.add(new ActivityEntity(activity)); 28 | } 29 | 30 | @Override 31 | public void onActivityStarted(Activity activity) { 32 | 33 | } 34 | 35 | @Override 36 | public void onActivityResumed(Activity activity) { 37 | 38 | } 39 | 40 | @Override 41 | public void onActivityPaused(Activity activity) { 42 | 43 | } 44 | 45 | @Override 46 | public void onActivityStopped(Activity activity) { 47 | 48 | } 49 | 50 | @Override 51 | public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { 52 | 53 | } 54 | 55 | @Override 56 | public void onActivityDestroyed(Activity activity) { 57 | // Log.e("TAG", "ActivityHelper-销毁: " + activity); 58 | postRemoveActivity(activity); 59 | } 60 | 61 | /** 62 | * 获取上一个页面 63 | */ 64 | public Activity getPreActivity() { 65 | if (mActivityStack == null) { 66 | return null; 67 | } 68 | int size = mActivityStack.size(); 69 | if (size < 2) { 70 | return null; 71 | } 72 | return mActivityStack.elementAt(size - 2).mActivity; 73 | } 74 | 75 | /** 76 | * 获取下一个页面 77 | */ 78 | public ActivityEntity getNextActivity(Activity activity) { 79 | int current = getActivityEntityIndex(activity); 80 | if (current == -1) return null; 81 | int size = mActivityStack.size(); 82 | if (size < 2 || size - 1 <= current) { 83 | return null; 84 | } 85 | return mActivityStack.elementAt(current + 1); 86 | } 87 | 88 | 89 | // /** 90 | // * 获取上一个页面 91 | // */ 92 | // public Activity getPreActivity(SlideBackLayout slideBackLayout) { 93 | // if (mActivityStack == null) { 94 | // return null; 95 | // } 96 | // int size = mActivityStack.size(); 97 | // if (size < 2) { 98 | // return null; 99 | // } 100 | // int index = 0; 101 | // for (int i = 0; i < size; i++) { 102 | // ActivityEntity entity = mActivityStack.elementAt(i); 103 | // if (entity != null && entity.mSlideBackLayout == slideBackLayout) { 104 | // index = i; 105 | // break; 106 | // } 107 | // } 108 | // if (index - 2 >= 0) { 109 | // return mActivityStack.elementAt(index - 2).mActivity; 110 | // } 111 | // return null; 112 | // } 113 | 114 | public void finishAllActivity() { 115 | if (mActivityStack == null) { 116 | return; 117 | } 118 | for (ActivityEntity entity : mActivityStack) { 119 | if (entity.mSlideBackHelper != null) 120 | entity.mSlideBackHelper.onDestroy(); 121 | entity.mActivity.finish(); 122 | } 123 | } 124 | 125 | public void printAllActivity() { 126 | if (mActivityStack == null) { 127 | return; 128 | } 129 | for (int i = 0; i < mActivityStack.size(); i++) { 130 | Log.e("TAG", "位置" + i + ": " + mActivityStack.get(i)); 131 | } 132 | } 133 | 134 | /** 135 | * 强制删掉activity,用于用户快速滑动页面的时候,因为页面还没来得及destroy导致的问题 136 | * 137 | * @param activity 删掉的activity 138 | */ 139 | void postRemoveActivity(Activity activity) { 140 | if (mActivityStack == null) { 141 | return; 142 | } 143 | //获取下一个页面 144 | // ActivityEntity entityNext = getNextActivity(activity); 145 | // if (entityNext != null && entityNext.mSlideBackLayout != null) { 146 | // entityNext.mSlideBackLayout.setPreContentDestroy(); 147 | // } 148 | ActivityEntity entity = getActivityEntity(activity); 149 | if (entity != null && entity.mSlideBackHelper != null) { 150 | entity.mSlideBackHelper.onDestroy(); 151 | entity.mActivity = null; 152 | entity.mSlideBackLayout = null; 153 | entity.mSlideBackHelper = null; 154 | } 155 | mActivityStack.remove(entity); 156 | } 157 | 158 | private ActivityEntity getActivityEntity(Activity mActivity) { 159 | if (mActivity == null) return null; 160 | for (ActivityEntity entity : mActivityStack) { 161 | if (mActivity == entity.mActivity) return entity; 162 | } 163 | return null; 164 | } 165 | 166 | private int getActivityEntityIndex(Activity mActivity) { 167 | if (mActivity == null) return -1; 168 | for (int i = 0, size = mActivityStack.size(); i < size; i++) { 169 | if (mActivity == mActivityStack.elementAt(i).mActivity) return i; 170 | } 171 | return -1; 172 | } 173 | 174 | public void setActivityInfo(Activity mActivity, SlideBackLayout mSlideBackLayout, SlideBackHelper mSlideBackHelper) { 175 | ActivityEntity entity = getActivityEntity(mActivity); 176 | entity.mSlideBackHelper = mSlideBackHelper; 177 | entity.mSlideBackLayout = mSlideBackLayout; 178 | } 179 | 180 | private class ActivityEntity { 181 | Activity mActivity; 182 | SlideBackLayout mSlideBackLayout; 183 | SlideBackHelper mSlideBackHelper; 184 | 185 | ActivityEntity(Activity mActivity) { 186 | this(mActivity, null); 187 | } 188 | 189 | ActivityEntity(Activity mActivity, SlideBackLayout mSlideBackLayout) { 190 | this(mActivity, mSlideBackLayout, null); 191 | } 192 | 193 | ActivityEntity(Activity mActivity, SlideBackLayout mSlideBackLayout, SlideBackHelper mSlideBackHelper) { 194 | this.mActivity = mActivity; 195 | this.mSlideBackLayout = mSlideBackLayout; 196 | this.mSlideBackHelper = mSlideBackHelper; 197 | } 198 | } 199 | 200 | 201 | } 202 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/SlideBackHelper.java: -------------------------------------------------------------------------------- 1 | package com.slideback; 2 | 3 | import android.app.Activity; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.LinearLayout; 13 | 14 | import com.slideback.callbak.OnInternalStateListener; 15 | import com.slideback.callbak.OnSlideListener; 16 | import com.slideback.widget.SlideBackLayout; 17 | 18 | /** 19 | * Created by Oubowu on 2016/9/22 0022 14:31. 20 | * 侧滑处理 21 | */ 22 | // TODO: 2016/9/24 添加了上个页面的布局,如果页面有Toolbar的话其不随屏幕旋转而大小变化,永远维持进入时的宽高比 23 | public class SlideBackHelper { 24 | 25 | public static ViewGroup getDecorView(Activity activity) { 26 | if (activity == null || activity.getWindow() == null) return null; 27 | View view = activity.getWindow().getDecorView(); 28 | if (view == null) return null; 29 | return (ViewGroup) view; 30 | } 31 | 32 | public static Drawable getDecorViewDrawable(Activity activity) { 33 | ViewGroup viewGroup = getDecorView(activity); 34 | if (viewGroup == null) return null; 35 | return viewGroup.getBackground(); 36 | } 37 | 38 | public static View getContentView(Activity activity) { 39 | ViewGroup viewGroup = getDecorView(activity); 40 | if (viewGroup == null) return null; 41 | return viewGroup.getChildAt(0); 42 | } 43 | 44 | private ActivityHelper helper;//Activity管理对象 45 | private Activity curActivity;//当前承载SlideBackHelper的Activity 46 | private Activity preActivity;//当前Activity的上一个Activity 47 | private OnSlideListener listener;//事件回调 48 | private SlideConfig config;//配置信息 49 | private ViewGroup currentContentView;//当前Activity显示的view 50 | private View preContentView;//上一个Activity显示的view 51 | 52 | /** 53 | * 附着Activity,实现侧滑 54 | * 55 | * @param activity 当前Activity 56 | * @param activityHelper Activity栈管理类 57 | * @param slideConfig 参数配置 58 | * @param slideListener 滑动的监听 59 | * @return 处理侧滑的布局,提高方法动态设置滑动相关参数 60 | */ 61 | public SlideBackLayout attach(@NonNull Activity activity, @NonNull ActivityHelper activityHelper, @Nullable SlideConfig slideConfig, @Nullable OnSlideListener slideListener) { 62 | this.helper = activityHelper; 63 | this.curActivity = activity; 64 | this.config = slideConfig; 65 | this.listener = slideListener; 66 | final ViewGroup decorView = getDecorView(curActivity); 67 | if (decorView == null) return null; 68 | final LinearLayout contentView = (LinearLayout) decorView.getChildAt(0); 69 | currentContentView = contentView.findViewById(android.R.id.content); 70 | if (currentContentView.getBackground() == null) { 71 | //延迟设置背景,防止在返回时页面未透明色 72 | //修复在某些手机直接设置背景时背景色为黑色 73 | new Handler(Looper.myLooper()).postDelayed(new Runnable() { 74 | @Override 75 | public void run() { 76 | if (currentContentView == null) return; 77 | currentContentView.setBackground(decorView.getBackground()); 78 | } 79 | }, 500); 80 | } 81 | this.preActivity = helper.getPreActivity(); 82 | preContentView = getContentView(preActivity); 83 | // if (preContentView == null){ 84 | // return null; 85 | // } 86 | decorView.removeViewAt(0); 87 | Drawable preDecorViewDrawable = getDecorViewDrawable(preActivity); 88 | SlideBackLayout slideBackLayout = new SlideBackLayout(curActivity, contentView, preContentView, preDecorViewDrawable, config, new OnInternalStateListener() { 89 | @Override 90 | public void onSlide(float percent) { 91 | if (listener != null) { 92 | listener.onSlide(percent); 93 | } 94 | } 95 | 96 | @Override 97 | public void onOpen() { 98 | if (listener != null) { 99 | listener.onOpen(); 100 | } 101 | } 102 | 103 | @Override 104 | public void onClose(Boolean finishActivity) { 105 | // finishActivity为true时关闭页面,为false时不关闭页面,为null时为其他地方关闭页面时调用SlideBackLayout.isComingToFinish的回调 106 | if (listener != null) { 107 | listener.onClose(); 108 | } 109 | if ((finishActivity == null || !finishActivity) && listener != null) { 110 | listener.onClose(); 111 | } 112 | if (config != null && config.isRotateScreen()) { 113 | if (finishActivity != null && finishActivity) { 114 | // remove了preContentView后布局会重新调整,这时候contentView回到原处,所以要设不可见 115 | contentView.setVisibility(View.INVISIBLE); 116 | } 117 | if (preActivity != null && preContentView != null && preContentView.getParent() != getDecorView(preActivity)) { 118 | // Log.e("TAG", ((SlideBackLayout) preContentView[0].getParent()).getTestName() + "这里把欠人的布局放回到上个Activity"); 119 | preContentView.setX(0); 120 | ((ViewGroup) preContentView.getParent()).removeView(preContentView); 121 | getDecorView(preActivity).addView(preContentView, 0); 122 | } 123 | } 124 | if (curActivity == null) return; 125 | curActivity.finish(); 126 | // helper.postRemoveActivity(curActivity); 127 | if (preActivity == null || preActivity.isFinishing()) { 128 | return; 129 | } 130 | curActivity.overridePendingTransition(R.anim.sback_anim_activity_none, R.anim.sback_anim_activity_none); 131 | } 132 | 133 | @Override 134 | public void onCheckPreActivity(SlideBackLayout slideBackLayout) { 135 | // Log.e("TAG", "--------------------------------------------------"); 136 | // helper.printAllActivity(); 137 | // Log.e("TAG", "--------------------------------------------------"); 138 | if (helper == null) return; 139 | Activity activity = helper.getPreActivity(); 140 | // Log.e("TAG", "SlideBackHelper-120行-onFocus(): " + preActivity[0] + ";" + activity); 141 | if (activity != preActivity) { 142 | // Log.e("TAG", "SlideBackHelper-122行-onFocus(): 上个Activity变了"); 143 | preActivity = activity; 144 | if (preActivity == null) return; 145 | preContentView = getContentView(preActivity); 146 | slideBackLayout.updatePreContentView(preContentView); 147 | } 148 | } 149 | }); 150 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 151 | decorView.addView(slideBackLayout, params); 152 | return slideBackLayout; 153 | } 154 | 155 | /** 156 | * Activity销毁时调用方法 157 | */ 158 | public void onDestroy() { 159 | this.helper = null; 160 | this.curActivity = null; 161 | this.preActivity = null; 162 | this.listener = null; 163 | this.config = null; 164 | this.currentContentView = null; 165 | this.preContentView = null; 166 | Log.d("123", "onDestroy: "); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/SlideConfig.java: -------------------------------------------------------------------------------- 1 | package com.slideback; 2 | 3 | import android.support.annotation.FloatRange; 4 | 5 | /** 6 | * Created by Oubowu on 2016/9/22 23:37. 7 | * 滑动配置 8 | */ 9 | public class SlideConfig { 10 | 11 | private boolean mEdgeOnly; 12 | private boolean mLock; 13 | 14 | @FloatRange(from = 0.0, to = 1.0) 15 | private float mEdgePercent; 16 | @FloatRange(from = 0.0, to = 1.0) 17 | private float mSlideOutPercent; 18 | 19 | private float mSlideOutVelocity; 20 | 21 | private boolean mRotateScreen; 22 | 23 | public SlideConfig() { 24 | } 25 | 26 | public boolean isEdgeOnly() { 27 | return mEdgeOnly; 28 | } 29 | 30 | public boolean isLock() { 31 | return mLock; 32 | } 33 | 34 | public float getEdgePercent() { 35 | return mEdgePercent; 36 | } 37 | 38 | public float getSlideOutPercent() { 39 | return mSlideOutPercent; 40 | } 41 | 42 | public float getSlideOutVelocity() { 43 | return mSlideOutVelocity; 44 | } 45 | 46 | /** 47 | * 屏幕是否旋转,针对是否旋转两种方案实现侧滑 48 | * 49 | * @return true为屏幕旋转,false为屏幕不旋转 50 | */ 51 | public boolean isRotateScreen() { 52 | return mRotateScreen; 53 | } 54 | 55 | public SlideConfig setEdgeOnly(boolean edgeOnly) { 56 | mEdgeOnly = edgeOnly; 57 | return this; 58 | } 59 | 60 | public SlideConfig setLock(boolean lock) { 61 | mLock = lock; 62 | return this; 63 | } 64 | 65 | public SlideConfig setEdgePercent(float edgePercent) { 66 | mEdgePercent = edgePercent; 67 | return this; 68 | } 69 | 70 | public SlideConfig setSlideOutPercent(float slideOutPercent) { 71 | mSlideOutPercent = slideOutPercent; 72 | return this; 73 | } 74 | 75 | public SlideConfig setSlideOutVelocity(float slideOutVelocity) { 76 | mSlideOutVelocity = slideOutVelocity; 77 | return this; 78 | } 79 | 80 | public SlideConfig setRotateScreen(boolean rotateScreen) { 81 | mRotateScreen = rotateScreen; 82 | return this; 83 | } 84 | 85 | 86 | // public SlideConfig(Builder builder) { 87 | // mEdgeOnly = builder.edgeOnly; 88 | // mLock = builder.lock; 89 | // mEdgePercent = builder.edgePercent; 90 | // mSlideOutPercent = builder.slideOutPercent; 91 | // mSlideOutVelocity = builder.slideOutVelocity; 92 | // mRotateScreen = builder.rotateScreen; 93 | // } 94 | 95 | // public static class Builder { 96 | // 97 | // private boolean edgeOnly = false; 98 | // private boolean lock = false; 99 | // 100 | // @FloatRange(from = 0.0, 101 | // to = 1.0) 102 | // private float edgePercent = 0.4f; 103 | // @FloatRange(from = 0.0, 104 | // to = 1.0) 105 | // private float slideOutPercent = 0.1f; 106 | // 107 | // private float slideOutVelocity = 2000f; 108 | // 109 | // private boolean rotateScreen = false; 110 | // 111 | // public Builder() { 112 | // } 113 | // 114 | // public SlideConfig create() { 115 | // return new SlideConfig(this); 116 | // } 117 | // 118 | // public Builder edgeOnly(boolean edgeOnly) { 119 | // this.edgeOnly = edgeOnly; 120 | // return this; 121 | // } 122 | // 123 | // public Builder lock(boolean lock) { 124 | // this.lock = lock; 125 | // return this; 126 | // } 127 | // 128 | // public Builder slideOutVelocity(float slideOutVelocity) { 129 | // this.slideOutVelocity = slideOutVelocity; 130 | // return this; 131 | // } 132 | // 133 | // public Builder edgePercent(@FloatRange(from = 0.0, 134 | // to = 1.0) float edgePercent) { 135 | // this.edgePercent = edgePercent; 136 | // return this; 137 | // } 138 | // 139 | // public Builder slideOutPercent(@FloatRange(from = 0.0, 140 | // to = 1.0) float slideOutPercent) { 141 | // this.slideOutPercent = slideOutPercent; 142 | // return this; 143 | // } 144 | // 145 | // /** 146 | // * 屏幕是否旋转,针对是否旋转两种方案实现侧滑 147 | // * 148 | // * @return true为屏幕旋转,false为屏幕不旋转 149 | // */ 150 | // public Builder rotateScreen(boolean rotateScreen) { 151 | // this.rotateScreen = rotateScreen; 152 | // return this; 153 | // } 154 | // 155 | // } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/callbak/OnInternalStateListener.java: -------------------------------------------------------------------------------- 1 | package com.slideback.callbak; 2 | 3 | import android.support.annotation.FloatRange; 4 | 5 | import com.slideback.widget.SlideBackLayout; 6 | 7 | /** 8 | * Created by Oubowu on 2016/9/22 0022 18:22. 9 | */ 10 | public interface OnInternalStateListener { 11 | 12 | void onSlide(@FloatRange(from = 0.0, 13 | to = 1.0) float percent); 14 | 15 | void onOpen(); 16 | 17 | void onClose(Boolean finishActivity); 18 | 19 | void onCheckPreActivity(SlideBackLayout slideBackLayout); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/callbak/OnSlideListener.java: -------------------------------------------------------------------------------- 1 | package com.slideback.callbak; 2 | 3 | import android.support.annotation.FloatRange; 4 | 5 | /** 6 | * Created by Oubowu on 2016/9/22 0022 18:22. 7 | */ 8 | public interface OnSlideListener { 9 | 10 | void onSlide(@FloatRange(from = 0.0, 11 | to = 1.0) float percent); 12 | 13 | void onOpen(); 14 | 15 | void onClose(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/callbak/OnSlideListenerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.slideback.callbak; 2 | 3 | import android.support.annotation.FloatRange; 4 | 5 | /** 6 | * Created by Oubowu on 2016/9/23 0:05. 7 | */ 8 | public class OnSlideListenerAdapter implements OnSlideListener { 9 | @Override 10 | public void onSlide(@FloatRange(from = 0.0, 11 | to = 1.0) float percent) { 12 | } 13 | 14 | @Override 15 | public void onOpen() { 16 | 17 | } 18 | 19 | @Override 20 | public void onClose() { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/widget/CacheDrawView.java: -------------------------------------------------------------------------------- 1 | package com.slideback.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.view.View; 6 | 7 | 8 | /** 9 | * Created by Oubowu on 2016/9/20 0020 11:19. 10 | * 11 | */ 12 | public class CacheDrawView extends View { 13 | 14 | private View mCacheView; 15 | 16 | public CacheDrawView(Context context) { 17 | super(context); 18 | } 19 | 20 | public void drawCacheView(View cacheView) { 21 | mCacheView = cacheView; 22 | invalidate(); 23 | } 24 | 25 | @Override 26 | protected void onDraw(Canvas canvas) { 27 | if (mCacheView != null) { 28 | // canvas.drawColor(Color.YELLOW); 29 | mCacheView.draw(canvas); 30 | // Log.e("TAG", "绘制上个Activity的内容视图..."); 31 | } 32 | } 33 | 34 | @Override 35 | protected void onDetachedFromWindow() { 36 | super.onDetachedFromWindow(); 37 | // Log.e("TAG", "CacheDrawView-37行-onDetachedFromWindow(): "); 38 | mCacheView = null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/widget/ShadowView.java: -------------------------------------------------------------------------------- 1 | package com.slideback.widget; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.res.Configuration; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.LinearGradient; 9 | import android.graphics.Paint; 10 | import android.graphics.RectF; 11 | import android.graphics.Shader; 12 | import android.support.annotation.FloatRange; 13 | import android.view.View; 14 | 15 | /** 16 | * Created by Oubowu on 2016/9/20 0020 11:22. 17 | */ 18 | public class ShadowView extends View { 19 | 20 | private LinearGradient mLinearGradient; 21 | private Paint mPaint; 22 | private RectF mRectF; 23 | private float mAlphaPercent = -1; 24 | 25 | public ShadowView(Context context) { 26 | super(context); 27 | mPaint = new Paint(); 28 | } 29 | 30 | @Override 31 | protected void onDraw(Canvas canvas) { 32 | if (mAlphaPercent >= 0) { 33 | // 绘制渐变阴影 34 | if (mLinearGradient == null) { 35 | mRectF = new RectF(); 36 | int[] colors = {Color.parseColor("#05000000"), Color.parseColor("#22000000"), Color.parseColor("#55000000")}; 37 | // 我设置着色器开始的位置为(0,0),结束位置为(getWidth(), 0)表示我的着色器要给整个View在水平方向上渲染 38 | mLinearGradient = new LinearGradient(0, 0, getWidth(), 0, colors, null, Shader.TileMode.REPEAT); 39 | mPaint.setShader(mLinearGradient); 40 | mRectF.set(0, 0, getWidth(), getHeight()); 41 | } 42 | mPaint.setAlpha((int) (mAlphaPercent * 255)); 43 | canvas.drawRect(mRectF, mPaint); 44 | } 45 | } 46 | 47 | public void redraw(@FloatRange(from = 0.0, to = 1.0) float alphaPercent) { 48 | mAlphaPercent = alphaPercent; 49 | invalidate(); 50 | } 51 | 52 | @Override 53 | protected void onConfigurationChanged(Configuration newConfig) { 54 | super.onConfigurationChanged(newConfig); 55 | mLinearGradient = null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/java/com/slideback/widget/SlideBackLayout.java: -------------------------------------------------------------------------------- 1 | package com.slideback.widget; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.Configuration; 6 | import android.graphics.drawable.Drawable; 7 | import android.support.annotation.FloatRange; 8 | import android.support.annotation.NonNull; 9 | import android.support.v4.view.ViewGroupCompat; 10 | import android.support.v4.widget.ViewDragHelper; 11 | import android.util.Log; 12 | import android.view.MotionEvent; 13 | import android.view.VelocityTracker; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.widget.FrameLayout; 17 | 18 | import com.slideback.SlideConfig; 19 | import com.slideback.callbak.OnInternalStateListener; 20 | 21 | /** 22 | * Created by Oubowu on 2016/9/22 0022 15:24. 23 | * 滑动控制类 24 | */ 25 | public class SlideBackLayout extends FrameLayout { 26 | 27 | private static final int MIN_FLING_VELOCITY = 400; 28 | // private final String mTestName; 29 | private boolean mCheckPreContentView; 30 | private boolean mIsFirstAttachToWindow; 31 | private ViewDragHelper mDragHelper; 32 | private View mContentView; 33 | private CacheDrawView mCacheDrawView; 34 | private ShadowView mShadowView; 35 | private View mPreContentView; 36 | private Drawable mPreDecorViewDrawable; 37 | private int mScreenWidth; 38 | //是否关闭全局侧滑 39 | private boolean mEdgeOnly = false; 40 | //是否关闭侧滑 41 | private boolean mLock = false; 42 | //是否可以滑动 43 | private boolean isSlideBack = true; 44 | 45 | @FloatRange(from = 0.0, to = 1.0) 46 | private float mSlideOutRangePercent = 0.4f; 47 | @FloatRange(from = 0.0, to = 1.0) 48 | private float mEdgeRangePercent = 0.1f; 49 | 50 | private float mSlideOutRange; 51 | private float mEdgeRange; 52 | 53 | private float mSlideOutVelocity; 54 | 55 | private boolean mIsEdgeRangeInside; 56 | 57 | private OnInternalStateListener mOnInternalStateListener; 58 | //按下的点 59 | private float mDownX; 60 | //开始滑动时的点 61 | private float mDownStartX; 62 | 63 | private float mSlidDistantX; 64 | 65 | private boolean mRotateScreen; 66 | 67 | private boolean mCloseFlagForWindowFocus; 68 | private boolean mCloseFlagForDetached; 69 | private boolean mEnableTouchEvent; 70 | //鼠标移动 71 | private VelocityTracker mVelocityTracker; 72 | 73 | public SlideBackLayout(Context context, View contentView, View preContentView, Drawable preDecorViewDrawable, SlideConfig config, @NonNull OnInternalStateListener onInternalStateListener) { 74 | super(context); 75 | mContentView = contentView; 76 | mPreContentView = preContentView; 77 | mPreDecorViewDrawable = preDecorViewDrawable; 78 | mOnInternalStateListener = onInternalStateListener; 79 | 80 | initConfig(config); 81 | 82 | // if (preContentView != null && preContentView instanceof LinearLayout) { 83 | // mTestName = "1号滑动"; 84 | // } else { 85 | // mTestName = "2号滑动"; 86 | // } 87 | } 88 | 89 | private void initConfig(SlideConfig config) { 90 | if (config == null) { 91 | config = new SlideConfig(); 92 | } 93 | mScreenWidth = getResources().getDisplayMetrics().widthPixels; 94 | final float density = getResources().getDisplayMetrics().density; 95 | final float minVel = MIN_FLING_VELOCITY * density; 96 | 97 | ViewGroupCompat.setMotionEventSplittingEnabled(this, false); 98 | SlideLeftCallback slideLeftCallback = new SlideLeftCallback(); 99 | mDragHelper = ViewDragHelper.create(this, 1.0f, slideLeftCallback); 100 | // 最小拖动速度 101 | mDragHelper.setMinVelocity(minVel); 102 | mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); 103 | 104 | mCacheDrawView = new CacheDrawView(getContext()); 105 | mCacheDrawView.setVisibility(INVISIBLE); 106 | addView(mCacheDrawView); 107 | 108 | mShadowView = new ShadowView(getContext()); 109 | mShadowView.setVisibility(INVISIBLE); 110 | addView(mShadowView, mScreenWidth / 28, LayoutParams.MATCH_PARENT); 111 | 112 | addView(mContentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 113 | 114 | mEdgeOnly = config.isEdgeOnly(); 115 | mLock = config.isLock(); 116 | mRotateScreen = config.isRotateScreen(); 117 | 118 | mSlideOutRangePercent = config.getSlideOutPercent(); 119 | mEdgeRangePercent = config.getEdgePercent(); 120 | 121 | mSlideOutRange = mScreenWidth * mSlideOutRangePercent; 122 | mEdgeRange = mScreenWidth * mEdgeRangePercent; 123 | mSlideOutVelocity = config.getSlideOutVelocity(); 124 | 125 | mSlidDistantX = mScreenWidth / 20.0f; 126 | 127 | mContentView.setFitsSystemWindows(false); 128 | // mContentView.getFitsSystemWindows() 129 | if (mRotateScreen) { 130 | mContentView.findViewById(android.R.id.content).setOnClickListener(new OnClickListener() { 131 | @Override 132 | public void onClick(View v) { 133 | // 屏蔽上个内容页的点击事件 134 | } 135 | }); 136 | } 137 | } 138 | 139 | @Override 140 | public boolean onInterceptTouchEvent(MotionEvent event) { 141 | if (mLock) {//是否关闭侧滑 142 | return false; 143 | } 144 | mDownStartX = event.getX(); 145 | switch (event.getAction()) { 146 | case MotionEvent.ACTION_DOWN: 147 | mDownX = mDownStartX; 148 | isSlideBack = isSlide(); 149 | // Log.d("123", "onInterceptTouchEvent: 按下事件"); 150 | break; 151 | case MotionEvent.ACTION_MOVE: 152 | // 优化侧滑的逻辑,不要一有稍微的滑动就被ViewDragHelper拦截掉了 153 | if (mDownStartX - mDownX < mSlidDistantX) { 154 | // Log.d("123", "onInterceptTouchEvent: 滑动没有拦截"); 155 | return false; 156 | } 157 | // Log.d("123", "onInterceptTouchEvent: 滑动继续执行"); 158 | break; 159 | } 160 | if (isSlideBack) { 161 | if (mEdgeOnly) {//是否关闭全局侧滑 162 | mIsEdgeRangeInside = isEdgeRangeInside(mDownStartX); 163 | return mIsEdgeRangeInside && mDragHelper.shouldInterceptTouchEvent(event); 164 | } else {//开启全局侧滑 165 | return mDragHelper.shouldInterceptTouchEvent(event); 166 | } 167 | } else { 168 | // Log.d("123", "onInterceptTouchEvent: 上个页面被销毁:" + event.getAction()); 169 | mIsEdgeRangeInside = isEdgeRangeInside(mDownX); 170 | if (MotionEvent.ACTION_MOVE != event.getAction()) { 171 | // Log.d("123", "onInterceptTouchEvent: 不是滑动"); 172 | return false; 173 | } 174 | // Log.d("123", "onInterceptTouchEvent: " + mEdgeOnly + ",mDownX:" + isEdgeRangeInside(mDownX)); 175 | return !mEdgeOnly || mIsEdgeRangeInside; 176 | } 177 | } 178 | 179 | /** 180 | * 是否在监听滑动范围 181 | */ 182 | private boolean isEdgeRangeInside(float x) { 183 | return x <= mEdgeRange; 184 | } 185 | 186 | @Override 187 | public boolean onTouchEvent(MotionEvent event) { 188 | if (mLock) { 189 | return super.onTouchEvent(event); 190 | } 191 | // Log.d("123", "onTouchEvent: 开始监听"); 192 | if (mEdgeOnly && !mIsEdgeRangeInside) { 193 | return super.onTouchEvent(event); 194 | } 195 | // Log.d("123", "onTouchEvent: mEnableTouchEvent:" + mEnableTouchEvent); 196 | if (!mEnableTouchEvent) { 197 | return super.onTouchEvent(event); 198 | } 199 | if (mCloseFlagForDetached || mCloseFlagForWindowFocus) { 200 | // 针对快速滑动的时候,页面关闭的时候移除上个页面的时候,布局重新调整,这时候我们把contentView设为invisible, 201 | // 但是还是可以响应DragHelper的处理,所以这里根据页面关闭的标志位不给处理事件了 202 | // Log.e("TAG", mTestName + "都要死了,还处理什么触摸事件!!"); 203 | return super.onTouchEvent(event); 204 | } 205 | if (isSlideBack) { 206 | // Log.d("123", "onTouchEvent: 上个页面没有销毁"); 207 | mDragHelper.processTouchEvent(event); 208 | } else { 209 | // Log.d("123", "onTouchEvent: 上个页面被销毁"); 210 | switch (event.getAction()) { 211 | case MotionEvent.ACTION_POINTER_UP: 212 | case MotionEvent.ACTION_UP: 213 | case MotionEvent.ACTION_CANCEL: 214 | //intunitis表示速率的基本时间单位。unitis值为1的表示是, 215 | // 一毫秒时间单位内运动了多少个像素, unitis值为1000表示一秒(1000毫秒)时间单位内运动了多少个像素 216 | mVelocityTracker.computeCurrentVelocity(1000); 217 | if (getXVelocity() >= mDragHelper.getMinVelocity() * 0.8 || event.getX() - mDownStartX >= mSlideOutRange) { 218 | //关闭页面 219 | mCloseFlagForWindowFocus = true; 220 | mCloseFlagForDetached = true; 221 | mOnInternalStateListener.onClose(true); 222 | } 223 | cancelVelocity(); 224 | return true; 225 | default: 226 | addMovement(event); 227 | break; 228 | } 229 | } 230 | return true; 231 | } 232 | 233 | public void addMovement(MotionEvent event) { 234 | if (mVelocityTracker == null) { 235 | mVelocityTracker = VelocityTracker.obtain(); 236 | } 237 | mVelocityTracker.addMovement(event); 238 | } 239 | 240 | private float getXVelocity() { 241 | if (mVelocityTracker == null) { 242 | return 0; 243 | } 244 | return mVelocityTracker.getXVelocity(); 245 | } 246 | 247 | public void cancelVelocity() { 248 | if (mVelocityTracker != null) { 249 | mVelocityTracker.recycle(); 250 | mVelocityTracker = null; 251 | } 252 | } 253 | 254 | private void addPreContentView() { 255 | if (isSlideBack) return; 256 | if (mPreContentView != null && mPreContentView.getParent() != SlideBackLayout.this) { 257 | // Log.e("TAG", mTestName + ": 我要把上个页面的内容页加到我这里啦!"); 258 | mPreContentView.setTag("notScreenOrientationChange"); 259 | ViewGroup viewGroup = (ViewGroup) mPreContentView.getParent(); 260 | if (viewGroup != null) 261 | viewGroup.removeView(mPreContentView); 262 | SlideBackLayout.this.addView(mPreContentView, 0); 263 | mShadowView.setVisibility(VISIBLE); 264 | } 265 | } 266 | 267 | @Override 268 | public void computeScroll() { 269 | if (mDragHelper.continueSettling(true)) { 270 | invalidate(); 271 | } 272 | } 273 | 274 | public void isComingToFinish() { 275 | if (mRotateScreen) { 276 | mCloseFlagForDetached = true; 277 | mCloseFlagForWindowFocus = false; 278 | mOnInternalStateListener.onClose(null); 279 | if (mPreContentView != null) 280 | mPreContentView.setX(0); 281 | } 282 | } 283 | 284 | public void updatePreContentView(View contentView) { 285 | mPreContentView = contentView; 286 | mCacheDrawView.drawCacheView(mPreContentView); 287 | } 288 | 289 | private boolean isSlide() { 290 | if (mPreContentView == null) return false; 291 | Context context = mPreContentView.getContext(); 292 | if (context == null || !(context instanceof Activity) || ((Activity) context).isFinishing()) { 293 | return false; 294 | } 295 | return true; 296 | } 297 | 298 | private class SlideLeftCallback extends ViewDragHelper.Callback { 299 | 300 | @Override 301 | public boolean tryCaptureView(View child, int pointerId) { 302 | //是否可以移动 303 | return isSlideBack && child == mContentView; 304 | } 305 | 306 | @Override 307 | public int clampViewPositionHorizontal(View child, int left, int dx) { 308 | //分别为即将移动到的位置,比如横向的情况下,我希望只在ViewGroup的内部移动, 309 | //即:最小>=paddingleft,最大<=ViewGroup.getWidth()-paddingright-child.getWidth 310 | return Math.max(Math.min(mScreenWidth, left), 0); 311 | } 312 | 313 | @Override 314 | public int getViewHorizontalDragRange(View child) { 315 | return mScreenWidth; 316 | } 317 | 318 | @Override 319 | public void onViewReleased(View releasedChild, float xvel, float yvel) { 320 | //手指抬起时回调方法 321 | if (!isSlideBack) { 322 | return; 323 | } 324 | if (releasedChild == mContentView) { 325 | if (xvel > mSlideOutVelocity) { 326 | mDragHelper.settleCapturedViewAt(mScreenWidth, 0); 327 | invalidate(); 328 | return; 329 | } 330 | if (mContentView.getLeft() < mSlideOutRange) { 331 | mDragHelper.settleCapturedViewAt(0, 0); 332 | } else { 333 | mDragHelper.settleCapturedViewAt(mScreenWidth, 0); 334 | } 335 | invalidate(); 336 | } 337 | } 338 | 339 | @Override 340 | public void onViewDragStateChanged(int state) { 341 | if (!isSlideBack) { 342 | return; 343 | } 344 | switch (state) { 345 | case ViewDragHelper.STATE_IDLE: 346 | if (mContentView.getLeft() == 0) { 347 | // 2016/9/22 0022 回到原处 348 | mOnInternalStateListener.onOpen(); 349 | } else if (mContentView.getLeft() == mScreenWidth) { 350 | // 2016/9/22 0022 结束Activity 351 | // 这里再绘制一次是因为在屏幕旋转的模式下,remove了preContentView后布局会重新调整 352 | if (mRotateScreen && mCacheDrawView.getVisibility() == INVISIBLE) { 353 | mCacheDrawView.setBackground(mPreDecorViewDrawable); 354 | if (mPreContentView != null) 355 | mCacheDrawView.drawCacheView(mPreContentView); 356 | mCacheDrawView.setVisibility(VISIBLE); 357 | // Log.e("TAG", mTestName + ": 这里再绘制一次是因为在屏幕旋转的模式下,remove了preContentView后布局会重新调整"); 358 | mCloseFlagForWindowFocus = true; 359 | mCloseFlagForDetached = true; 360 | // Log.e("TAG", mTestName + ": 滑动到尽头了这个界面要死了,把preContentView给回上个Activity"); 361 | // 这里setTag是因为下面的回调会把它移除出当前页面,这时候会触发它的onDetachedFromWindow事件, 362 | // 而它的onDetachedFromWindow实际上是来处理屏幕旋转的,所以设置个tag给它,让它知道是当前界面移除它的,并不是屏幕旋转导致的 363 | if (mPreContentView != null) 364 | mPreContentView.setTag("notScreenOrientationChange"); 365 | mOnInternalStateListener.onClose(true); 366 | if (mPreContentView != null) 367 | mPreContentView.postDelayed(new Runnable() { 368 | @Override 369 | public void run() { 370 | mCacheDrawView.setBackground(mPreDecorViewDrawable); 371 | mCacheDrawView.drawCacheView(mPreContentView); 372 | } 373 | }, 10); 374 | } else if (!mRotateScreen) { 375 | mCloseFlagForWindowFocus = true; 376 | mCloseFlagForDetached = true; 377 | mOnInternalStateListener.onClose(true); 378 | } 379 | } 380 | break; 381 | default: 382 | break; 383 | } 384 | } 385 | 386 | @Override 387 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 388 | if (!mRotateScreen && mCacheDrawView.getVisibility() == INVISIBLE) { 389 | mCacheDrawView.setBackground(mPreDecorViewDrawable); 390 | if (mPreContentView != null) 391 | mCacheDrawView.drawCacheView(mPreContentView); 392 | mCacheDrawView.setVisibility(VISIBLE); 393 | } else if (mRotateScreen) { 394 | if (!mCheckPreContentView) { 395 | // 在旋转屏幕的模式下,这里的检查很有必要,比如一个滑动activity先旋转了屏幕,然后再返回上个滑动activity的时候,由于屏幕旋转上个activity会重建,步骤是: 396 | // 上个activity会先新建一个activity,再把之前的销毁,所以新建的activity调SlideBackLayout.attach的时候传的上个activity实际上是要删掉的activity 397 | // (因为要删掉的activity的destroy有延时的,还没销毁掉),这就出错了; 398 | // 所以这里还要在当前页面取得焦点的时候回调,去检查下看是不是上个activity改了,改了再重新赋值 399 | mCheckPreContentView = true; 400 | // 只需要检查一次上个Activity是不是变了 401 | // Log.e("TAG","只需要检查一次上个Activity是不是变了"); 402 | mOnInternalStateListener.onCheckPreActivity(SlideBackLayout.this); 403 | } 404 | addPreContentView(); 405 | } 406 | if (mShadowView.getVisibility() != VISIBLE) { 407 | mShadowView.setVisibility(VISIBLE); 408 | } 409 | final float percent = left * 1.0f / mScreenWidth; 410 | mOnInternalStateListener.onSlide(percent); 411 | if (mRotateScreen) { 412 | // // Log.e("TAG", "滑动上个页面"); 413 | if (mPreContentView != null) 414 | mPreContentView.setX(-mScreenWidth / 2 + percent * (mScreenWidth / 2)); 415 | } else { 416 | mCacheDrawView.setX(-mScreenWidth / 2 + percent * (mScreenWidth / 2)); 417 | } 418 | mShadowView.setX(mContentView.getX() - mShadowView.getWidth()); 419 | mShadowView.redraw(1 - percent); 420 | } 421 | } 422 | 423 | public void edgeOnly(boolean edgeOnly) { 424 | mEdgeOnly = edgeOnly; 425 | } 426 | 427 | public boolean isEdgeOnly() { 428 | return mEdgeOnly; 429 | } 430 | 431 | public void lock(boolean lock) { 432 | mLock = lock; 433 | } 434 | 435 | public boolean isLock() { 436 | return mLock; 437 | } 438 | 439 | public void setSlideOutRangePercent(float slideOutRangePercent) { 440 | mSlideOutRangePercent = slideOutRangePercent; 441 | mSlideOutRange = mScreenWidth * mSlideOutRangePercent; 442 | } 443 | 444 | public float getSlideOutRangePercent() { 445 | return mSlideOutRangePercent; 446 | } 447 | 448 | public void setEdgeRangePercent(float edgeRangePercent) { 449 | mEdgeRangePercent = edgeRangePercent; 450 | mEdgeRange = mScreenWidth * mEdgeRangePercent; 451 | } 452 | 453 | public float getEdgeRangePercent() { 454 | return mEdgeRangePercent; 455 | } 456 | 457 | @Override 458 | public void onWindowFocusChanged(boolean hasWindowFocus) { 459 | super.onWindowFocusChanged(hasWindowFocus); 460 | if (hasWindowFocus) { 461 | mEnableTouchEvent = true; 462 | // 当前页面 463 | if (!mIsFirstAttachToWindow) { 464 | mIsFirstAttachToWindow = true; 465 | } 466 | } else { 467 | if (mRotateScreen) { 468 | // 1.跳转到另外一个Activity,例如也是需要滑动的,这时候就需要取当前Activity的contentView,所以这里把preContentView给回上个Activity 469 | if (mCloseFlagForWindowFocus) { 470 | mCloseFlagForWindowFocus = false; 471 | // Log.e("TAG", mTestName + ": onWindowFocusChanged前已经调了关闭"); 472 | } else { 473 | // Log.e("TAG", mTestName + ": 跳转到另外一个Activity,取这个Activity的contentView前把preContentView给回上个Activity"); 474 | mOnInternalStateListener.onClose(false); 475 | } 476 | } 477 | } 478 | } 479 | 480 | @Override 481 | protected void onDetachedFromWindow() { 482 | super.onDetachedFromWindow(); 483 | mEnableTouchEvent = false; 484 | cancelVelocity(); 485 | // // Log.e("TAG", "SlideBackLayout-345行-onDetachedFromWindow(): " + this); 486 | if (mRotateScreen) { 487 | // 1.旋转屏幕的时候必调此方法,这里掉onClose目的是把preContentView给回上个Activity 488 | if (mCloseFlagForDetached) { 489 | mCloseFlagForDetached = false; 490 | // Log.e("TAG", mTestName + ": onDetachedFromWindow(): " + "已经调了关闭"); 491 | } else { 492 | if (getTag() != null && getTag().equals("notScreenOrientationChange")) { 493 | // 说明是手动删的不关旋转屏幕的事,所以不处理 494 | // Log.e("TAG", mTestName + ":说明是手动删的不关旋转屏幕的事,所以不处理"); 495 | setTag(null); 496 | } else { 497 | // Log.e("TAG", mTestName + ":屏幕旋转了,重建界面: 把preContentView给回上个Activity"); 498 | mOnInternalStateListener.onClose(false); 499 | } 500 | } 501 | } 502 | } 503 | 504 | @Override 505 | protected void onConfigurationChanged(Configuration newConfig) { 506 | super.onConfigurationChanged(newConfig); 507 | mScreenWidth = getResources().getDisplayMetrics().widthPixels; 508 | // Log.e("TAG", mTestName + ": SlideBackLayout-338行-onConfigurationChanged(): " + mScreenWidth); 509 | ViewGroup.LayoutParams layoutParams = mShadowView.getLayoutParams(); 510 | layoutParams.width = mScreenWidth / 28; 511 | layoutParams.height = LayoutParams.MATCH_PARENT; 512 | } 513 | 514 | /** 515 | * 上一个页面被关闭 516 | */ 517 | public void setPreContentDestroy() { 518 | mPreContentView = null; 519 | Log.d("123", "上个页面被关闭了"); 520 | } 521 | 522 | } 523 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/anim/anim_out_none.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/anim/sback_anim_activity_none.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/anim/sback_close_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/anim/sback_close_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/anim/sback_open_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/anim/sback_open_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/drawable/sliding_back_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/layout/slide_back_default_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sideBackLibrary/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | --------------------------------------------------------------------------------