├── .idea ├── .name ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── vcs.xml ├── modules.xml ├── runConfigurations.xml ├── gradle.xml ├── compiler.xml └── misc.xml ├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── attrs.xml │ │ │ ├── drawable-hdpi │ │ │ │ └── app_launcher.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── expert_default.jpg │ │ │ │ └── expert_list_bg_default.jpg │ │ │ ├── drawable │ │ │ │ └── shape_bg_item.xml │ │ │ └── layout │ │ │ │ ├── main_activity.xml │ │ │ │ └── item_viewpager.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── upc │ │ │ └── viewpagerGallery │ │ │ ├── View │ │ │ ├── ZoomOutPageTransformer.java │ │ │ └── RoundImageView.java │ │ │ └── Activity │ │ │ ├── ViewPagerGalleryActivity.java │ │ │ └── SystemBarTintManager.java │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── upc │ │ │ └── viewpagerGallery │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── upc │ │ └── viewpagerGallery │ │ └── ApplicationTest.java ├── proguard-rules.pro ├── build.gradle └── app.iml ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── README.md ├── gradle.properties ├── ViewPagerGallery.iml ├── gradlew.bat └── gradlew /.idea/.name: -------------------------------------------------------------------------------- 1 | ViewPagerGallery -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ViewPagerGallery 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qloop/ViewPager-Gallery-/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/app_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qloop/ViewPager-Gallery-/HEAD/app/src/main/res/drawable-hdpi/app_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/expert_default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qloop/ViewPager-Gallery-/HEAD/app/src/main/res/drawable-xxhdpi/expert_default.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/expert_list_bg_default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qloop/ViewPager-Gallery-/HEAD/app/src/main/res/drawable-xxhdpi/expert_list_bg_default.jpg -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15dp 4 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Mar 27 12:54:15 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ViewPager-Gallery- 2 | ViewPager实现Gallery——仿慕课网app“职业路线计划”效果 3 | 4 | ### 实现效果: 5 | 6 | http://img.blog.csdn.net/20160327133530993 7 | 8 | 点开链接就可以看到 9 | 10 | 具体实现过程请看我的博客: 11 | http://blog.csdn.net/CodeNoodles/article/details/50992113 12 | 13 | 如果喜欢这个效果请start or fork吧>。< 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #89000000 7 | 8 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/com/upc/viewpagerGallery/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.upc.viewpagerGallery; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/upc/viewpagerGallery/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.upc.viewpagerGallery; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /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:\AndroidStudio/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.upc.viewpagerGallery" 9 | minSdkVersion 16 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.2.0' 26 | } 27 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Sun Mar 27 12:54:31 CST 2016 16 | systemProp.http.proxyHost=localhost 17 | systemProp.http.proxyPort=1080 18 | -------------------------------------------------------------------------------- /ViewPagerGallery.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 19 | 20 | 31 | 32 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/upc/viewpagerGallery/View/ZoomOutPageTransformer.java: -------------------------------------------------------------------------------- 1 | package com.upc.viewpagerGallery.View; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by Explorer on 2016/3/26. 8 | */ 9 | public class ZoomOutPageTransformer implements ViewPager.PageTransformer { 10 | 11 | private static final float MIN_SCALE = 0.9f; 12 | private static final float MIN_ALPHA = 0.5f; 13 | 14 | private static float defaultScale = 0.9f; 15 | 16 | public void transformPage(View view, float position) { 17 | int pageWidth = view.getWidth(); 18 | int pageHeight = view.getHeight(); 19 | 20 | if (position < -1) { // [-Infinity,-1) 21 | // This page is way off-screen to the left. 22 | // view.setAlpha(0); 23 | view.setScaleX(defaultScale); 24 | view.setScaleY(defaultScale); 25 | } else if (position <= 1) { // [-1,1] 26 | // Modify the default slide transition to shrink the page as well 27 | float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); 28 | float vertMargin = pageHeight * (1 - scaleFactor) / 2; 29 | float horzMargin = pageWidth * (1 - scaleFactor) / 2; 30 | if (position < 0) { 31 | view.setTranslationX(horzMargin - vertMargin / 2); 32 | } else { 33 | view.setTranslationX(-horzMargin + vertMargin / 2); 34 | } 35 | 36 | // Scale the page down (between MIN_SCALE and 1) 37 | view.setScaleX(scaleFactor); 38 | view.setScaleY(scaleFactor); 39 | 40 | // Fade the page relative to its size. 41 | // view.setAlpha(MIN_ALPHA + 42 | // (scaleFactor - MIN_SCALE) / 43 | // (1 - MIN_SCALE) * (1 - MIN_ALPHA)); 44 | 45 | } else { // (1,+Infinity] 46 | // This page is way off-screen to the right. 47 | // view.setAlpha(0); 48 | view.setScaleX(defaultScale); 49 | view.setScaleY(defaultScale); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.7 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_viewpager.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 15 | 23 | 24 | 33 | 34 | 46 | 47 | 53 | 54 | 62 | 63 | 70 | 71 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/upc/viewpagerGallery/Activity/ViewPagerGalleryActivity.java: -------------------------------------------------------------------------------- 1 | package com.upc.viewpagerGallery.Activity; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.v4.view.PagerAdapter; 8 | import android.support.v4.view.ViewPager; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.Window; 12 | import android.view.WindowManager; 13 | import android.widget.ImageView; 14 | import android.widget.RelativeLayout; 15 | import android.widget.TextView; 16 | 17 | import com.upc.viewpagerGallery.R; 18 | 19 | import java.util.LinkedList; 20 | 21 | /** 22 | * Created by Explorer on 2016/3/27. 23 | */ 24 | public class ViewPagerGalleryActivity extends Activity { 25 | 26 | 27 | private ViewPager mViewPager; 28 | private ImageView ivBgPic; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 34 | setTranslucentStatus(true); 35 | SystemBarTintManager tintManager = new SystemBarTintManager(this); 36 | tintManager.setStatusBarTintEnabled(true); 37 | tintManager.setStatusBarTintResource(R.color.statusbar_color);//通知栏所需颜色 38 | } 39 | 40 | setContentView(R.layout.main_activity); 41 | initViews(); 42 | } 43 | 44 | @TargetApi(19) 45 | private void setTranslucentStatus(boolean on) { 46 | Window win = getWindow(); 47 | WindowManager.LayoutParams winParams = win.getAttributes(); 48 | final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 49 | if (on) { 50 | winParams.flags |= bits; 51 | } else { 52 | winParams.flags &= ~bits; 53 | } 54 | win.setAttributes(winParams); 55 | } 56 | 57 | private void initViews() { 58 | mViewPager = (ViewPager) findViewById(R.id.vp_pager); 59 | ivBgPic = (ImageView) findViewById(R.id.iv_bg_pic); 60 | mViewPager.setOffscreenPageLimit(3); 61 | mViewPager.setPageTransformer(true, new com.upc.viewpagerGallery.View.ZoomOutPageTransformer()); 62 | mViewPager.setPageMargin(getResources().getDimensionPixelSize(R.dimen.page_margin)); 63 | 64 | MyViewPagerAdapter mAdapter = new MyViewPagerAdapter(); 65 | mViewPager.setAdapter(mAdapter); 66 | mViewPager.setOffscreenPageLimit(mAdapter.getCount()); 67 | } 68 | 69 | 70 | 71 | 72 | /** 73 | * Viewpager数据适配器 74 | */ 75 | class MyViewPagerAdapter extends PagerAdapter { 76 | 77 | //view复用 78 | private LinkedList mViewCache = null; 79 | 80 | public MyViewPagerAdapter() { 81 | mViewCache = new LinkedList<>(); 82 | } 83 | 84 | @Override 85 | public int getCount() { 86 | return 6; 87 | } 88 | 89 | @Override 90 | public boolean isViewFromObject(View view, Object object) { 91 | return view == object; 92 | } 93 | 94 | 95 | @Override 96 | public Object instantiateItem(ViewGroup container, int position) { 97 | ViewHolder holder = null; 98 | View convertView = null; 99 | if (mViewCache.size() == 0) { 100 | convertView = View.inflate(ViewPagerGalleryActivity.this, R.layout.item_viewpager, null); 101 | holder = new ViewHolder(); 102 | holder.ivPic = (ImageView) convertView.findViewById(R.id.iv_title_pic); 103 | holder.tvName = (TextView) convertView.findViewById(R.id.tv_exper_name); 104 | holder.tvNum = (TextView) convertView.findViewById(R.id.tv_num); 105 | holder.vLine = convertView.findViewById(R.id.v_line); 106 | 107 | convertView.setTag(holder); 108 | } else { 109 | convertView = mViewCache.removeFirst(); 110 | holder = (ViewHolder) convertView.getTag(); 111 | } 112 | 113 | 114 | holder.ivPic.setImageResource(R.drawable.expert_default); 115 | holder.tvName.setText("Android工程师"); 116 | holder.tvNum.setText("39179"); 117 | 118 | /* 动态设置view 横线 让它和上方的文字等宽*/ 119 | holder.tvName.measure(0, 0); 120 | int measuredWidth = holder.tvName.getMeasuredWidth(); 121 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(measuredWidth, 1); 122 | params.addRule(RelativeLayout.BELOW, R.id.tv_exper_name); 123 | params.addRule(RelativeLayout.CENTER_HORIZONTAL); 124 | // holder.vLine.setPadding(0, DensityUtils.dp2px(ExperimentActivity.this,1000), 0, 0); 125 | holder.vLine.setLayoutParams(params); 126 | 127 | 128 | container.addView(convertView); 129 | return convertView; 130 | } 131 | 132 | 133 | @Override 134 | public void destroyItem(ViewGroup container, int position, Object object) { 135 | container.removeView((View) object); 136 | mViewCache.add((View) object); 137 | } 138 | 139 | //View复用 140 | public final class ViewHolder { 141 | public TextView tvName; 142 | public TextView tvNum; 143 | public ImageView ivPic; 144 | public View vLine; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /app/src/main/java/com/upc/viewpagerGallery/View/RoundImageView.java: -------------------------------------------------------------------------------- 1 | package com.upc.viewpagerGallery.View; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapShader; 7 | import android.graphics.Canvas; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.RectF; 11 | import android.graphics.Shader; 12 | import android.graphics.drawable.BitmapDrawable; 13 | import android.graphics.drawable.Drawable; 14 | import android.os.Bundle; 15 | import android.os.Parcelable; 16 | import android.util.AttributeSet; 17 | import android.util.Log; 18 | import android.util.TypedValue; 19 | import android.widget.ImageView; 20 | 21 | import com.upc.viewpagerGallery.R; 22 | 23 | /** 24 | * 圆角ImageView 25 | * Created by Explorer on 2016/3/26. 26 | */ 27 | public class RoundImageView extends ImageView { 28 | /** 29 | * 图片的类型,圆形or圆角 30 | */ 31 | private int type; 32 | public static final int TYPE_CIRCLE = 0; 33 | public static final int TYPE_ROUND = 1; 34 | /** 35 | * 圆角大小的默认值 36 | */ 37 | private static final int BODER_RADIUS_DEFAULT = 10; 38 | /** 39 | * 圆角的大小 40 | */ 41 | private int mBorderRadius; 42 | 43 | /** 44 | * 绘图的Paint 45 | */ 46 | private Paint mBitmapPaint; 47 | /** 48 | * 圆角的半径 49 | */ 50 | private int mRadius; 51 | /** 52 | * 3x3 矩阵,主要用于缩小放大 53 | */ 54 | private Matrix mMatrix; 55 | /** 56 | * 渲染图像,使用图像为绘制图形着色 57 | */ 58 | private BitmapShader mBitmapShader; 59 | /** 60 | * view的宽度 61 | */ 62 | private int mWidth; 63 | private RectF mRoundRect; 64 | 65 | public RoundImageView(Context context, AttributeSet attrs) { 66 | 67 | super(context, attrs); 68 | mMatrix = new Matrix(); 69 | mBitmapPaint = new Paint(); 70 | mBitmapPaint.setAntiAlias(true); 71 | 72 | TypedArray a = context.obtainStyledAttributes(attrs, 73 | R.styleable.RoundImageView); 74 | 75 | mBorderRadius = a.getDimensionPixelSize( 76 | R.styleable.RoundImageView_borderRadius, (int) TypedValue 77 | .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 78 | BODER_RADIUS_DEFAULT, getResources() 79 | .getDisplayMetrics()));// 默认为10dp 80 | type = a.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);// 默认为Circle 81 | 82 | a.recycle(); 83 | } 84 | 85 | public RoundImageView(Context context) { 86 | this(context, null); 87 | } 88 | 89 | @Override 90 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 91 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 92 | 93 | /** 94 | * 如果类型是圆形,则强制改变view的宽高一致,以小值为准 95 | */ 96 | if (type == TYPE_CIRCLE) { 97 | mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight()); 98 | mRadius = mWidth / 2; 99 | setMeasuredDimension(mWidth, mWidth); 100 | } 101 | 102 | } 103 | 104 | /** 105 | * 初始化BitmapShader 106 | */ 107 | private void setUpShader() { 108 | Drawable drawable = getDrawable(); 109 | if (drawable == null) { 110 | return; 111 | } 112 | 113 | Bitmap bmp = drawableToBitamp(drawable); 114 | // 将bmp作为着色器,就是在指定区域内绘制bmp 115 | mBitmapShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 116 | float scale = 1.0f; 117 | if (type == TYPE_CIRCLE) { 118 | // 拿到bitmap宽或高的小值 119 | int bSize = Math.min(bmp.getWidth(), bmp.getHeight()); 120 | scale = mWidth * 1.0f / bSize; 121 | 122 | } else if (type == TYPE_ROUND) { 123 | Log.e("TAG", 124 | "b'w = " + bmp.getWidth() + " , " + "b'h = " 125 | + bmp.getHeight()); 126 | if (!(bmp.getWidth() == getWidth() && bmp.getHeight() == getHeight())) { 127 | // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值; 128 | scale = Math.max(getWidth() * 1.0f / bmp.getWidth(), 129 | getHeight() * 1.0f / bmp.getHeight()); 130 | } 131 | 132 | } 133 | // shader的变换矩阵,我们这里主要用于放大或者缩小 134 | mMatrix.setScale(scale, scale); 135 | // 设置变换矩阵 136 | mBitmapShader.setLocalMatrix(mMatrix); 137 | // 设置shader 138 | mBitmapPaint.setShader(mBitmapShader); 139 | } 140 | 141 | @Override 142 | protected void onDraw(Canvas canvas) { 143 | Log.e("TAG", "onDraw"); 144 | if (getDrawable() == null) { 145 | return; 146 | } 147 | setUpShader(); 148 | 149 | if (type == TYPE_ROUND) { 150 | canvas.drawRoundRect(mRoundRect, mBorderRadius, mBorderRadius, 151 | mBitmapPaint); 152 | } else { 153 | canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint); 154 | // drawSomeThing(canvas); 155 | } 156 | } 157 | 158 | @Override 159 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 160 | super.onSizeChanged(w, h, oldw, oldh); 161 | 162 | // 圆角图片的范围 163 | if (type == TYPE_ROUND) 164 | mRoundRect = new RectF(0, 0, w, h); 165 | } 166 | 167 | /** 168 | * drawable转bitmap 169 | * 170 | * @param drawable 171 | * @return 172 | */ 173 | private Bitmap drawableToBitamp(Drawable drawable) { 174 | if (drawable instanceof BitmapDrawable) { 175 | BitmapDrawable bd = (BitmapDrawable) drawable; 176 | return bd.getBitmap(); 177 | } 178 | int w = drawable.getIntrinsicWidth(); 179 | int h = drawable.getIntrinsicHeight(); 180 | Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 181 | Canvas canvas = new Canvas(bitmap); 182 | drawable.setBounds(0, 0, w, h); 183 | drawable.draw(canvas); 184 | return bitmap; 185 | } 186 | 187 | private static final String STATE_INSTANCE = "state_instance"; 188 | private static final String STATE_TYPE = "state_type"; 189 | private static final String STATE_BORDER_RADIUS = "state_border_radius"; 190 | 191 | @Override 192 | protected Parcelable onSaveInstanceState() { 193 | Bundle bundle = new Bundle(); 194 | bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState()); 195 | bundle.putInt(STATE_TYPE, type); 196 | bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius); 197 | return bundle; 198 | } 199 | 200 | @Override 201 | protected void onRestoreInstanceState(Parcelable state) { 202 | if (state instanceof Bundle) { 203 | Bundle bundle = (Bundle) state; 204 | super.onRestoreInstanceState(((Bundle) state) 205 | .getParcelable(STATE_INSTANCE)); 206 | this.type = bundle.getInt(STATE_TYPE); 207 | this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS); 208 | } else { 209 | super.onRestoreInstanceState(state); 210 | } 211 | 212 | } 213 | 214 | public void setBorderRadius(int borderRadius) { 215 | int pxVal = dp2px(borderRadius); 216 | if (this.mBorderRadius != pxVal) { 217 | this.mBorderRadius = pxVal; 218 | invalidate(); 219 | } 220 | } 221 | 222 | public void setType(int type) { 223 | if (this.type != type) { 224 | this.type = type; 225 | if (this.type != TYPE_ROUND && this.type != TYPE_CIRCLE) { 226 | this.type = TYPE_CIRCLE; 227 | } 228 | requestLayout(); 229 | } 230 | 231 | } 232 | 233 | public int dp2px(int dpVal) { 234 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 235 | dpVal, getResources().getDisplayMetrics()); 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/upc/viewpagerGallery/Activity/SystemBarTintManager.java: -------------------------------------------------------------------------------- 1 | package com.upc.viewpagerGallery.Activity; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.annotation.TargetApi; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.res.Configuration; 8 | import android.content.res.Resources; 9 | import android.content.res.TypedArray; 10 | import android.graphics.drawable.Drawable; 11 | import android.os.Build; 12 | import android.util.DisplayMetrics; 13 | import android.util.TypedValue; 14 | import android.view.Gravity; 15 | import android.view.View; 16 | import android.view.ViewConfiguration; 17 | import android.view.ViewGroup; 18 | import android.view.Window; 19 | import android.view.WindowManager; 20 | import android.widget.FrameLayout; 21 | 22 | import java.lang.reflect.Method; 23 | 24 | /** 25 | * Created by Explorer on 2016/3/27. 26 | */ 27 | public class SystemBarTintManager { 28 | 29 | static { 30 | // Android allows a system property to override the presence of the navigation bar. 31 | // Used by the emulator. 32 | // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076 33 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 34 | try { 35 | Class c = Class.forName("android.os.SystemProperties"); 36 | Method m = c.getDeclaredMethod("get", String.class); 37 | m.setAccessible(true); 38 | sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); 39 | } catch (Throwable e) { 40 | sNavBarOverride = null; 41 | } 42 | } 43 | } 44 | 45 | 46 | /** 47 | * The default system bar tint color value. 48 | */ 49 | public static final int DEFAULT_TINT_COLOR = 0x99000000; 50 | 51 | private static String sNavBarOverride; 52 | 53 | private final SystemBarConfig mConfig; 54 | private boolean mStatusBarAvailable; 55 | private boolean mNavBarAvailable; 56 | private boolean mStatusBarTintEnabled; 57 | private boolean mNavBarTintEnabled; 58 | private View mStatusBarTintView; 59 | private View mNavBarTintView; 60 | 61 | /** 62 | * Constructor. Call this in the host activity onCreate method after its 63 | * content view has been set. You should always create new instances when 64 | * the host activity is recreated. 65 | * 66 | * @param activity The host activity. 67 | */ 68 | @TargetApi(19) 69 | public SystemBarTintManager(Activity activity) { 70 | 71 | Window win = activity.getWindow(); 72 | ViewGroup decorViewGroup = (ViewGroup) win.getDecorView(); 73 | 74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 75 | // check theme attrs 76 | int[] attrs = {android.R.attr.windowTranslucentStatus, 77 | android.R.attr.windowTranslucentNavigation}; 78 | TypedArray a = activity.obtainStyledAttributes(attrs); 79 | try { 80 | mStatusBarAvailable = a.getBoolean(0, false); 81 | mNavBarAvailable = a.getBoolean(1, false); 82 | } finally { 83 | a.recycle(); 84 | } 85 | 86 | // check window flags 87 | WindowManager.LayoutParams winParams = win.getAttributes(); 88 | int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 89 | if ((winParams.flags & bits) != 0) { 90 | mStatusBarAvailable = true; 91 | } 92 | bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; 93 | if ((winParams.flags & bits) != 0) { 94 | mNavBarAvailable = true; 95 | } 96 | } 97 | 98 | mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable); 99 | // device might not have virtual navigation keys 100 | if (!mConfig.hasNavigtionBar()) { 101 | mNavBarAvailable = false; 102 | } 103 | 104 | if (mStatusBarAvailable) { 105 | setupStatusBarView(activity, decorViewGroup); 106 | } 107 | if (mNavBarAvailable) { 108 | setupNavBarView(activity, decorViewGroup); 109 | } 110 | 111 | } 112 | 113 | /** 114 | * Enable tinting of the system status bar. 115 | *

116 | * If the platform is running Jelly Bean or earlier, or translucent system 117 | * UI modes have not been enabled in either the theme or via window flags, 118 | * then this method does nothing. 119 | * 120 | * @param enabled True to enable tinting, false to disable it (default). 121 | */ 122 | public void setStatusBarTintEnabled(boolean enabled) { 123 | mStatusBarTintEnabled = enabled; 124 | if (mStatusBarAvailable) { 125 | mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE); 126 | } 127 | } 128 | 129 | /** 130 | * Enable tinting of the system navigation bar. 131 | *

132 | * If the platform does not have soft navigation keys, is running Jelly Bean 133 | * or earlier, or translucent system UI modes have not been enabled in either 134 | * the theme or via window flags, then this method does nothing. 135 | * 136 | * @param enabled True to enable tinting, false to disable it (default). 137 | */ 138 | public void setNavigationBarTintEnabled(boolean enabled) { 139 | mNavBarTintEnabled = enabled; 140 | if (mNavBarAvailable) { 141 | mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE); 142 | } 143 | } 144 | 145 | /** 146 | * Apply the specified color tint to all system UI bars. 147 | * 148 | * @param color The color of the background tint. 149 | */ 150 | public void setTintColor(int color) { 151 | setStatusBarTintColor(color); 152 | setNavigationBarTintColor(color); 153 | } 154 | 155 | /** 156 | * Apply the specified drawable or color resource to all system UI bars. 157 | * 158 | * @param res The identifier of the resource. 159 | */ 160 | public void setTintResource(int res) { 161 | setStatusBarTintResource(res); 162 | setNavigationBarTintResource(res); 163 | } 164 | 165 | /** 166 | * Apply the specified drawable to all system UI bars. 167 | * 168 | * @param drawable The drawable to use as the background, or null to remove it. 169 | */ 170 | public void setTintDrawable(Drawable drawable) { 171 | setStatusBarTintDrawable(drawable); 172 | setNavigationBarTintDrawable(drawable); 173 | } 174 | 175 | /** 176 | * Apply the specified alpha to all system UI bars. 177 | * 178 | * @param alpha The alpha to use 179 | */ 180 | public void setTintAlpha(float alpha) { 181 | setStatusBarAlpha(alpha); 182 | setNavigationBarAlpha(alpha); 183 | } 184 | 185 | /** 186 | * Apply the specified color tint to the system status bar. 187 | * 188 | * @param color The color of the background tint. 189 | */ 190 | public void setStatusBarTintColor(int color) { 191 | if (mStatusBarAvailable) { 192 | mStatusBarTintView.setBackgroundColor(color); 193 | } 194 | } 195 | 196 | /** 197 | * Apply the specified drawable or color resource to the system status bar. 198 | * 199 | * @param res The identifier of the resource. 200 | */ 201 | public void setStatusBarTintResource(int res) { 202 | if (mStatusBarAvailable) { 203 | mStatusBarTintView.setBackgroundResource(res); 204 | } 205 | } 206 | 207 | /** 208 | * Apply the specified drawable to the system status bar. 209 | * 210 | * @param drawable The drawable to use as the background, or null to remove it. 211 | */ 212 | @SuppressWarnings("deprecation") 213 | public void setStatusBarTintDrawable(Drawable drawable) { 214 | if (mStatusBarAvailable) { 215 | mStatusBarTintView.setBackgroundDrawable(drawable); 216 | } 217 | } 218 | 219 | /** 220 | * Apply the specified alpha to the system status bar. 221 | * 222 | * @param alpha The alpha to use 223 | */ 224 | @TargetApi(11) 225 | public void setStatusBarAlpha(float alpha) { 226 | if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 227 | mStatusBarTintView.setAlpha(alpha); 228 | } 229 | } 230 | 231 | /** 232 | * Apply the specified color tint to the system navigation bar. 233 | * 234 | * @param color The color of the background tint. 235 | */ 236 | public void setNavigationBarTintColor(int color) { 237 | if (mNavBarAvailable) { 238 | mNavBarTintView.setBackgroundColor(color); 239 | } 240 | } 241 | 242 | /** 243 | * Apply the specified drawable or color resource to the system navigation bar. 244 | * 245 | * @param res The identifier of the resource. 246 | */ 247 | public void setNavigationBarTintResource(int res) { 248 | if (mNavBarAvailable) { 249 | mNavBarTintView.setBackgroundResource(res); 250 | } 251 | } 252 | 253 | /** 254 | * Apply the specified drawable to the system navigation bar. 255 | * 256 | * @param drawable The drawable to use as the background, or null to remove it. 257 | */ 258 | @SuppressWarnings("deprecation") 259 | public void setNavigationBarTintDrawable(Drawable drawable) { 260 | if (mNavBarAvailable) { 261 | mNavBarTintView.setBackgroundDrawable(drawable); 262 | } 263 | } 264 | 265 | /** 266 | * Apply the specified alpha to the system navigation bar. 267 | * 268 | * @param alpha The alpha to use 269 | */ 270 | @TargetApi(11) 271 | public void setNavigationBarAlpha(float alpha) { 272 | if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 273 | mNavBarTintView.setAlpha(alpha); 274 | } 275 | } 276 | 277 | /** 278 | * Get the system bar configuration. 279 | * 280 | * @return The system bar configuration for the current device configuration. 281 | */ 282 | public SystemBarConfig getConfig() { 283 | return mConfig; 284 | } 285 | 286 | /** 287 | * Is tinting enabled for the system status bar? 288 | * 289 | * @return True if enabled, False otherwise. 290 | */ 291 | public boolean isStatusBarTintEnabled() { 292 | return mStatusBarTintEnabled; 293 | } 294 | 295 | /** 296 | * Is tinting enabled for the system navigation bar? 297 | * 298 | * @return True if enabled, False otherwise. 299 | */ 300 | public boolean isNavBarTintEnabled() { 301 | return mNavBarTintEnabled; 302 | } 303 | 304 | private void setupStatusBarView(Context context, ViewGroup decorViewGroup) { 305 | mStatusBarTintView = new View(context); 306 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight()); 307 | params.gravity = Gravity.TOP; 308 | if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) { 309 | params.rightMargin = mConfig.getNavigationBarWidth(); 310 | } 311 | mStatusBarTintView.setLayoutParams(params); 312 | mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR); 313 | mStatusBarTintView.setVisibility(View.GONE); 314 | decorViewGroup.addView(mStatusBarTintView); 315 | } 316 | 317 | private void setupNavBarView(Context context, ViewGroup decorViewGroup) { 318 | mNavBarTintView = new View(context); 319 | FrameLayout.LayoutParams params; 320 | if (mConfig.isNavigationAtBottom()) { 321 | params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight()); 322 | params.gravity = Gravity.BOTTOM; 323 | } else { 324 | params = new FrameLayout.LayoutParams(mConfig.getNavigationBarWidth(), FrameLayout.LayoutParams.MATCH_PARENT); 325 | params.gravity = Gravity.RIGHT; 326 | } 327 | mNavBarTintView.setLayoutParams(params); 328 | mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR); 329 | mNavBarTintView.setVisibility(View.GONE); 330 | decorViewGroup.addView(mNavBarTintView); 331 | } 332 | 333 | /** 334 | * Class which describes system bar sizing and other characteristics for the current 335 | * device configuration. 336 | */ 337 | public static class SystemBarConfig { 338 | 339 | private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; 340 | private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; 341 | private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; 342 | private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"; 343 | private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; 344 | 345 | private final boolean mTranslucentStatusBar; 346 | private final boolean mTranslucentNavBar; 347 | private final int mStatusBarHeight; 348 | private final int mActionBarHeight; 349 | private final boolean mHasNavigationBar; 350 | private final int mNavigationBarHeight; 351 | private final int mNavigationBarWidth; 352 | private final boolean mInPortrait; 353 | private final float mSmallestWidthDp; 354 | 355 | private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) { 356 | Resources res = activity.getResources(); 357 | mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT); 358 | mSmallestWidthDp = getSmallestWidthDp(activity); 359 | mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME); 360 | mActionBarHeight = getActionBarHeight(activity); 361 | mNavigationBarHeight = getNavigationBarHeight(activity); 362 | mNavigationBarWidth = getNavigationBarWidth(activity); 363 | mHasNavigationBar = (mNavigationBarHeight > 0); 364 | mTranslucentStatusBar = translucentStatusBar; 365 | mTranslucentNavBar = traslucentNavBar; 366 | } 367 | 368 | @TargetApi(14) 369 | private int getActionBarHeight(Context context) { 370 | int result = 0; 371 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 372 | TypedValue tv = new TypedValue(); 373 | context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); 374 | result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); 375 | } 376 | return result; 377 | } 378 | 379 | @TargetApi(14) 380 | private int getNavigationBarHeight(Context context) { 381 | Resources res = context.getResources(); 382 | int result = 0; 383 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 384 | if (hasNavBar(context)) { 385 | String key; 386 | if (mInPortrait) { 387 | key = NAV_BAR_HEIGHT_RES_NAME; 388 | } else { 389 | key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; 390 | } 391 | return getInternalDimensionSize(res, key); 392 | } 393 | } 394 | return result; 395 | } 396 | 397 | @TargetApi(14) 398 | private int getNavigationBarWidth(Context context) { 399 | Resources res = context.getResources(); 400 | int result = 0; 401 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 402 | if (hasNavBar(context)) { 403 | return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME); 404 | } 405 | } 406 | return result; 407 | } 408 | 409 | @TargetApi(14) 410 | private boolean hasNavBar(Context context) { 411 | Resources res = context.getResources(); 412 | int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); 413 | if (resourceId != 0) { 414 | boolean hasNav = res.getBoolean(resourceId); 415 | // check override flag (see static block) 416 | if ("1".equals(sNavBarOverride)) { 417 | hasNav = false; 418 | } else if ("0".equals(sNavBarOverride)) { 419 | hasNav = true; 420 | } 421 | return hasNav; 422 | } else { // fallback 423 | return !ViewConfiguration.get(context).hasPermanentMenuKey(); 424 | } 425 | } 426 | 427 | private int getInternalDimensionSize(Resources res, String key) { 428 | int result = 0; 429 | int resourceId = res.getIdentifier(key, "dimen", "android"); 430 | if (resourceId > 0) { 431 | result = res.getDimensionPixelSize(resourceId); 432 | } 433 | return result; 434 | } 435 | 436 | @SuppressLint("NewApi") 437 | private float getSmallestWidthDp(Activity activity) { 438 | DisplayMetrics metrics = new DisplayMetrics(); 439 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 440 | activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); 441 | } else { 442 | // TODO this is not correct, but we don't really care pre-kitkat 443 | activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 444 | } 445 | float widthDp = metrics.widthPixels / metrics.density; 446 | float heightDp = metrics.heightPixels / metrics.density; 447 | return Math.min(widthDp, heightDp); 448 | } 449 | 450 | /** 451 | * Should a navigation bar appear at the bottom of the screen in the current 452 | * device configuration? A navigation bar may appear on the right side of 453 | * the screen in certain configurations. 454 | * 455 | * @return True if navigation should appear at the bottom of the screen, False otherwise. 456 | */ 457 | public boolean isNavigationAtBottom() { 458 | return (mSmallestWidthDp >= 600 || mInPortrait); 459 | } 460 | 461 | /** 462 | * Get the height of the system status bar. 463 | * 464 | * @return The height of the status bar (in pixels). 465 | */ 466 | public int getStatusBarHeight() { 467 | return mStatusBarHeight; 468 | } 469 | 470 | /** 471 | * Get the height of the action bar. 472 | * 473 | * @return The height of the action bar (in pixels). 474 | */ 475 | public int getActionBarHeight() { 476 | return mActionBarHeight; 477 | } 478 | 479 | /** 480 | * Does this device have a system navigation bar? 481 | * 482 | * @return True if this device uses soft key navigation, False otherwise. 483 | */ 484 | public boolean hasNavigtionBar() { 485 | return mHasNavigationBar; 486 | } 487 | 488 | /** 489 | * Get the height of the system navigation bar. 490 | * 491 | * @return The height of the navigation bar (in pixels). If the device does not have 492 | * soft navigation keys, this will always return 0. 493 | */ 494 | public int getNavigationBarHeight() { 495 | return mNavigationBarHeight; 496 | } 497 | 498 | /** 499 | * Get the width of the system navigation bar when it is placed vertically on the screen. 500 | * 501 | * @return The width of the navigation bar (in pixels). If the device does not have 502 | * soft navigation keys, this will always return 0. 503 | */ 504 | public int getNavigationBarWidth() { 505 | return mNavigationBarWidth; 506 | } 507 | 508 | /** 509 | * Get the layout inset for any system UI that appears at the top of the screen. 510 | * 511 | * @param withActionBar True to include the height of the action bar, False otherwise. 512 | * @return The layout inset (in pixels). 513 | */ 514 | public int getPixelInsetTop(boolean withActionBar) { 515 | return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0); 516 | } 517 | 518 | /** 519 | * Get the layout inset for any system UI that appears at the bottom of the screen. 520 | * 521 | * @return The layout inset (in pixels). 522 | */ 523 | public int getPixelInsetBottom() { 524 | if (mTranslucentNavBar && isNavigationAtBottom()) { 525 | return mNavigationBarHeight; 526 | } else { 527 | return 0; 528 | } 529 | } 530 | 531 | /** 532 | * Get the layout inset for any system UI that appears at the right of the screen. 533 | * 534 | * @return The layout inset (in pixels). 535 | */ 536 | public int getPixelInsetRight() { 537 | if (mTranslucentNavBar && !isNavigationAtBottom()) { 538 | return mNavigationBarWidth; 539 | } else { 540 | return 0; 541 | } 542 | } 543 | 544 | } 545 | } 546 | --------------------------------------------------------------------------------