├── .gitignore ├── README.md ├── app ├── .gitignore ├── aar │ ├── compresshelper.aar │ └── glideimageview.aar ├── build.gradle ├── libs │ └── zxing-3.1.1.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── wkz │ │ └── share │ │ ├── adapter │ │ ├── ListViewAdapter.java │ │ └── RecyclerViewAdapter.java │ │ ├── blur │ │ └── GlideBlurTransformation.java │ │ ├── immersionbar │ │ ├── BarConfig.java │ │ ├── BarHide.java │ │ ├── BarParams.java │ │ ├── BarType.java │ │ ├── ImmersionBar.java │ │ ├── ImmersionFragment.java │ │ ├── KeyboardPatch.java │ │ └── OSUtils.java │ │ ├── share │ │ ├── OnShareListener.java │ │ ├── ShareDialog.java │ │ ├── SharePlatform.java │ │ ├── SharePlatformAdapter.java │ │ └── SharePlatformBean.java │ │ ├── ui │ │ ├── ListViewActivity.java │ │ ├── MainActivity.java │ │ ├── RecyclerViewActivity.java │ │ ├── ScrollViewActivity.java │ │ └── WebViewActivity.java │ │ ├── utils │ │ ├── AnimationUtils.java │ │ ├── BlurBitmapUtils.java │ │ ├── ScreenShotUtils.java │ │ ├── ScreenUtils.java │ │ └── ViewUtils.java │ │ └── zxing │ │ └── QRCode.java │ └── res │ ├── anim │ ├── dialog_enter.xml │ └── dialog_exit.xml │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── ic_launcher_background.xml │ ├── shape_bg_0xffededed_cornersfive.xml │ ├── shape_bg_0xffededed_cornersfive_bottom.xml │ ├── shape_bg_0xffededed_cornersfive_top.xml │ └── shape_bg_0xffffffff_cornerstwo.xml │ ├── layout │ ├── activity_list_view.xml │ ├── activity_main.xml │ ├── activity_recycler_view.xml │ ├── activity_scroll_view.xml │ ├── activity_web_view.xml │ ├── dialog_share.xml │ ├── list_item_list.xml │ ├── recycler_item_recycler1.xml │ ├── recycler_item_recycler2.xml │ └── recycler_item_share_dialog.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.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_close_white.png │ ├── ic_game_icon.webp │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── ic_share_friend_circle.png │ ├── ic_share_link.png │ ├── ic_share_microblog.png │ ├── ic_share_qq.png │ ├── ic_share_qqspace.png │ ├── ic_share_wechat.png │ ├── pic_image.webp │ ├── pic_long_img1.jpg │ └── pic_long_img2.jpg │ ├── values-v19 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── preview ├── shot_listview.jpeg ├── shot_nestedscrollview.jpeg ├── shot_recyclerview.jpeg └── shot_webview.jpeg └── settings.gradle /.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 | /app/keystore.properties 11 | /.idea 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LongScreenShotShare 2 | 3 | 长截图分享,NestedScrollView、RecyclerView、ListView、WebView等实现长截图,RecyclerView、ListView的Item数据可异步加载 4 | ------------------------------ 5 | 6 |
7 | 8 | 9 | 10 | 11 |
12 | 13 | ----------------------------- 14 | 15 | #### 1. NestedScrollView截图 16 | ```java 17 | public static Bitmap shotNestedScrollView(NestedScrollView nestedScrollView) { 18 | if (nestedScrollView == null) { 19 | return null; 20 | } 21 | try { 22 | int h = 0; 23 | // 获取ScrollView实际高度 24 | for (int i = 0; i < nestedScrollView.getChildCount(); i++) { 25 | h += nestedScrollView.getChildAt(i).getHeight(); 26 | } 27 | // 创建对应大小的bitmap 28 | Bitmap bitmap = Bitmap.createBitmap(nestedScrollView.getWidth(), h, Bitmap.Config.ARGB_8888); 29 | final Canvas canvas = new Canvas(bitmap); 30 | nestedScrollView.draw(canvas); 31 | 32 | // 保存图片 33 | savePicture(nestedScrollView.getContext(), bitmap); 34 | 35 | return bitmap; 36 | } catch (OutOfMemoryError oom) { 37 | return null; 38 | } 39 | } 40 | ``` 41 | -------------------------------- 42 | 43 | #### 2. ListView截图 44 | ```java 45 | public static Bitmap shotListView(ListView listView) { 46 | if (listView == null) { 47 | return null; 48 | } 49 | 50 | try { 51 | ListViewAdapter adapter = (ListViewAdapter) listView.getAdapter(); 52 | Bitmap bigBitmap = null; 53 | if (adapter != null) { 54 | int size = adapter.getCount(); 55 | int height = 0; 56 | Paint paint = new Paint(); 57 | final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); 58 | 59 | // Use 1/8th of the available memory for this memory cache. 60 | final int cacheSize = maxMemory / 8; 61 | LruCache bitmapCache = new LruCache<>(cacheSize); 62 | SparseIntArray bitmapTop = new SparseIntArray(size); 63 | for (int i = 0; i < size; i++) { 64 | View childView = adapter.getConvertView(i, null, listView); 65 | adapter.onBindViewSync(i, childView, listView); 66 | childView.measure( 67 | View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.EXACTLY), 68 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) 69 | ); 70 | childView.layout( 71 | 0, 72 | 0, 73 | childView.getMeasuredWidth(), 74 | childView.getMeasuredHeight() 75 | ); 76 | childView.setDrawingCacheEnabled(true); 77 | childView.buildDrawingCache(); 78 | Bitmap drawingCache = childView.getDrawingCache(); 79 | if (drawingCache != null) { 80 | bitmapCache.put(String.valueOf(i), drawingCache); 81 | } 82 | 83 | bitmapTop.put(i, height); 84 | height += childView.getMeasuredHeight(); 85 | } 86 | 87 | bigBitmap = Bitmap.createBitmap(listView.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888); 88 | Canvas bigCanvas = new Canvas(bigBitmap); 89 | Drawable lBackground = listView.getBackground(); 90 | if (lBackground instanceof ColorDrawable) { 91 | ColorDrawable lColorDrawable = (ColorDrawable) lBackground; 92 | int lColor = lColorDrawable.getColor(); 93 | bigCanvas.drawColor(lColor); 94 | } 95 | 96 | for (int i = 0; i < size; i++) { 97 | Bitmap bitmap = bitmapCache.get(String.valueOf(i)); 98 | bigCanvas.drawBitmap(bitmap, 0, bitmapTop.get(i), paint); 99 | bitmap.recycle(); 100 | } 101 | } 102 | return bigBitmap; 103 | } catch (OutOfMemoryError oom) { 104 | return null; 105 | } 106 | } 107 | ``` 108 | -------------------------------- 109 | 110 | #### 3. RecyclerView截图 111 | ```java 112 | public static Bitmap shotRecyclerView(RecyclerView recyclerView) { 113 | if (recyclerView == null) { 114 | return null; 115 | } 116 | try { 117 | RecyclerViewAdapter adapter = (RecyclerViewAdapter) recyclerView.getAdapter(); 118 | Bitmap bigBitmap = null; 119 | if (adapter != null) { 120 | int size = adapter.getItemCount(); 121 | int height = 0; 122 | Paint paint = new Paint(); 123 | final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); 124 | 125 | // Use 1/8th of the available memory for this memory cache. 126 | final int cacheSize = maxMemory / 8; 127 | LruCache bitmapCache = new LruCache<>(cacheSize); 128 | SparseIntArray bitmapLeft = new SparseIntArray(size); 129 | SparseIntArray bitmapTop = new SparseIntArray(size); 130 | for (int i = 0; i < size; i++) { 131 | RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i)); 132 | adapter.onBindViewSync(holder, i); 133 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams(); 134 | holder.itemView.measure( 135 | View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth() - layoutParams.leftMargin - layoutParams.rightMargin, View.MeasureSpec.EXACTLY), 136 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) 137 | ); 138 | holder.itemView.layout( 139 | layoutParams.leftMargin, 140 | layoutParams.topMargin, 141 | holder.itemView.getMeasuredWidth() + layoutParams.leftMargin, 142 | holder.itemView.getMeasuredHeight() + layoutParams.topMargin 143 | ); 144 | holder.itemView.setDrawingCacheEnabled(true); 145 | holder.itemView.buildDrawingCache(); 146 | Bitmap drawingCache = holder.itemView.getDrawingCache(); 147 | if (drawingCache != null) { 148 | bitmapCache.put(String.valueOf(i), drawingCache); 149 | } 150 | 151 | height += layoutParams.topMargin; 152 | bitmapLeft.put(i, layoutParams.leftMargin); 153 | bitmapTop.put(i, height); 154 | height += holder.itemView.getMeasuredHeight() + layoutParams.bottomMargin; 155 | } 156 | 157 | bigBitmap = Bitmap.createBitmap(recyclerView.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888); 158 | Canvas bigCanvas = new Canvas(bigBitmap); 159 | Drawable lBackground = recyclerView.getBackground(); 160 | if (lBackground instanceof ColorDrawable) { 161 | ColorDrawable lColorDrawable = (ColorDrawable) lBackground; 162 | int lColor = lColorDrawable.getColor(); 163 | bigCanvas.drawColor(lColor); 164 | } 165 | 166 | for (int i = 0; i < size; i++) { 167 | Bitmap bitmap = bitmapCache.get(String.valueOf(i)); 168 | bigCanvas.drawBitmap(bitmap, bitmapLeft.get(i), bitmapTop.get(i), paint); 169 | bitmap.recycle(); 170 | } 171 | } 172 | return bigBitmap; 173 | } catch (OutOfMemoryError oom) { 174 | return null; 175 | } 176 | } 177 | ``` 178 | -------------------------------- 179 | 180 | #### 4. WebView截图 181 | ```java 182 | public static Bitmap shotWebView(WebView webView) { 183 | try { 184 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 185 | // Android5.0以上 186 | float scale = webView.getScale(); 187 | int width = webView.getWidth(); 188 | int height = (int) (webView.getContentHeight() * scale + 0.5); 189 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 190 | Canvas canvas = new Canvas(bitmap); 191 | webView.draw(canvas); 192 | 193 | // 保存图片 194 | savePicture(webView.getContext(), bitmap); 195 | return bitmap; 196 | } else { 197 | // Android5.0以下 198 | Picture picture = webView.capturePicture(); 199 | int width = picture.getWidth(); 200 | int height = picture.getHeight(); 201 | if (width > 0 && height > 0) { 202 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 203 | Canvas canvas = new Canvas(bitmap); 204 | picture.draw(canvas); 205 | 206 | // 保存图片 207 | savePicture(webView.getContext(), bitmap); 208 | return bitmap; 209 | } 210 | return null; 211 | } 212 | } catch (OutOfMemoryError oom) { 213 | return null; 214 | } 215 | } 216 | ``` 217 | -------------------------------- 218 | 219 | #### 5. 异步加载数据截图实现(以ListView为例) 220 | 221 | - **adapter中定义异步加载方法:** 222 | ```java 223 | public void onBindViewSync(final int position, View convertView, ViewGroup parent) { 224 | final ViewHolder holder; 225 | if (convertView == null) { 226 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_list, parent, false); 227 | holder = new ViewHolder(convertView); 228 | convertView.setTag(holder); 229 | } else { 230 | holder = (ViewHolder) convertView.getTag(); 231 | } 232 | 233 | // List中的Item的LayoutParam是直接继承自ViewGroup中的LayoutParam。 不包含有margin信息。 234 | // 所以在ListView中父节点设置的值会失效。 235 | if (position == 0) { 236 | // 设置margin 237 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 100, 25, 0); 238 | } else if (position == getCount() - 1) { 239 | // 设置margin 240 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 15, 25, 150); 241 | } else { 242 | // 设置margin 243 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 15, 25, 0); 244 | } 245 | 246 | try { 247 | File gameImageFile = Glide.with(mContext) 248 | .load(mDatas.get(position)) 249 | .downloadOnly(0, 0) 250 | .get(); 251 | Bitmap gameImageBitmap = BitmapFactory.decodeFile(gameImageFile.getAbsolutePath()); 252 | 253 | File gameIconFile = Glide.with(mContext) 254 | .load(mDatas.get(position)) 255 | .downloadOnly(0, 0) 256 | .get(); 257 | Bitmap gameIconBitmap = BitmapFactory.decodeFile(gameIconFile.getAbsolutePath()); 258 | 259 | holder.mIvGameImage.setImageBitmap(gameImageBitmap); 260 | holder.mIvGameIcon.setImageBitmap(gameIconBitmap); 261 | holder.mTvGameName.setText(String.format(Locale.getDefault(), "《将进酒》李白%d", position)); 262 | } catch (ExecutionException e) { 263 | e.printStackTrace(); 264 | } catch (InterruptedException e) { 265 | e.printStackTrace(); 266 | } 267 | } 268 | ``` 269 | 270 | - **adapter中定义获取复用View方法:** 271 | ```java 272 | public View getConvertView(final int position, View convertView, final ViewGroup parent) { 273 | final ViewHolder holder; 274 | if (convertView == null) { 275 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_list, parent, false); 276 | holder = new ViewHolder(convertView); 277 | convertView.setTag(holder); 278 | } else { 279 | holder = (ViewHolder) convertView.getTag(); 280 | } 281 | return convertView; 282 | } 283 | ``` 284 | 285 | - **activity中利用线程调用截图方法:** 286 | ```java 287 | Observable.defer( 288 | new Callable>() { 289 | @Override 290 | public ObservableSource call() throws Exception { 291 | return new ObservableSource() { 292 | @Override 293 | public void subscribe(Observer observer) { 294 | // 开始截图 295 | observer.onNext(ScreenShotUtils.shotListView(mLvList)); 296 | } 297 | }; 298 | } 299 | }) 300 | .subscribeOn(Schedulers.computation()) 301 | .observeOn(AndroidSchedulers.mainThread()) 302 | .subscribe(new Consumer() { 303 | @Override 304 | public void accept(Bitmap bitmap) throws Exception { 305 | // 保存图片 306 | File file = ScreenShotUtils.savePicture(mContext, bitmap); 307 | 308 | Toast.makeText(mContext, "图片已保存至 " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show(); 309 | } 310 | }); 311 | ``` 312 | -------------------------------------------------------------------- 313 | 314 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/aar/compresshelper.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/LongScreenShotShare/53ed232d02f1d4d7588bb3716e0744d6caee06df/app/aar/compresshelper.aar -------------------------------------------------------------------------------- /app/aar/glideimageview.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/LongScreenShotShare/53ed232d02f1d4d7588bb3716e0744d6caee06df/app/aar/glideimageview.aar -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | 6 | defaultConfig { 7 | applicationId "com.wkz.share" 8 | minSdkVersion 19 9 | targetSdkVersion 27 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | //新的 gradle 插件不再支持 annotation processors,如果需要使用需要显式声明 14 | javaCompileOptions { 15 | // 显式声明支持注解 16 | annotationProcessorOptions { 17 | includeCompileClasspath false 18 | } 19 | } 20 | } 21 | 22 | /** 23 | * 签名设置 24 | */ 25 | signingConfigs { 26 | release { 27 | File propFile = file('../app/keystore.properties') 28 | if (propFile.exists()) { 29 | Properties props = new Properties() 30 | props.load(new FileInputStream(propFile)) 31 | if (props.containsKey('STORE_FILE') && 32 | props.containsKey('STORE_PASSWORD') && 33 | props.containsKey('KEY_ALIAS') && 34 | props.containsKey('KEY_PASSWORD')) { 35 | storeFile file(props['STORE_FILE']) 36 | storePassword props['STORE_PASSWORD'] 37 | keyAlias props['KEY_ALIAS'] 38 | keyPassword props['KEY_PASSWORD'] 39 | } 40 | } 41 | } 42 | 43 | debug { 44 | File propFile = file('../app/keystore.properties') 45 | if (propFile.exists()) { 46 | Properties props = new Properties() 47 | props.load(new FileInputStream(propFile)) 48 | if (props.containsKey('STORE_FILE') && 49 | props.containsKey('STORE_PASSWORD') && 50 | props.containsKey('KEY_ALIAS') && 51 | props.containsKey('KEY_PASSWORD')) { 52 | storeFile file(props['STORE_FILE']) 53 | storePassword props['STORE_PASSWORD'] 54 | keyAlias props['KEY_ALIAS'] 55 | keyPassword props['KEY_PASSWORD'] 56 | } 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * 构建配置 63 | */ 64 | buildTypes { 65 | release { 66 | //执行proguard混淆 67 | minifyEnabled true 68 | //Zipalign优化 69 | zipAlignEnabled true 70 | //移除无用的resource文件 71 | shrinkResources true 72 | //混淆文件 73 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 74 | 75 | //签名 76 | signingConfig signingConfigs.release 77 | 78 | //apk重命名 79 | android.applicationVariants.all { variant -> 80 | variant.outputs.all { 81 | 82 | outputFileName = "${project.name}_${defaultConfig.versionName}_${variant.buildType.name}.apk" 83 | 84 | } 85 | } 86 | } 87 | 88 | debug { 89 | //不执行proguard 90 | minifyEnabled false 91 | //Zipalign优化 92 | zipAlignEnabled false 93 | // 移除无用的resource文件 94 | shrinkResources false 95 | //签名 96 | signingConfig signingConfigs.debug 97 | 98 | //apk重命名 99 | android.applicationVariants.all { variant -> 100 | variant.outputs.all { 101 | 102 | outputFileName = "${project.name}_${defaultConfig.versionName}_${variant.buildType.name}.apk" 103 | 104 | } 105 | } 106 | } 107 | } 108 | 109 | //这个是解决lint报错的代码 110 | lintOptions { 111 | quiet true 112 | abortOnError false 113 | ignoreWarnings true 114 | checkReleaseBuilds false//方法过时警告的开关 115 | disable 'InvalidPackage' //Some libraries have issues with this. 116 | disable 'OldTargetApi' //Lint gives this warning but SDK 20 would be Android L Beta. 117 | disable 'IconDensities' //For testing purpose. This is safe to remove. 118 | disable 'IconMissingDensityFolder' //For testing purpose. This is safe to remove. 119 | } 120 | 121 | packagingOptions { 122 | exclude 'META-INF/DEPENDENCIES.txt' 123 | exclude 'META-INF/LICENSE.txt' 124 | exclude 'META-INF/NOTICE.txt' 125 | exclude 'META-INF/NOTICE' 126 | exclude 'META-INF/LICENSE' 127 | exclude 'META-INF/DEPENDENCIES' 128 | exclude 'META-INF/notice.txt' 129 | exclude 'META-INF/license.txt' 130 | exclude 'META-INF/dependencies.txt' 131 | exclude 'META-INF/LGPL2.1' 132 | } 133 | 134 | repositories { 135 | flatDir { 136 | dirs 'aar' 137 | } 138 | } 139 | } 140 | 141 | final SUPPORT_VERSION = '27.1.1' 142 | 143 | dependencies { 144 | implementation fileTree(include: ['*.jar'], dir: 'libs') 145 | implementation fileTree(include: ['*.aar'], dir: 'aar') 146 | implementation "com.android.support:appcompat-v7:$SUPPORT_VERSION" 147 | implementation "com.android.support:support-annotations:$SUPPORT_VERSION" 148 | /** 149 | * GlideImageView 150 | */ 151 | implementation "com.android.support:support-v4:$SUPPORT_VERSION" 152 | implementation 'com.github.bumptech.glide:glide:4.0.0-RC0' 153 | implementation 'com.github.bumptech.glide:compiler:4.0.0-RC0' 154 | implementation 'com.github.bumptech.glide:okhttp3-integration:4.0.0-RC0' 155 | /** 156 | * RecyclerView 157 | */ 158 | implementation "com.android.support:recyclerview-v7:$SUPPORT_VERSION" 159 | /** 160 | * rxjava2 161 | */ 162 | implementation "io.reactivex.rxjava2:rxjava:2.2.0" 163 | implementation "io.reactivex.rxjava2:rxandroid:2.1.0" 164 | } 165 | -------------------------------------------------------------------------------- /app/libs/zxing-3.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/LongScreenShotShare/53ed232d02f1d4d7588bb3716e0744d6caee06df/app/libs/zxing-3.1.1.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -ignorewarnings -keep class * { public private *; } 24 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/adapter/ListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | import android.widget.RelativeLayout; 11 | import android.widget.TextView; 12 | 13 | import com.bumptech.glide.Glide; 14 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 15 | import com.bumptech.glide.request.RequestOptions; 16 | import com.sunfusheng.glideimageview.GlideImageView; 17 | import com.wkz.share.R; 18 | import com.wkz.share.utils.ViewUtils; 19 | 20 | import java.io.File; 21 | import java.util.List; 22 | import java.util.Locale; 23 | import java.util.concurrent.ExecutionException; 24 | 25 | /** 26 | * @author Administrator 27 | * @date 2019/5/30 28 | */ 29 | public class ListViewAdapter extends BaseAdapter { 30 | 31 | private Context mContext; 32 | private List mDatas; 33 | private View.OnClickListener mOnClickListener; 34 | 35 | public ListViewAdapter(Context mContext, List mDatas) { 36 | this.mContext = mContext; 37 | this.mDatas = mDatas; 38 | } 39 | 40 | @Override 41 | public int getCount() { 42 | return null != mDatas ? mDatas.size() : 0; 43 | } 44 | 45 | @Override 46 | public Object getItem(int position) { 47 | return null != mDatas ? mDatas.get(position) : null; 48 | } 49 | 50 | @Override 51 | public long getItemId(int position) { 52 | return position; 53 | } 54 | 55 | public View getConvertView(final int position, View convertView, final ViewGroup parent) { 56 | final ViewHolder holder; 57 | if (convertView == null) { 58 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_list, parent, false); 59 | holder = new ViewHolder(convertView); 60 | convertView.setTag(holder); 61 | } else { 62 | holder = (ViewHolder) convertView.getTag(); 63 | } 64 | return convertView; 65 | } 66 | 67 | @Override 68 | public View getView(final int position, View convertView, final ViewGroup parent) { 69 | final ViewHolder holder; 70 | if (convertView == null) { 71 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_list, parent, false); 72 | holder = new ViewHolder(convertView); 73 | convertView.setTag(holder); 74 | } else { 75 | holder = (ViewHolder) convertView.getTag(); 76 | } 77 | 78 | // List中的Item的LayoutParam是直接继承自ViewGroup中的LayoutParam。 不包含有margin信息。 79 | // 所以在ListView中父节点设置的值会失效。 80 | if (position == 0) { 81 | // 设置margin 82 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 100, 25, 0); 83 | } else if (position == getCount() - 1) { 84 | // 设置margin 85 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 15, 25, 150); 86 | } else { 87 | // 设置margin 88 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 15, 25, 0); 89 | } 90 | 91 | holder.mIvGameImage.load(mDatas.get(position), new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)); 92 | holder.mIvGameIcon.load(mDatas.get(position), new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)); 93 | holder.mTvGameName.setText(String.format(Locale.getDefault(), "《将进酒》李白%d", position)); 94 | 95 | holder.mIvGameImage.setOnClickListener(new View.OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | if (mOnClickListener != null) { 99 | mOnClickListener.onClick(v); 100 | } 101 | } 102 | }); 103 | holder.mIvGameIcon.setOnClickListener(new View.OnClickListener() { 104 | @Override 105 | public void onClick(View v) { 106 | holder.mIvGameImage.performClick(); 107 | } 108 | }); 109 | return convertView; 110 | } 111 | 112 | public void onBindViewSync(final int position, View convertView, ViewGroup parent) { 113 | final ViewHolder holder; 114 | if (convertView == null) { 115 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_list, parent, false); 116 | holder = new ViewHolder(convertView); 117 | convertView.setTag(holder); 118 | } else { 119 | holder = (ViewHolder) convertView.getTag(); 120 | } 121 | 122 | // List中的Item的LayoutParam是直接继承自ViewGroup中的LayoutParam。 不包含有margin信息。 123 | // 所以在ListView中父节点设置的值会失效。 124 | if (position == 0) { 125 | // 设置margin 126 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 100, 25, 0); 127 | } else if (position == getCount() - 1) { 128 | // 设置margin 129 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 15, 25, 150); 130 | } else { 131 | // 设置margin 132 | ViewUtils.setViewMargin(holder.mRlGameInfo, true, 25, 15, 25, 0); 133 | } 134 | 135 | try { 136 | File gameImageFile = Glide.with(mContext) 137 | .load(mDatas.get(position)) 138 | .downloadOnly(0, 0) 139 | .get(); 140 | Bitmap gameImageBitmap = BitmapFactory.decodeFile(gameImageFile.getAbsolutePath()); 141 | 142 | File gameIconFile = Glide.with(mContext) 143 | .load(mDatas.get(position)) 144 | .downloadOnly(0, 0) 145 | .get(); 146 | Bitmap gameIconBitmap = BitmapFactory.decodeFile(gameIconFile.getAbsolutePath()); 147 | 148 | holder.mIvGameImage.setImageBitmap(gameImageBitmap); 149 | holder.mIvGameIcon.setImageBitmap(gameIconBitmap); 150 | holder.mTvGameName.setText(String.format(Locale.getDefault(), "《将进酒》李白%d", position)); 151 | } catch (ExecutionException e) { 152 | e.printStackTrace(); 153 | } catch (InterruptedException e) { 154 | e.printStackTrace(); 155 | } 156 | } 157 | 158 | @Override 159 | public int getViewTypeCount() { 160 | return 1; 161 | } 162 | 163 | public static class ViewHolder { 164 | 165 | View mItemView; 166 | GlideImageView mIvGameImage; 167 | GlideImageView mIvGameIcon; 168 | TextView mTvGameName; 169 | TextView mTvGameDescription; 170 | RelativeLayout mRlGameInfo; 171 | 172 | ViewHolder(View view) { 173 | this.mItemView = view; 174 | this.mIvGameImage = (GlideImageView) view.findViewById(R.id.iv_game_image); 175 | this.mIvGameIcon = (GlideImageView) view.findViewById(R.id.iv_game_icon); 176 | this.mTvGameName = (TextView) view.findViewById(R.id.tv_game_name); 177 | this.mTvGameDescription = (TextView) view.findViewById(R.id.tv_game_description); 178 | this.mRlGameInfo = (RelativeLayout) view.findViewById(R.id.rl_game_info); 179 | } 180 | } 181 | 182 | public void setmOnClickListener(View.OnClickListener mOnClickListener) { 183 | this.mOnClickListener = mOnClickListener; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/adapter/RecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.net.Uri; 8 | import android.support.annotation.NonNull; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | import com.bumptech.glide.Glide; 17 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 18 | import com.bumptech.glide.request.RequestOptions; 19 | import com.bumptech.glide.request.target.SimpleTarget; 20 | import com.bumptech.glide.request.transition.Transition; 21 | import com.sunfusheng.glideimageview.GlideImageView; 22 | import com.wkz.share.R; 23 | import com.wkz.share.utils.ViewUtils; 24 | import com.wkz.share.zxing.QRCode; 25 | 26 | import java.io.File; 27 | import java.util.List; 28 | import java.util.Locale; 29 | import java.util.concurrent.ExecutionException; 30 | 31 | /** 32 | * @author Administrator 33 | * @date 2019/5/20 34 | */ 35 | public class RecyclerViewAdapter extends RecyclerView.Adapter { 36 | 37 | private Context mContext; 38 | private List mDatas; 39 | private String mCenterImageUrl; 40 | private String mUrl; 41 | private int mVertexColor; 42 | 43 | public RecyclerViewAdapter(Context mContext, List mDatas, String mCenterImageUrl, String mUrl, int mVertexColor) { 44 | this.mContext = mContext; 45 | this.mDatas = mDatas; 46 | this.mCenterImageUrl = mCenterImageUrl; 47 | this.mUrl = mUrl; 48 | this.mVertexColor = mVertexColor; 49 | } 50 | 51 | @NonNull 52 | @Override 53 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 54 | if (viewType == 1) { 55 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_recycler2, parent, false)) { 56 | }; 57 | } else { 58 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_recycler1, parent, false)) { 59 | }; 60 | } 61 | } 62 | 63 | @Override 64 | public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { 65 | if (position == 0) { 66 | //设置margin 67 | ViewUtils.setViewMargin(holder.itemView.findViewById(R.id.rl_game_info), true, 25, 100, 25, 0); 68 | holder.itemView.findViewById(R.id.rl_game_info).setBackgroundResource(R.drawable.shape_bg_0xffededed_cornersfive); 69 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_image)).load(mDatas.get(position), new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)); 70 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_icon)).load(mCenterImageUrl, new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)); 71 | ((TextView) holder.itemView.findViewById(R.id.tv_game_name)).setText(String.format(Locale.getDefault(), "《长恨歌》白居易%d", position)); 72 | } else if (position == getItemCount() - 1) { 73 | //设置margin 74 | ViewUtils.setViewMargin(holder.itemView.findViewById(R.id.rl_qr_code), true, 25, 0, 25, 150); 75 | 76 | //二维码中心图片 77 | Glide.with(mContext) 78 | .asBitmap() 79 | .load(mCenterImageUrl) 80 | .apply(new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)) 81 | .into(new SimpleTarget() { 82 | @Override 83 | public void onResourceReady(Bitmap resource, Transition transition) { 84 | ((ImageView) holder.itemView.findViewById(R.id.iv_qr_code)) 85 | .setImageBitmap(QRCode.createQRCodeWithLogo6(mUrl, 500, resource, mVertexColor)); 86 | } 87 | }); 88 | 89 | holder.itemView.findViewById(R.id.iv_qr_code).setOnLongClickListener(new View.OnLongClickListener() { 90 | @Override 91 | public boolean onLongClick(View v) { 92 | //打开浏览器下载游戏 93 | Intent intent = new Intent(); 94 | intent.setAction(Intent.ACTION_VIEW); 95 | intent.setData(Uri.parse(mUrl)); 96 | mContext.startActivity(intent); 97 | return false; 98 | } 99 | }); 100 | } else { 101 | //设置margin 102 | ViewUtils.setViewMargin(holder.itemView.findViewById(R.id.rl_game_info), true, 25, 15, 25, 0); 103 | if (position == getItemCount() - 2) { 104 | holder.itemView.findViewById(R.id.rl_game_info).setBackgroundResource(R.drawable.shape_bg_0xffededed_cornersfive_top); 105 | } else { 106 | holder.itemView.findViewById(R.id.rl_game_info).setBackgroundResource(R.drawable.shape_bg_0xffededed_cornersfive); 107 | } 108 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_image)).load(mDatas.get(position), new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)); 109 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_icon)).load(mCenterImageUrl, new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL)); 110 | ((TextView) holder.itemView.findViewById(R.id.tv_game_name)).setText(String.format(Locale.getDefault(), "《长恨歌》白居易%d", position)); 111 | } 112 | } 113 | 114 | public void onBindViewSync(@NonNull final RecyclerView.ViewHolder holder, final int position) { 115 | try { 116 | if (position == 0) { 117 | //设置margin 118 | ViewUtils.setViewMargin(holder.itemView.findViewById(R.id.rl_game_info), true, 25, 100, 25, 0); 119 | holder.itemView.findViewById(R.id.rl_game_info).setBackgroundResource(R.drawable.shape_bg_0xffededed_cornersfive); 120 | 121 | File gameImageFile = Glide.with(mContext) 122 | .load(mDatas.get(position)) 123 | .downloadOnly(0, 0) 124 | .get(); 125 | Bitmap gameImageBitmap = BitmapFactory.decodeFile(gameImageFile.getAbsolutePath()); 126 | 127 | File gameIconFile = Glide.with(mContext) 128 | .load(mCenterImageUrl) 129 | .downloadOnly(0, 0) 130 | .get(); 131 | Bitmap gameIconBitmap = BitmapFactory.decodeFile(gameIconFile.getAbsolutePath()); 132 | 133 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_image)).setImageBitmap(gameImageBitmap); 134 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_icon)).setImageBitmap(gameIconBitmap); 135 | ((TextView) holder.itemView.findViewById(R.id.tv_game_name)).setText(String.format(Locale.getDefault(), "《长恨歌》白居易%d", position)); 136 | } else if (position == getItemCount() - 1) { 137 | //设置margin 138 | ViewUtils.setViewMargin(holder.itemView.findViewById(R.id.rl_qr_code), true, 25, 0, 25, 150); 139 | 140 | //二维码中心图片 141 | File centerImageFile = Glide.with(mContext) 142 | .load(mCenterImageUrl) 143 | .downloadOnly(0, 0) 144 | .get(); 145 | Bitmap centerImageBitmap = BitmapFactory.decodeFile(centerImageFile.getAbsolutePath()); 146 | 147 | ((ImageView) holder.itemView.findViewById(R.id.iv_qr_code)) 148 | .setImageBitmap(QRCode.createQRCodeWithLogo6(mUrl, 500, centerImageBitmap, mVertexColor)); 149 | 150 | holder.itemView.findViewById(R.id.iv_qr_code).setOnLongClickListener(new View.OnLongClickListener() { 151 | @Override 152 | public boolean onLongClick(View v) { 153 | //打开浏览器 154 | Intent intent = new Intent(); 155 | intent.setAction(Intent.ACTION_VIEW); 156 | intent.setData(Uri.parse(mUrl)); 157 | mContext.startActivity(intent); 158 | return false; 159 | } 160 | }); 161 | } else { 162 | //设置margin 163 | ViewUtils.setViewMargin(holder.itemView.findViewById(R.id.rl_game_info), true, 25, 15, 25, 0); 164 | if (position == getItemCount() - 2) { 165 | holder.itemView.findViewById(R.id.rl_game_info).setBackgroundResource(R.drawable.shape_bg_0xffededed_cornersfive_top); 166 | } else { 167 | holder.itemView.findViewById(R.id.rl_game_info).setBackgroundResource(R.drawable.shape_bg_0xffededed_cornersfive); 168 | } 169 | 170 | File gameImageFile = Glide.with(mContext) 171 | .load(mDatas.get(position)) 172 | .downloadOnly(0, 0) 173 | .get(); 174 | Bitmap gameImageBitmap = BitmapFactory.decodeFile(gameImageFile.getAbsolutePath()); 175 | 176 | File gameIconFile = Glide.with(mContext) 177 | .load(mCenterImageUrl) 178 | .downloadOnly(0, 0) 179 | .get(); 180 | Bitmap gameIconBitmap = BitmapFactory.decodeFile(gameIconFile.getAbsolutePath()); 181 | 182 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_image)).setImageBitmap(gameImageBitmap); 183 | ((GlideImageView) holder.itemView.findViewById(R.id.iv_game_icon)).setImageBitmap(gameIconBitmap); 184 | ((TextView) holder.itemView.findViewById(R.id.tv_game_name)).setText(String.format(Locale.getDefault(), "《长恨歌》白居易%d", position)); 185 | } 186 | } catch (ExecutionException e) { 187 | e.printStackTrace(); 188 | } catch (InterruptedException e) { 189 | e.printStackTrace(); 190 | } 191 | } 192 | 193 | @Override 194 | public int getItemCount() { 195 | return mDatas.size() + 1; 196 | } 197 | 198 | @Override 199 | public int getItemViewType(int position) { 200 | if (position == getItemCount() - 1) { 201 | return 1; 202 | } 203 | return super.getItemViewType(position); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/blur/GlideBlurTransformation.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.blur; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.support.annotation.NonNull; 6 | 7 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 8 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 9 | import com.wkz.share.utils.BlurBitmapUtils; 10 | 11 | import java.security.MessageDigest; 12 | 13 | /** 14 | * Glide高斯模糊图片转化 15 | * 16 | * @author Administrator 17 | * @date 2018/5/21 18 | */ 19 | public class GlideBlurTransformation extends BitmapTransformation { 20 | 21 | private Context context; 22 | 23 | public GlideBlurTransformation(Context context) { 24 | this.context = context; 25 | } 26 | 27 | @Override 28 | protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { 29 | return BlurBitmapUtils.blurBitmap(context, toTransform, 25, outWidth, outHeight); 30 | } 31 | 32 | @Override 33 | public void updateDiskCacheKey(MessageDigest messageDigest) { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/BarConfig.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 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.os.Build; 10 | import android.util.DisplayMetrics; 11 | import android.util.TypedValue; 12 | import android.view.ViewConfiguration; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | class BarConfig { 17 | 18 | private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; 19 | private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; 20 | private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; 21 | private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"; 22 | private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; 23 | 24 | private static String sNavBarOverride; 25 | private final int mStatusBarHeight; 26 | private final int mActionBarHeight; 27 | private final boolean mHasNavigationBar; 28 | private final int mNavigationBarHeight; 29 | private final int mNavigationBarWidth; 30 | private final boolean mInPortrait; 31 | private final float mSmallestWidthDp; 32 | 33 | static { 34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 35 | try { 36 | Class c = Class.forName("android.os.SystemProperties"); 37 | Method m = c.getDeclaredMethod("get", String.class); 38 | m.setAccessible(true); 39 | sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); 40 | } catch (Throwable e) { 41 | sNavBarOverride = null; 42 | } 43 | } 44 | } 45 | 46 | 47 | public BarConfig(Activity activity) { 48 | Resources res = activity.getResources(); 49 | mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT); 50 | mSmallestWidthDp = getSmallestWidthDp(activity); 51 | mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME); 52 | mActionBarHeight = getActionBarHeight(activity); 53 | mNavigationBarHeight = getNavigationBarHeight(activity); 54 | mNavigationBarWidth = getNavigationBarWidth(activity); 55 | mHasNavigationBar = (mNavigationBarHeight > 0); 56 | } 57 | 58 | @TargetApi(14) 59 | private int getActionBarHeight(Context context) { 60 | int result = 0; 61 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 62 | TypedValue tv = new TypedValue(); 63 | context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); 64 | result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); 65 | } 66 | return result; 67 | } 68 | 69 | @TargetApi(14) 70 | private int getNavigationBarHeight(Context context) { 71 | Resources res = context.getResources(); 72 | int result = 0; 73 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 74 | if (hasNavBar(context)) { 75 | String key; 76 | if (mInPortrait) { 77 | key = NAV_BAR_HEIGHT_RES_NAME; 78 | } else { 79 | key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; 80 | } 81 | return getInternalDimensionSize(res, key); 82 | } 83 | } 84 | return result; 85 | } 86 | 87 | @TargetApi(14) 88 | private int getNavigationBarWidth(Context context) { 89 | Resources res = context.getResources(); 90 | int result = 0; 91 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 92 | if (hasNavBar(context)) { 93 | return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME); 94 | } 95 | } 96 | return result; 97 | } 98 | 99 | @TargetApi(14) 100 | private boolean hasNavBar(Context context) { 101 | Resources res = context.getResources(); 102 | int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); 103 | if (resourceId != 0) { 104 | boolean hasNav = res.getBoolean(resourceId); 105 | // check override flag (see static block) 106 | if ("1".equals(sNavBarOverride)) { 107 | hasNav = false; 108 | } else if ("0".equals(sNavBarOverride)) { 109 | hasNav = true; 110 | } 111 | return hasNav; 112 | } else { // fallback 113 | return !ViewConfiguration.get(context).hasPermanentMenuKey(); 114 | } 115 | } 116 | 117 | private int getInternalDimensionSize(Resources res, String key) { 118 | int result = 0; 119 | int resourceId = res.getIdentifier(key, "dimen", "android"); 120 | if (resourceId > 0) { 121 | result = res.getDimensionPixelSize(resourceId); 122 | } 123 | return result; 124 | } 125 | 126 | @SuppressLint("NewApi") 127 | private float getSmallestWidthDp(Activity activity) { 128 | DisplayMetrics metrics = new DisplayMetrics(); 129 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 130 | activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); 131 | } else { 132 | // TODO this is not correct, but we don't really care pre-kitkat 133 | activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 134 | } 135 | float widthDp = metrics.widthPixels / metrics.density; 136 | float heightDp = metrics.heightPixels / metrics.density; 137 | return Math.min(widthDp, heightDp); 138 | } 139 | 140 | /** 141 | * Should a navigation bar appear at the bottom of the screen in the current 142 | * device configuration? A navigation bar may appear on the right side of 143 | * the screen in certain configurations. 144 | * 145 | * @return True if navigation should appear at the bottom of the screen, False otherwise. 146 | */ 147 | public boolean isNavigationAtBottom() { 148 | return (mSmallestWidthDp >= 600 || mInPortrait); 149 | } 150 | 151 | /** 152 | * Get the height of the system status bar. 153 | * 154 | * @return The height of the status bar (in pixels). 155 | */ 156 | public int getStatusBarHeight() { 157 | return mStatusBarHeight; 158 | } 159 | 160 | /** 161 | * Get the height of the action bar. 162 | * 163 | * @return The height of the action bar (in pixels). 164 | */ 165 | public int getActionBarHeight() { 166 | return mActionBarHeight; 167 | } 168 | 169 | /** 170 | * Does this device have a system navigation bar? 171 | * 172 | * @return True if this device uses soft key navigation, False otherwise. 173 | */ 174 | public boolean hasNavigtionBar() { 175 | return mHasNavigationBar; 176 | } 177 | 178 | /** 179 | * Get the height of the system navigation bar. 180 | * 181 | * @return The height of the navigation bar (in pixels). If the device does not have 182 | * soft navigation keys, this will always return 0. 183 | */ 184 | public int getNavigationBarHeight() { 185 | return mNavigationBarHeight; 186 | } 187 | 188 | /** 189 | * Get the width of the system navigation bar when it is placed vertically on the screen. 190 | * 191 | * @return The width of the navigation bar (in pixels). If the device does not have 192 | * soft navigation keys, this will always return 0. 193 | */ 194 | public int getNavigationBarWidth() { 195 | return mNavigationBarWidth; 196 | } 197 | 198 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/BarHide.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 2 | 3 | /** 4 | * Created by geyifeng on 2017/4/25. 5 | */ 6 | 7 | public enum BarHide { 8 | /** 9 | * 隐藏状态栏 10 | */ 11 | FLAG_HIDE_STATUS_BAR, 12 | /** 13 | * 隐藏导航栏 14 | */ 15 | FLAG_HIDE_NAVIGATION_BAR, 16 | /** 17 | * 隐藏状态栏和导航栏 18 | */ 19 | FLAG_HIDE_BAR, 20 | /** 21 | * 显示状态栏和导航栏 22 | */ 23 | FLAG_SHOW_BAR 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/BarParams.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.ColorInt; 5 | import android.support.annotation.FloatRange; 6 | import android.view.View; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class BarParams { 12 | @ColorInt 13 | public int statusBarColor = Color.TRANSPARENT; 14 | @ColorInt 15 | public int navigationBarColor = Color.BLACK; 16 | @FloatRange(from = 0f, to = 1f) 17 | public float statusBarAlpha = 0.0f; 18 | @FloatRange(from = 0f, to = 1f) 19 | public float navigationBarAlpha = 0.0f; 20 | public boolean fullScreen = false; 21 | public boolean fullScreenTemp = fullScreen; 22 | public BarHide barHide = BarHide.FLAG_SHOW_BAR; 23 | public boolean darkFont = false; 24 | @ColorInt 25 | public int statusBarColorTransform = Color.BLACK; 26 | @ColorInt 27 | public int navigationBarColorTransform = Color.BLACK; 28 | public View view; 29 | public Map> viewMap = new HashMap<>(); 30 | @ColorInt 31 | public int viewColorBeforeTransform = statusBarColor; 32 | @ColorInt 33 | public int viewColorAfterTransform = statusBarColorTransform; 34 | public boolean fits = false; 35 | public int navigationBarColorTem = navigationBarColor; 36 | public View statusBarView; 37 | public View navigationBarView; 38 | public View statusBarViewByHeight; 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/BarType.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 2 | 3 | public enum BarType { 4 | /** 5 | * 状态栏 6 | */ 7 | STATUS_BAR, 8 | /** 9 | * 导航栏 10 | */ 11 | NAVIGATION_BAR, 12 | /** 13 | * 同时设置状态栏和导航栏 14 | */ 15 | ALL_BAR 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/ImmersionFragment.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | /** 6 | * ImmersionFragment沉浸式基类,因为fragment是基于activity之上的, 7 | * 为了能够在fragment使用沉浸式而fragment之间又相互不影响,必须实现immersionInit方法, 8 | * 原理是当用户可见才执行沉浸式初始化 9 | */ 10 | public abstract class ImmersionFragment extends Fragment { 11 | @Override 12 | public void setUserVisibleHint(boolean isVisibleToUser) { 13 | super.setUserVisibleHint(isVisibleToUser); 14 | if ((isVisibleToUser && isResumed())) { 15 | onResume(); 16 | } 17 | } 18 | 19 | @Override 20 | public void onResume() { 21 | super.onResume(); 22 | if (getUserVisibleHint()) { 23 | immersionInit(); 24 | } 25 | } 26 | 27 | protected abstract void immersionInit(); 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/KeyboardPatch.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Rect; 5 | import android.os.Build; 6 | import android.view.View; 7 | import android.view.ViewTreeObserver; 8 | import android.view.WindowManager; 9 | 10 | /** 11 | * 解决EditText和软键盘的问题 12 | */ 13 | public class KeyboardPatch { 14 | private Activity mActivity; 15 | private View mDecorView; 16 | private View mContentView; 17 | 18 | 19 | private KeyboardPatch() { 20 | } 21 | 22 | /** 23 | * 构造函数 24 | * 25 | * @param activity 需要解决bug的activity 26 | * @param contentView 界面容器,如果使用ImmersionBar这个库,对于android 5.0来说,在activity中一般是R.id.content 27 | * ,也可能是Fragment的容器,根据个人需要传递,为了方便指定布局的根节点就行 28 | */ 29 | private KeyboardPatch(Activity activity, View contentView) { 30 | this.mActivity = activity; 31 | this.mDecorView = activity.getWindow().getDecorView(); 32 | this.mContentView = contentView; 33 | } 34 | 35 | public static KeyboardPatch patch(Activity activity, View contentView) { 36 | return new KeyboardPatch(activity, contentView); 37 | } 38 | 39 | /** 40 | * 监听layout变化 41 | */ 42 | public void enable() { 43 | mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN 44 | | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); 45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 46 | //当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类 47 | mDecorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); 48 | } 49 | } 50 | 51 | /** 52 | * 取消监听 53 | */ 54 | public void disable() { 55 | mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN 56 | | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); 57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 58 | mDecorView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener); 59 | } 60 | } 61 | 62 | private ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { 63 | @Override 64 | public void onGlobalLayout() { 65 | Rect r = new Rect(); 66 | //获取当前窗口可视区域大小 67 | mDecorView.getWindowVisibleDisplayFrame(r); 68 | //获取屏幕密度,不包含导航栏 69 | int height = mDecorView.getContext().getResources().getDisplayMetrics().heightPixels; 70 | int diff = height - r.bottom; 71 | if (diff > 0) { 72 | if (mContentView.getPaddingBottom() != diff) { 73 | mContentView.setPadding(0, 0, 0, diff); 74 | } 75 | } else { 76 | if (mContentView.getPaddingBottom() != 0) { 77 | mContentView.setPadding(0, 0, 0, 0); 78 | } 79 | } 80 | } 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/immersionbar/OSUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.immersionbar; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.lang.reflect.Method; 6 | 7 | public class OSUtils { 8 | 9 | private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"; 10 | private static final String KEY_EMUI_VERSION_NAME = "ro.build.version.emui"; 11 | private static final String KEY_DISPLAY = "ro.build.display.id"; 12 | 13 | public static String MIUIVersion() { 14 | return isMIUI() ? getSystemProperty(KEY_MIUI_VERSION_NAME, null) : ""; 15 | } 16 | 17 | public static boolean isMIUI() { 18 | String property = getSystemProperty(KEY_MIUI_VERSION_NAME, null); 19 | return !TextUtils.isEmpty(property); 20 | } 21 | 22 | public static boolean isFlymeOS() { 23 | return getMeizuFlymeOSFlag().toLowerCase().contains("flyme"); 24 | } 25 | 26 | public static boolean isEMUI() { 27 | String property = getSystemProperty(KEY_EMUI_VERSION_NAME, null); 28 | return !TextUtils.isEmpty(property); 29 | } 30 | 31 | public static boolean isEMUI3_1() { 32 | if ("EmotionUI_3.1".equals(getSystemProperty(KEY_EMUI_VERSION_NAME, null))) { 33 | return true; 34 | } 35 | return false; 36 | } 37 | 38 | public static String getMeizuFlymeOSFlag() { 39 | return getSystemProperty(KEY_DISPLAY, ""); 40 | } 41 | 42 | private static String getSystemProperty(String key, String defaultValue) { 43 | try { 44 | Class clz = Class.forName("android.os.SystemProperties"); 45 | Method get = clz.getMethod("get", String.class, String.class); 46 | return (String) get.invoke(clz, key, defaultValue); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | return defaultValue; 51 | } 52 | 53 | 54 | private static String getEmuiVersion() { 55 | Class classType; 56 | try { 57 | classType = Class.forName("android.os.SystemProperties"); 58 | Method getMethod = classType.getDeclaredMethod("get", String.class); 59 | return (String) getMethod.invoke(classType, "ro.build.version.emui"); 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | } 63 | return ""; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/share/OnShareListener.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.share; 2 | 3 | /** 4 | * 分享监听 5 | * 6 | * @author Administrator 7 | * @date 2019/5/15 8 | */ 9 | public interface OnShareListener { 10 | 11 | /** 12 | * 点击关闭按钮 13 | * 14 | * @param shareDialog 分享弹窗 15 | */ 16 | void onClickCloseBtn(ShareDialog shareDialog); 17 | 18 | /** 19 | * 触摸空白区域 20 | * 21 | * @param shareDialog 分享弹窗 22 | */ 23 | void onTouchOutSide(ShareDialog shareDialog); 24 | 25 | /** 26 | * 解散弹窗 27 | * 28 | * @param shareDialog 分享弹窗 29 | */ 30 | void onDismiss(ShareDialog shareDialog); 31 | 32 | /** 33 | * 点击分享平台 34 | * 35 | * @param shareDialog 分享弹窗 36 | * @param holder 分享视图持有者 37 | * @param sharePlatform 分享平台{@link SharePlatform} 38 | */ 39 | void onClickSharePlatform(ShareDialog shareDialog, SharePlatformAdapter.ViewHolder holder, int sharePlatform); 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/share/ShareDialog.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.share; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.content.DialogInterface; 7 | import android.graphics.Color; 8 | import android.graphics.drawable.ColorDrawable; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.support.annotation.NonNull; 12 | import android.support.v7.widget.LinearLayoutManager; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.text.TextUtils; 15 | import android.view.Gravity; 16 | import android.view.MotionEvent; 17 | import android.view.View; 18 | import android.view.WindowManager; 19 | import android.widget.FrameLayout; 20 | import android.widget.ImageView; 21 | import android.widget.LinearLayout; 22 | import android.widget.RelativeLayout; 23 | import android.widget.TextView; 24 | 25 | import com.wkz.share.R; 26 | import com.wkz.share.utils.ViewUtils; 27 | 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | /** 32 | * 分享弹窗 33 | * 34 | * @author Administrator 35 | * @date 2018/5/15 36 | */ 37 | public class ShareDialog extends Dialog { 38 | 39 | private FrameLayout mDialogFl; 40 | private ImageView mCloseIv; 41 | private FrameLayout mCloseFl; 42 | private RelativeLayout mSharePlatformRl; 43 | private TextView mShareTitleTv; 44 | private RecyclerView mSharePlatformRv; 45 | 46 | private String mShareTitle; 47 | private OnShareListener mOnShareListener; 48 | private SharePlatformAdapter mSharePlatformAdapter; 49 | 50 | public ShareDialog(@NonNull Context context) { 51 | super(context, R.style.Theme_ShareDialog); 52 | } 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | //初始化窗口属性 58 | initWindowAttribute(); 59 | //设置视图 60 | setContentView(R.layout.dialog_share); 61 | //设置是否可撤销 62 | setCancelable(true); 63 | //设置触摸外部是否可撤销 64 | setCanceledOnTouchOutside(true); 65 | //初始化视图 66 | initView(); 67 | //初始化监听 68 | initListener(); 69 | //初始化分享平台 70 | initSharePlatform(); 71 | } 72 | 73 | private void initView() { 74 | mShareTitleTv = (TextView) findViewById(R.id.tv_share_title); 75 | mSharePlatformRv = (RecyclerView) findViewById(R.id.rv_share_platform); 76 | mCloseIv = (ImageView) findViewById(R.id.iv_close); 77 | mCloseFl = (FrameLayout) findViewById(R.id.fl_close); 78 | mDialogFl = (FrameLayout) findViewById(R.id.fl_dialog); 79 | mSharePlatformRl = (RelativeLayout) findViewById(R.id.rl_share_platform); 80 | 81 | 82 | //分享标题 83 | if (!TextUtils.isEmpty(mShareTitle)) { 84 | mShareTitleTv.setText(mShareTitle); 85 | } 86 | } 87 | 88 | /** 89 | * 初始化监听 90 | */ 91 | @SuppressLint("ClickableViewAccessibility") 92 | private void initListener() { 93 | mDialogFl.setOnTouchListener(new View.OnTouchListener() { 94 | @Override 95 | public boolean onTouch(View v, MotionEvent event) { 96 | if (event.getAction() == MotionEvent.ACTION_UP) { 97 | if (event.getY() > mCloseFl.getBottom() && event.getY() < mSharePlatformRl.getTop()) { 98 | dismiss(); 99 | if (mOnShareListener != null) { 100 | mOnShareListener.onTouchOutSide(ShareDialog.this); 101 | } 102 | } 103 | } 104 | return true; 105 | } 106 | }); 107 | 108 | mCloseFl.setOnClickListener(new View.OnClickListener() { 109 | @Override 110 | public void onClick(View v) { 111 | dismiss(); 112 | if (mOnShareListener != null) { 113 | mOnShareListener.onClickCloseBtn(ShareDialog.this); 114 | } 115 | } 116 | }); 117 | 118 | setOnDismissListener(new OnDismissListener() { 119 | @Override 120 | public void onDismiss(DialogInterface dialog) { 121 | if (mOnShareListener != null) { 122 | mOnShareListener.onDismiss((ShareDialog) dialog); 123 | } 124 | } 125 | }); 126 | } 127 | 128 | /** 129 | * 初始化窗口属性 130 | */ 131 | private void initWindowAttribute() { 132 | if (getWindow() != null) { 133 | //替换掉默认主题的背景,默认主题背景有一个16dp的padding 134 | getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 135 | //外边距 136 | ViewUtils.setViewPadding(getWindow().getDecorView(), true, 0, 0, 0, 0); 137 | //设置重力位置 138 | getWindow().setGravity(Gravity.BOTTOM); 139 | //设置弹窗的宽高 140 | getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); 141 | //全屏,隐藏状态栏, 142 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 143 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 144 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 145 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 146 | } 147 | } 148 | } 149 | 150 | 151 | /** 152 | * 初始化分享平台 153 | */ 154 | private void initSharePlatform() { 155 | mSharePlatformRv.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayout.HORIZONTAL, false)); 156 | 157 | List datas = new ArrayList<>(); 158 | datas.add(new SharePlatformBean().setIconRes(R.mipmap.ic_share_friend_circle).setPlatformName("微信朋友圈")); 159 | datas.add(new SharePlatformBean().setIconRes(R.mipmap.ic_share_wechat).setPlatformName("微信好友")); 160 | datas.add(new SharePlatformBean().setIconRes(R.mipmap.ic_share_qqspace).setPlatformName("QQ空间")); 161 | datas.add(new SharePlatformBean().setIconRes(R.mipmap.ic_share_qq).setPlatformName("QQ好友")); 162 | datas.add(new SharePlatformBean().setIconRes(R.mipmap.ic_share_microblog).setPlatformName("微博")); 163 | datas.add(new SharePlatformBean().setIconRes(R.mipmap.ic_share_link).setPlatformName("复制链接")); 164 | 165 | mSharePlatformRv.setAdapter(mSharePlatformAdapter = new SharePlatformAdapter(this, datas) 166 | .setOnShareListener(mOnShareListener) 167 | ); 168 | } 169 | 170 | @Override 171 | public void show() { 172 | super.show(); 173 | //为了每次show的时候执行动画 174 | mSharePlatformAdapter.notifyDataSetChanged(); 175 | } 176 | 177 | public ShareDialog setShareTitle(String mShareTitle) { 178 | this.mShareTitle = mShareTitle; 179 | return this; 180 | } 181 | 182 | public ShareDialog setOnShareListener(OnShareListener mOnShareListener) { 183 | this.mOnShareListener = mOnShareListener; 184 | return this; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/share/SharePlatform.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.share; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target(ElementType.FIELD) 9 | @Retention(RetentionPolicy.SOURCE) 10 | public @interface SharePlatform { 11 | /** 12 | * 微信 13 | */ 14 | int WeChat = 1; 15 | /** 16 | * 微信朋友圈 17 | */ 18 | int WeChatMoments = 2; 19 | /** 20 | * QQ 21 | */ 22 | int QQ = 3; 23 | /** 24 | * QQ空间 25 | */ 26 | int QQSpace = 4; 27 | /** 28 | * 微博 29 | */ 30 | int MicroBlog = 5; 31 | /** 32 | * 复制链接 33 | */ 34 | int Link = 6; 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/share/SharePlatformAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.share; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.LinearLayout; 9 | import android.widget.TextView; 10 | 11 | import com.sunfusheng.glideimageview.GlideImageView; 12 | import com.wkz.share.R; 13 | import com.wkz.share.utils.AnimationUtils; 14 | import com.wkz.share.utils.ViewUtils; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 分享平台适配器 21 | * 22 | * @author Administrator 23 | * @date 2019/5/15 24 | */ 25 | public class SharePlatformAdapter extends RecyclerView.Adapter { 26 | 27 | private ShareDialog mShareDialog; 28 | private List mDatas; 29 | private OnShareListener mOnShareListener; 30 | 31 | SharePlatformAdapter(ShareDialog shareDialog, List mDatas) { 32 | this.mShareDialog = shareDialog; 33 | this.mDatas = mDatas == null ? new ArrayList() : mDatas; 34 | } 35 | 36 | @Override 37 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 38 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_share_dialog, parent, false)); 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(final ViewHolder holder, int position) { 43 | if (position == mDatas.size() - 1) { 44 | //最右边那个 45 | ViewUtils.setViewMargin(holder.mItemLl, true, 25, 0, 25, 15); 46 | } else { 47 | ViewUtils.setViewMargin(holder.mItemLl, true, 25, 0, 15, 15); 48 | } 49 | 50 | holder.mShareIconIv.loadLocalImage(mDatas.get(position).getIconRes(), 0); 51 | holder.mSharePlatformNameTv.setText(mDatas.get(position).getPlatformName()); 52 | 53 | //开始动画 54 | AnimationUtils.startOvershootAnimation(holder.mShareIconIv, 200, position * 100); 55 | 56 | holder.mShareIconIv.setOnClickListener(new View.OnClickListener() { 57 | @Override 58 | public void onClick(View v) { 59 | holder.mItemLl.performClick(); 60 | } 61 | }); 62 | 63 | holder.mItemLl.setOnClickListener(new View.OnClickListener() { 64 | @Override 65 | public void onClick(View v) { 66 | if (mShareDialog != null && mShareDialog.isShowing()) { 67 | mShareDialog.dismiss(); 68 | } 69 | if (mOnShareListener != null) { 70 | mOnShareListener.onClickSharePlatform(mShareDialog, holder, SharePlatform.WeChat); 71 | } 72 | } 73 | }); 74 | } 75 | 76 | @Override 77 | public int getItemCount() { 78 | return mDatas.size(); 79 | } 80 | 81 | SharePlatformAdapter setOnShareListener(OnShareListener mOnShareListener) { 82 | this.mOnShareListener = mOnShareListener; 83 | return this; 84 | } 85 | 86 | public static class ViewHolder extends RecyclerView.ViewHolder { 87 | 88 | private GlideImageView mShareIconIv; 89 | private TextView mSharePlatformNameTv; 90 | private LinearLayout mItemLl; 91 | 92 | ViewHolder(View itemView) { 93 | super(itemView); 94 | 95 | initView(itemView); 96 | } 97 | 98 | private void initView(@NonNull final View itemView) { 99 | mShareIconIv = (GlideImageView) itemView.findViewById(R.id.iv_share_icon); 100 | mSharePlatformNameTv = (TextView) itemView.findViewById(R.id.tv_share_platform_name); 101 | mItemLl = (LinearLayout) itemView.findViewById(R.id.ll_item); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/share/SharePlatformBean.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.share; 2 | 3 | /** 4 | * 分享平台实体 5 | * 6 | * @author Administrator 7 | * @date 2019/5/15 8 | */ 9 | public class SharePlatformBean { 10 | 11 | private int iconRes; 12 | private String platformName; 13 | 14 | public int getIconRes() { 15 | return iconRes; 16 | } 17 | 18 | public SharePlatformBean setIconRes(int iconRes) { 19 | this.iconRes = iconRes; 20 | return this; 21 | } 22 | 23 | public String getPlatformName() { 24 | return platformName; 25 | } 26 | 27 | public SharePlatformBean setPlatformName(String platformName) { 28 | this.platformName = platformName; 29 | return this; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return "SharePlatformBean{" + 35 | "iconRes=" + iconRes + 36 | ", platformName='" + platformName + '\'' + 37 | '}'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/ui/ListViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.ui; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.AdapterView; 8 | import android.widget.FrameLayout; 9 | import android.widget.ListView; 10 | import android.widget.Toast; 11 | 12 | import com.wkz.share.R; 13 | import com.wkz.share.adapter.ListViewAdapter; 14 | import com.wkz.share.immersionbar.BarHide; 15 | import com.wkz.share.immersionbar.ImmersionBar; 16 | import com.wkz.share.share.OnShareListener; 17 | import com.wkz.share.share.ShareDialog; 18 | import com.wkz.share.share.SharePlatformAdapter; 19 | import com.wkz.share.utils.ScreenShotUtils; 20 | 21 | import java.io.File; 22 | import java.util.concurrent.Callable; 23 | 24 | import io.reactivex.Observable; 25 | import io.reactivex.ObservableSource; 26 | import io.reactivex.Observer; 27 | import io.reactivex.android.schedulers.AndroidSchedulers; 28 | import io.reactivex.disposables.Disposable; 29 | import io.reactivex.functions.Consumer; 30 | import io.reactivex.schedulers.Schedulers; 31 | 32 | /** 33 | * 列表视图的长截图分享界面 34 | * 35 | * @author Administrator 36 | * @date 2018/5/16 37 | */ 38 | 39 | public class ListViewActivity extends MainActivity { 40 | 41 | private FrameLayout mFlRoot; 42 | private ListView mLvList; 43 | 44 | private Activity mContext; 45 | /** 46 | * 分享弹窗 47 | */ 48 | private ShareDialog mShareDialog; 49 | private ListViewAdapter mListViewAdapter; 50 | private Disposable mDisposable; 51 | 52 | @Override 53 | protected void onCreate(Bundle savedInstanceState) { 54 | super.onCreate(savedInstanceState); 55 | mContext = this; 56 | setContentView(R.layout.activity_list_view); 57 | initView(); 58 | initListView(); 59 | initListener(); 60 | initData(); 61 | } 62 | 63 | private void initView() { 64 | mLvList = (ListView) findViewById(R.id.lvList); 65 | mFlRoot = (FrameLayout) findViewById(R.id.fl_root); 66 | } 67 | 68 | private void initListView() { 69 | mLvList.setAdapter(mListViewAdapter = new ListViewAdapter(mContext, mDatas)); 70 | } 71 | 72 | private void initListener() { 73 | mLvList.setOnItemClickListener(new AdapterView.OnItemClickListener() { 74 | @Override 75 | public void onItemClick(AdapterView parent, View view, int position, long id) { 76 | //item点击 77 | if (!mShareDialog.isShowing()) { 78 | mShareDialog.show(); 79 | } 80 | zoomOut(mLvList); 81 | } 82 | }); 83 | mListViewAdapter.setmOnClickListener(new View.OnClickListener() { 84 | @Override 85 | public void onClick(View v) { 86 | //item点击 87 | if (!mShareDialog.isShowing()) { 88 | mShareDialog.show(); 89 | } 90 | zoomOut(mLvList); 91 | } 92 | }); 93 | } 94 | 95 | private void initData() { 96 | //隐藏状态栏 97 | ImmersionBar.with(this) 98 | .fitsSystemWindows(false) 99 | .statusBarDarkFont(false) 100 | .hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR) 101 | .init(); 102 | 103 | //分享弹窗 104 | mShareDialog = new ShareDialog(this) 105 | .setShareTitle("图片分享到") 106 | .setOnShareListener(new OnShareListener() { 107 | @Override 108 | public void onClickCloseBtn(ShareDialog shareDialog) { 109 | finish(); 110 | } 111 | 112 | @Override 113 | public void onTouchOutSide(ShareDialog shareDialog) { 114 | zoomIn(mLvList); 115 | } 116 | 117 | @Override 118 | public void onDismiss(ShareDialog shareDialog) { 119 | zoomIn(mLvList); 120 | } 121 | 122 | @Override 123 | public void onClickSharePlatform(ShareDialog shareDialog, SharePlatformAdapter.ViewHolder holder, int sharePlatform) { 124 | // 长截图 125 | mDisposable = Observable.defer( 126 | new Callable>() { 127 | @Override 128 | public ObservableSource call() throws Exception { 129 | return new ObservableSource() { 130 | @Override 131 | public void subscribe(Observer observer) { 132 | // 开始截图 133 | observer.onNext(ScreenShotUtils.shotListView(mLvList)); 134 | } 135 | }; 136 | } 137 | }) 138 | .subscribeOn(Schedulers.computation()) 139 | .observeOn(AndroidSchedulers.mainThread()) 140 | .subscribe(new Consumer() { 141 | @Override 142 | public void accept(Bitmap bitmap) throws Exception { 143 | // 保存图片 144 | File file = ScreenShotUtils.savePicture(mContext, bitmap); 145 | 146 | Toast.makeText(mContext, "图片已保存至 " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show(); 147 | } 148 | }); 149 | } 150 | }); 151 | mShareDialog.show(); 152 | } 153 | 154 | @Override 155 | protected void onDestroy() { 156 | super.onDestroy(); 157 | if (mDisposable != null && !mDisposable.isDisposed()) { 158 | mDisposable.dispose(); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.ui; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import com.wkz.share.R; 10 | import com.wkz.share.utils.AnimationUtils; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 16 | 17 | protected static final float ZOOM_BEFORE = 1.0F; 18 | protected static final float ZOOM_AFTER = 1.05F; 19 | protected static final long DURATION = 200L; 20 | 21 | protected static final List mDatas = Arrays.asList( 22 | "http://k.zol-img.com.cn/sjbbs/7692/a7691515_s.jpg", 23 | "http://pic37.nipic.com/20140113/8800276_184927469000_2.png", 24 | "http://d.hiphotos.baidu.com/lvpics/w=1000/sign=e2347e78217f9e2f703519082f00eb24/730e0cf3d7ca7bcb49f90bb1b8096b63f724a8aa.jpg", 25 | "http://f.hiphotos.baidu.com/lvpics/w=600/sign=b7c305c7aad3fd1f3609a13a004f25ce/dcc451da81cb39db83b5f1bfd2160924aa1830e5.jpg", 26 | "http://b-ssl.duitang.com/uploads/item/201412/01/20141201233907_YmPCw.jpeg", 27 | "http://d.hiphotos.baidu.com/lvpics/w=1000/sign=65d18f97ae6eddc426e7b0fb09ebb7fd/8326cffc1e178a82d224ded2f503738da977e8ac.jpg", 28 | "http://img5.imgtn.bdimg.com/it/u=1921905645,1831992008&fm=26&gp=0.jpg", 29 | "http://img4.imgtn.bdimg.com/it/u=903712134,2931096712&fm=26&gp=0.jpg", 30 | "http://img3.imgtn.bdimg.com/it/u=3394504538,1396132709&fm=26&gp=0.jpg", 31 | "http://img3.imgtn.bdimg.com/it/u=2995907650,3595492611&fm=26&gp=0.jpg", 32 | "http://img5.imgtn.bdimg.com/it/u=1517815520,1162522071&fm=26&gp=0.jpg", 33 | "http://img0.imgtn.bdimg.com/it/u=2346425371,1207604549&fm=26&gp=0.jpg" 34 | ); 35 | 36 | private Button mMScrollView; 37 | private Button mMListView; 38 | private Button mMRecyclerView; 39 | private Button mMWebView; 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_main); 45 | initView(); 46 | } 47 | 48 | private void initView() { 49 | mMScrollView = (Button) findViewById(R.id.mScrollView); 50 | mMScrollView.setOnClickListener(this); 51 | mMListView = (Button) findViewById(R.id.mListView); 52 | mMListView.setOnClickListener(this); 53 | mMRecyclerView = (Button) findViewById(R.id.mRecyclerView); 54 | mMRecyclerView.setOnClickListener(this); 55 | mMWebView = (Button) findViewById(R.id.mWebView); 56 | mMWebView.setOnClickListener(this); 57 | } 58 | 59 | @Override 60 | public void onClick(View v) { 61 | switch (v.getId()) { 62 | case R.id.mScrollView: 63 | startActivity(new Intent(this, ScrollViewActivity.class)); 64 | break; 65 | case R.id.mListView: 66 | startActivity(new Intent(this, ListViewActivity.class)); 67 | break; 68 | case R.id.mRecyclerView: 69 | startActivity(new Intent(this, RecyclerViewActivity.class)); 70 | break; 71 | case R.id.mWebView: 72 | startActivity(new Intent(this, WebViewActivity.class)); 73 | break; 74 | default: 75 | break; 76 | } 77 | } 78 | 79 | /** 80 | * 缩小 81 | * 82 | * @param targetView 目标视图 83 | */ 84 | protected void zoomIn(View targetView) { 85 | AnimationUtils.zoomIn(targetView, ZOOM_BEFORE, ZOOM_BEFORE, ZOOM_AFTER, ZOOM_AFTER, DURATION); 86 | } 87 | 88 | /** 89 | * 放大 90 | * 91 | * @param targetView 目标视图 92 | */ 93 | protected void zoomOut(View targetView) { 94 | AnimationUtils.zoomOut(targetView, ZOOM_AFTER, ZOOM_AFTER, ZOOM_BEFORE, ZOOM_BEFORE, DURATION); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/ui/RecyclerViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.ui; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.annotation.ColorInt; 8 | import android.support.annotation.Nullable; 9 | import android.support.v4.view.GestureDetectorCompat; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.view.GestureDetector; 13 | import android.view.MotionEvent; 14 | import android.widget.Toast; 15 | 16 | import com.wkz.share.R; 17 | import com.wkz.share.adapter.RecyclerViewAdapter; 18 | import com.wkz.share.immersionbar.BarHide; 19 | import com.wkz.share.immersionbar.ImmersionBar; 20 | import com.wkz.share.share.OnShareListener; 21 | import com.wkz.share.share.ShareDialog; 22 | import com.wkz.share.share.SharePlatformAdapter; 23 | import com.wkz.share.utils.ScreenShotUtils; 24 | 25 | import java.io.File; 26 | import java.util.concurrent.Callable; 27 | 28 | import io.reactivex.Observable; 29 | import io.reactivex.ObservableSource; 30 | import io.reactivex.Observer; 31 | import io.reactivex.android.schedulers.AndroidSchedulers; 32 | import io.reactivex.disposables.Disposable; 33 | import io.reactivex.functions.Consumer; 34 | import io.reactivex.schedulers.Schedulers; 35 | 36 | /** 37 | * 循环视图的长截图分享界面 38 | * 39 | * @author Administrator 40 | * @date 2018/5/16 41 | */ 42 | 43 | public class RecyclerViewActivity extends MainActivity { 44 | 45 | private RecyclerView mRvRecycler; 46 | 47 | private Activity mContext; 48 | /** 49 | * 二维码中心图片地址 50 | */ 51 | private String mCenterImageUrl = "http://gss0.baidu.com/-fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/5366d0160924ab1861c9326236fae6cd7a890b8c.jpg"; 52 | /** 53 | * 二维码顶角颜色 54 | */ 55 | @ColorInt 56 | private int mVertexColor = Color.parseColor("#ff000000"); 57 | /** 58 | * 扫描二维码打开百度 59 | */ 60 | private String mUrl = "https://www.baidu.com"; 61 | /** 62 | * 分享弹窗 63 | */ 64 | private ShareDialog mShareDialog; 65 | 66 | private Disposable mDisposable; 67 | 68 | 69 | @Override 70 | protected void onCreate(@Nullable Bundle savedInstanceState) { 71 | super.onCreate(savedInstanceState); 72 | 73 | mContext = this; 74 | 75 | setContentView(R.layout.activity_recycler_view); 76 | 77 | initView(); 78 | 79 | initListener(); 80 | 81 | initData(); 82 | 83 | initRecyclerView(); 84 | } 85 | 86 | private void initView() { 87 | mRvRecycler = (RecyclerView) findViewById(R.id.rvRecycler); 88 | } 89 | 90 | private void initListener() { 91 | mRvRecycler.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() { 92 | private GestureDetectorCompat mGestureDetectorCompat = new GestureDetectorCompat(mRvRecycler.getContext(), new GestureDetector.SimpleOnGestureListener() { 93 | @Override 94 | public boolean onSingleTapUp(MotionEvent e) { 95 | //item点击 96 | if (!mShareDialog.isShowing()) { 97 | mShareDialog.show(); 98 | } 99 | zoomOut(mRvRecycler); 100 | return true; 101 | } 102 | 103 | @Override 104 | public void onLongPress(MotionEvent e) { 105 | 106 | } 107 | }); 108 | 109 | @Override 110 | public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 111 | mGestureDetectorCompat.onTouchEvent(e); 112 | return false; 113 | } 114 | }); 115 | } 116 | 117 | private void initData() { 118 | //隐藏状态栏 119 | ImmersionBar.with(this) 120 | .fitsSystemWindows(false) 121 | .statusBarDarkFont(false) 122 | .hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR) 123 | .init(); 124 | 125 | //分享弹窗 126 | mShareDialog = new ShareDialog(this) 127 | .setShareTitle("图片分享到") 128 | .setOnShareListener(new OnShareListener() { 129 | @Override 130 | public void onClickCloseBtn(ShareDialog shareDialog) { 131 | finish(); 132 | } 133 | 134 | @Override 135 | public void onTouchOutSide(ShareDialog shareDialog) { 136 | zoomIn(mRvRecycler); 137 | } 138 | 139 | @Override 140 | public void onDismiss(ShareDialog shareDialog) { 141 | zoomIn(mRvRecycler); 142 | } 143 | 144 | @Override 145 | public void onClickSharePlatform(ShareDialog shareDialog, SharePlatformAdapter.ViewHolder holder, int sharePlatform) { 146 | // 长截图 147 | mDisposable = Observable.defer( 148 | new Callable>() { 149 | @Override 150 | public ObservableSource call() throws Exception { 151 | return new ObservableSource() { 152 | @Override 153 | public void subscribe(Observer observer) { 154 | // 开始截图 155 | observer.onNext(ScreenShotUtils.shotRecyclerView(mRvRecycler)); 156 | } 157 | }; 158 | } 159 | }) 160 | .subscribeOn(Schedulers.computation()) 161 | .observeOn(AndroidSchedulers.mainThread()) 162 | .subscribe(new Consumer() { 163 | @Override 164 | public void accept(Bitmap bitmap) throws Exception { 165 | // 保存图片 166 | File file = ScreenShotUtils.savePicture(mContext, bitmap); 167 | 168 | Toast.makeText(mContext, "图片已保存至 " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show(); 169 | } 170 | }); 171 | } 172 | }); 173 | mShareDialog.show(); 174 | } 175 | 176 | private void initRecyclerView() { 177 | mRvRecycler.setLayoutManager(new LinearLayoutManager(this)); 178 | mRvRecycler.setHasFixedSize(true); 179 | mRvRecycler.setAdapter(new RecyclerViewAdapter(mContext, mDatas, mCenterImageUrl, mUrl, mVertexColor)); 180 | } 181 | 182 | @Override 183 | protected void onDestroy() { 184 | super.onDestroy(); 185 | if (mDisposable != null && !mDisposable.isDisposed()) { 186 | mDisposable.dispose(); 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/ui/ScrollViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.drawable.BitmapDrawable; 9 | import android.graphics.drawable.Drawable; 10 | import android.net.Uri; 11 | import android.os.Bundle; 12 | import android.support.annotation.ColorInt; 13 | import android.support.annotation.NonNull; 14 | import android.support.annotation.Nullable; 15 | import android.support.v4.widget.NestedScrollView; 16 | import android.view.View; 17 | import android.widget.ImageView; 18 | import android.widget.LinearLayout; 19 | import android.widget.RelativeLayout; 20 | import android.widget.TextView; 21 | 22 | import com.bumptech.glide.Glide; 23 | import com.bumptech.glide.request.RequestOptions; 24 | import com.bumptech.glide.request.target.SimpleTarget; 25 | import com.bumptech.glide.request.transition.Transition; 26 | import com.sunfusheng.glideimageview.GlideImageView; 27 | import com.wkz.share.R; 28 | import com.wkz.share.blur.GlideBlurTransformation; 29 | import com.wkz.share.immersionbar.BarHide; 30 | import com.wkz.share.immersionbar.ImmersionBar; 31 | import com.wkz.share.share.OnShareListener; 32 | import com.wkz.share.share.ShareDialog; 33 | import com.wkz.share.share.SharePlatformAdapter; 34 | import com.wkz.share.utils.ScreenShotUtils; 35 | import com.wkz.share.zxing.QRCode; 36 | 37 | /** 38 | * 滚动视图的长截图分享界面 39 | * 40 | * @author Administrator 41 | * @date 2018/5/16 42 | */ 43 | public class ScrollViewActivity extends MainActivity implements View.OnClickListener, View.OnLongClickListener { 44 | 45 | 46 | private GlideImageView mGameImageIv; 47 | private GlideImageView mGameIconIv; 48 | private TextView mGameNameTv; 49 | private TextView mGameDescriptionTv; 50 | private RelativeLayout mGameInfoRl; 51 | private NestedScrollView mScrollNsv; 52 | private ImageView mQrCodeIv; 53 | private LinearLayout mChildLl; 54 | 55 | private Activity mContext; 56 | /** 57 | * 二维码中心图片地址 58 | */ 59 | private String mCenterImageUrl = "http://gss0.baidu.com/-fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/5366d0160924ab1861c9326236fae6cd7a890b8c.jpg"; 60 | /** 61 | * 二维码顶角颜色 62 | */ 63 | @ColorInt 64 | private int mVertexColor = Color.parseColor("#ff000000"); 65 | /** 66 | * 扫描二维码打开百度 67 | */ 68 | private String mUrl = "https://www.baidu.com"; 69 | /** 70 | * 分享弹窗 71 | */ 72 | private ShareDialog mShareDialog; 73 | 74 | @Override 75 | protected void onCreate(@Nullable Bundle savedInstanceState) { 76 | super.onCreate(savedInstanceState); 77 | 78 | mContext = this; 79 | 80 | setContentView(R.layout.activity_scroll_view); 81 | 82 | initView(); 83 | 84 | // 初始化状态栏 85 | initStatusBar(); 86 | 87 | // 初始化分享弹窗 88 | initShareDialog(); 89 | 90 | } 91 | 92 | private void initView() { 93 | mGameImageIv = (GlideImageView) findViewById(R.id.iv_game_image); 94 | mGameImageIv.setOnClickListener(this); 95 | mGameIconIv = (GlideImageView) findViewById(R.id.iv_game_icon); 96 | mGameIconIv.setOnClickListener(this); 97 | mGameNameTv = (TextView) findViewById(R.id.tv_game_name); 98 | mGameDescriptionTv = (TextView) findViewById(R.id.tv_game_description); 99 | mGameInfoRl = (RelativeLayout) findViewById(R.id.rl_game_info); 100 | mGameInfoRl.setOnClickListener(this); 101 | mScrollNsv = (NestedScrollView) findViewById(R.id.nsv_scroll); 102 | mQrCodeIv = (ImageView) findViewById(R.id.iv_qr_code); 103 | mQrCodeIv.setOnLongClickListener(this); 104 | mChildLl = (LinearLayout) findViewById(R.id.ll_child); 105 | 106 | // 背景图片 107 | Glide.with(this) 108 | .load(R.mipmap.pic_image) 109 | .apply(new RequestOptions().transform(new GlideBlurTransformation(this))) 110 | .into(new SimpleTarget() { 111 | @Override 112 | public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { 113 | mChildLl.setBackground(resource); 114 | } 115 | }); 116 | 117 | // 二维码中心图片 118 | Glide.with(mContext) 119 | .asBitmap() 120 | .load(mCenterImageUrl) 121 | .into(new SimpleTarget() { 122 | @Override 123 | public void onResourceReady(Bitmap resource, Transition transition) { 124 | mQrCodeIv.setImageBitmap(QRCode.createQRCodeWithLogo6(mUrl, 500, resource, mVertexColor)); 125 | } 126 | }); 127 | 128 | } 129 | 130 | private void initStatusBar() { 131 | // 隐藏状态栏 132 | ImmersionBar.with(this) 133 | .fitsSystemWindows(false) 134 | .statusBarDarkFont(false) 135 | .hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR) 136 | .init(); 137 | } 138 | 139 | private void initShareDialog() { 140 | // 分享弹窗 141 | mShareDialog = new ShareDialog(this) 142 | .setShareTitle("图片分享到") 143 | .setOnShareListener(new OnShareListener() { 144 | @Override 145 | public void onClickCloseBtn(ShareDialog shareDialog) { 146 | finish(); 147 | } 148 | 149 | @Override 150 | public void onTouchOutSide(ShareDialog shareDialog) { 151 | zoomIn(mGameInfoRl); 152 | } 153 | 154 | @Override 155 | public void onDismiss(ShareDialog shareDialog) { 156 | 157 | } 158 | 159 | @Override 160 | public void onClickSharePlatform(ShareDialog shareDialog, SharePlatformAdapter.ViewHolder holder, int sharePlatform) { 161 | // 长截图 162 | Bitmap bitmap = ScreenShotUtils.shotNestedScrollView(mScrollNsv); 163 | } 164 | }); 165 | mShareDialog.show(); 166 | } 167 | 168 | public static Bitmap drawableToBitmap(Drawable drawable) { 169 | if (drawable instanceof BitmapDrawable) { 170 | return ((BitmapDrawable) drawable).getBitmap(); 171 | } 172 | 173 | Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 174 | Canvas canvas = new Canvas(bitmap); 175 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 176 | drawable.draw(canvas); 177 | 178 | return bitmap; 179 | } 180 | 181 | @Override 182 | public void onClick(View v) { 183 | switch (v.getId()) { 184 | case R.id.iv_game_image: 185 | if (!mShareDialog.isShowing()) { 186 | mShareDialog.show(); 187 | } 188 | zoomOut(mGameInfoRl); 189 | break; 190 | case R.id.iv_game_icon: 191 | if (!mShareDialog.isShowing()) { 192 | mShareDialog.show(); 193 | } 194 | zoomOut(mGameInfoRl); 195 | break; 196 | case R.id.rl_game_info: 197 | if (!mShareDialog.isShowing()) { 198 | mShareDialog.show(); 199 | } 200 | zoomOut(mGameInfoRl); 201 | break; 202 | default: 203 | break; 204 | } 205 | } 206 | 207 | @Override 208 | public boolean onLongClick(View v) { 209 | // 打开浏览器 210 | Intent intent = new Intent(); 211 | intent.setAction(Intent.ACTION_VIEW); 212 | intent.setData(Uri.parse(mUrl)); 213 | mContext.startActivity(intent); 214 | return false; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/ui/WebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.ui; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.graphics.Bitmap; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.support.annotation.Nullable; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.webkit.WebChromeClient; 12 | import android.webkit.WebSettings; 13 | import android.webkit.WebView; 14 | import android.webkit.WebViewClient; 15 | 16 | import com.wkz.share.R; 17 | import com.wkz.share.immersionbar.BarHide; 18 | import com.wkz.share.immersionbar.ImmersionBar; 19 | import com.wkz.share.share.OnShareListener; 20 | import com.wkz.share.share.ShareDialog; 21 | import com.wkz.share.share.SharePlatformAdapter; 22 | import com.wkz.share.utils.ScreenShotUtils; 23 | 24 | /** 25 | * 网页视图的长截图分享界面 26 | * 27 | * @author Administrator 28 | * @date 2018/5/16 29 | */ 30 | @SuppressLint("SetJavaScriptEnabled") 31 | public class WebViewActivity extends MainActivity implements View.OnClickListener { 32 | 33 | private static final String TAG = WebViewActivity.class.getSimpleName(); 34 | private WebView mWvWeb; 35 | 36 | private Activity mContext; 37 | /** 38 | * 分享弹窗 39 | */ 40 | private ShareDialog mShareDialog; 41 | 42 | @Override 43 | protected void onCreate(@Nullable Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | mContext = this; 46 | // 在Android5.0及以上版本,Android对WebView进行了优化,为了减少内存使用和提高性能,使用WebView加载网页时只绘制显示部分。 47 | // 如果我们不做处理,仍然使用上述代码截图的话,就会出现只截到屏幕内显示的WebView内容,其它部分是空白的情况。 48 | // 这时候,我们通过调用WebView.enableSlowWholeDocumentDraw()方法可以关闭这种优化,但要注意的是,该方法需要在WebView实例被创建前就要调用,否则没有效果。 49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 50 | android.webkit.WebView.enableSlowWholeDocumentDraw(); 51 | } 52 | 53 | setContentView(R.layout.activity_web_view); 54 | initView(); 55 | initWebView(); 56 | // 初始化状态栏 57 | initStatusBar(); 58 | // 初始化分享弹窗 59 | initShareDialog(); 60 | } 61 | 62 | private void initView() { 63 | mWvWeb = (WebView) findViewById(R.id.wv_web); 64 | mWvWeb.setOnClickListener(this); 65 | } 66 | 67 | private void initWebView() { 68 | WebSettings webSettings = mWvWeb.getSettings(); 69 | //如果访问的页面中要与Javascript交互,则WebView必须设置支持Javascript 70 | webSettings.setJavaScriptEnabled(true); 71 | // 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量) 72 | // 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可 73 | 74 | //设置自适应屏幕,两者合用 75 | //将图片调整到适合WebView的大小 76 | webSettings.setUseWideViewPort(true); 77 | // 缩放至屏幕的大小 78 | webSettings.setLoadWithOverviewMode(true); 79 | 80 | //缩放操作 81 | //支持缩放,默认为true。是下面那个的前提。 82 | webSettings.setSupportZoom(true); 83 | //设置内置的缩放控件。若为false,则该WebView不可缩放 84 | webSettings.setBuiltInZoomControls(true); 85 | //隐藏原生的缩放控件 86 | webSettings.setDisplayZoomControls(false); 87 | 88 | //其他细节操作 89 | //关闭WebView中缓存 90 | webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 91 | //设置可以访问文件 92 | webSettings.setAllowFileAccess(true); 93 | //支持通过JS打开新窗口 94 | webSettings.setJavaScriptCanOpenWindowsAutomatically(true); 95 | //支持自动加载图片 96 | webSettings.setLoadsImagesAutomatically(true); 97 | //设置编码格式 98 | webSettings.setDefaultTextEncodingName("utf-8"); 99 | mWvWeb.setWebChromeClient(new WebChromeClient() { 100 | @Override 101 | public void onProgressChanged(WebView view, int newProgress) { 102 | super.onProgressChanged(view, newProgress); 103 | Log.d(TAG, "newProgress:" + newProgress); 104 | } 105 | 106 | @Override 107 | public void onReceivedTitle(WebView view, String title) { 108 | super.onReceivedTitle(view, title); 109 | Log.d(TAG, "标题:" + title); 110 | } 111 | }); 112 | mWvWeb.setWebViewClient(new WebViewClient() { 113 | @Override 114 | public void onPageStarted(WebView view, String url, Bitmap favicon) { 115 | super.onPageStarted(view, url, favicon); 116 | Log.d(TAG, "开始加载"); 117 | } 118 | 119 | @Override 120 | public void onPageFinished(WebView view, String url) { 121 | super.onPageFinished(view, url); 122 | Log.d(TAG, "加载结束"); 123 | } 124 | 125 | // 链接跳转都会走这个方法 126 | @Override 127 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 128 | Log.d(TAG, "Url:" + url); 129 | // 强制在当前 WebView 中加载 url 130 | view.loadUrl(url); 131 | return true; 132 | } 133 | }); 134 | mWvWeb.loadUrl("https://github.com/FPhoenixCorneaE?tab=repositories"); 135 | } 136 | 137 | private void initStatusBar() { 138 | // 隐藏状态栏 139 | ImmersionBar.with(this) 140 | .fitsSystemWindows(false) 141 | .statusBarDarkFont(false) 142 | .hideBar(BarHide.FLAG_HIDE_NAVIGATION_BAR) 143 | .init(); 144 | } 145 | 146 | private void initShareDialog() { 147 | // 分享弹窗 148 | mShareDialog = new ShareDialog(this) 149 | .setShareTitle("图片分享到") 150 | .setOnShareListener(new OnShareListener() { 151 | @Override 152 | public void onClickCloseBtn(ShareDialog shareDialog) { 153 | finish(); 154 | } 155 | 156 | @Override 157 | public void onTouchOutSide(ShareDialog shareDialog) { 158 | zoomIn(mWvWeb); 159 | } 160 | 161 | @Override 162 | public void onDismiss(ShareDialog shareDialog) { 163 | 164 | } 165 | 166 | @Override 167 | public void onClickSharePlatform(ShareDialog shareDialog, SharePlatformAdapter.ViewHolder holder, int sharePlatform) { 168 | // 长截图 169 | Bitmap bitmap = ScreenShotUtils.shotWebView(mWvWeb); 170 | } 171 | }); 172 | mShareDialog.show(); 173 | } 174 | 175 | @Override 176 | public void onClick(View v) { 177 | switch (v.getId()) { 178 | default: 179 | break; 180 | case R.id.wv_web: 181 | if (!mShareDialog.isShowing()) { 182 | mShareDialog.show(); 183 | } 184 | zoomOut(mWvWeb); 185 | break; 186 | } 187 | } 188 | 189 | @Override 190 | protected void onStop() { 191 | super.onStop(); 192 | mWvWeb.getSettings().setJavaScriptEnabled(false); 193 | } 194 | 195 | @Override 196 | protected void onResume() { 197 | super.onResume(); 198 | mWvWeb.getSettings().setJavaScriptEnabled(true); 199 | } 200 | 201 | @Override 202 | public void onBackPressed() { 203 | if (mWvWeb.canGoBack()) { 204 | mWvWeb.goBack(); 205 | return; 206 | } 207 | super.onBackPressed(); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/utils/AnimationUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.utils; 2 | 3 | import android.animation.AnimatorSet; 4 | import android.animation.ObjectAnimator; 5 | import android.animation.ValueAnimator; 6 | import android.view.View; 7 | import android.view.animation.OvershootInterpolator; 8 | 9 | /** 10 | * 动画工具类 11 | * 12 | * @author Administrator 13 | * @date 2019/5/15 14 | */ 15 | public class AnimationUtils { 16 | 17 | /** 18 | * OvershootInterpolator 向前甩一定值后再回到原来位置 19 | * 20 | * @param view targetView 21 | * @param translateValue The vertical position of this view relative to its top position,in pixels. 22 | * @param startDelay The amount of the delay, in milliseconds 23 | */ 24 | public static void startOvershootAnimation(final View view, final float translateValue, long startDelay) { 25 | view.setTranslationY(translateValue); 26 | view.setAlpha(0); 27 | 28 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0); 29 | valueAnimator.setDuration(1000); 30 | valueAnimator.setInterpolator(new OvershootInterpolator()); 31 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 32 | @Override 33 | public void onAnimationUpdate(ValueAnimator animation) { 34 | float value = (float) animation.getAnimatedValue(); 35 | view.setTranslationY(value * translateValue); 36 | view.setAlpha(1 - value); 37 | } 38 | }); 39 | valueAnimator.setStartDelay(startDelay); 40 | valueAnimator.start(); 41 | } 42 | 43 | /** 44 | * 缩小 45 | * 46 | * @param targetView 目标视图 47 | * @param beforeScaleX 缩小前X方向范围 48 | * @param beforeScaleY 缩小前Y方向范围 49 | * @param afterScaleX 缩小后X方向范围 50 | * @param afterScaleY 缩小后Y方向范围 51 | * @param duration 持续时间 52 | */ 53 | public static void zoomOut(View targetView, float beforeScaleX, float beforeScaleY, float afterScaleX, float afterScaleY, long duration) { 54 | AnimatorSet animSet = new AnimatorSet(); 55 | animSet.play(ObjectAnimator.ofFloat(targetView, "scaleX", beforeScaleX, afterScaleX)) 56 | .with(ObjectAnimator.ofFloat(targetView, "scaleY", beforeScaleY, afterScaleY)); 57 | animSet.setDuration(duration); 58 | animSet.start(); 59 | } 60 | 61 | /** 62 | * 放大 63 | * 64 | * @param targetView 目标视图 65 | * @param beforeScaleX 放大前X方向范围 66 | * @param beforeScaleY 放大前Y方向范围 67 | * @param afterScaleX 放大后X方向范围 68 | * @param afterScaleY 放大后Y方向范围 69 | * @param duration 持续时间 70 | */ 71 | public static void zoomIn(View targetView, float beforeScaleX, float beforeScaleY, float afterScaleX, float afterScaleY, long duration) { 72 | AnimatorSet animSet = new AnimatorSet(); 73 | animSet.play(ObjectAnimator.ofFloat(targetView, "scaleX", beforeScaleX, afterScaleX)) 74 | .with(ObjectAnimator.ofFloat(targetView, "scaleY", beforeScaleY, afterScaleY)); 75 | animSet.setDuration(duration); 76 | animSet.start(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/utils/BlurBitmapUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.utils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.os.Build; 7 | import android.renderscript.Allocation; 8 | import android.renderscript.Element; 9 | import android.renderscript.RenderScript; 10 | import android.renderscript.ScriptIntrinsicBlur; 11 | 12 | /** 13 | * 高斯模糊图片工具类 14 | * 15 | * @author Administrator 16 | * @date 2018/5/21 17 | */ 18 | public class BlurBitmapUtils { 19 | 20 | /** 21 | * @param context 上下文对象 22 | * @param image 需要模糊的图片 23 | * @param outWidth 输入出的宽度 24 | * @param outHeight 输出的高度 25 | * @return 模糊处理后的Bitmap 26 | */ 27 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 28 | public static Bitmap blurBitmap(Context context, Bitmap image, float blurRadius, int outWidth, int outHeight) { 29 | // 将缩小后的图片做为预渲染的图片 30 | Bitmap inputBitmap = Bitmap.createScaledBitmap(image, outWidth, outHeight, false); 31 | // 创建一张渲染后的输出图片 32 | Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap); 33 | // 创建RenderScript内核对象 34 | RenderScript rs = RenderScript.create(context); 35 | // 创建一个模糊效果的RenderScript的工具对象 36 | ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); 37 | // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间 38 | // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去 39 | Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap); 40 | Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); 41 | // 设置渲染的模糊程度, 25f是最大模糊度 42 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 43 | blurScript.setRadius(blurRadius); 44 | } 45 | // 设置blurScript对象的输入内存 46 | blurScript.setInput(tmpIn); 47 | // 将输出数据保存到输出内存中 48 | blurScript.forEach(tmpOut); 49 | // 将数据填充到Allocation中 50 | tmpOut.copyTo(outputBitmap); 51 | return outputBitmap; 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/utils/ScreenShotUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.utils; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.graphics.Bitmap; 8 | import android.graphics.Canvas; 9 | import android.graphics.Paint; 10 | import android.graphics.Picture; 11 | import android.graphics.Rect; 12 | import android.graphics.drawable.ColorDrawable; 13 | import android.graphics.drawable.Drawable; 14 | import android.net.Uri; 15 | import android.os.Build; 16 | import android.os.Environment; 17 | import android.support.v4.widget.NestedScrollView; 18 | import android.support.v7.widget.RecyclerView; 19 | import android.util.DisplayMetrics; 20 | import android.util.LruCache; 21 | import android.util.SparseIntArray; 22 | import android.view.View; 23 | import android.webkit.WebView; 24 | import android.widget.ListView; 25 | 26 | import com.nanchen.compresshelper.CompressHelper; 27 | import com.wkz.share.adapter.ListViewAdapter; 28 | import com.wkz.share.adapter.RecyclerViewAdapter; 29 | 30 | import java.io.File; 31 | import java.io.FileNotFoundException; 32 | import java.io.FileOutputStream; 33 | import java.io.IOException; 34 | import java.nio.charset.StandardCharsets; 35 | import java.security.MessageDigest; 36 | import java.util.Locale; 37 | 38 | /** 39 | * 长截图工具类 40 | * 41 | * @author Administrator 42 | * @date 2018/5/21 43 | */ 44 | 45 | public class ScreenShotUtils { 46 | 47 | private static final String FILE_DIR = "LongScreenShot"; 48 | 49 | /** 50 | * 截图Activity 51 | */ 52 | public static Bitmap shotActivity(Activity activity) { 53 | // View是你需要截图的View 54 | View view = activity.getWindow().getDecorView(); 55 | view.setDrawingCacheEnabled(true); 56 | view.buildDrawingCache(); 57 | 58 | Bitmap b1 = view.getDrawingCache(); 59 | 60 | // 获取状态栏高度 61 | Rect frame = new Rect(); 62 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); 63 | int statusBarHeight = frame.top; 64 | 65 | // 获取屏幕长和高 66 | DisplayMetrics displayMetrics = new DisplayMetrics(); 67 | activity.getWindow().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); 68 | int width = displayMetrics.widthPixels; 69 | int height = displayMetrics.heightPixels; 70 | // 去掉标题栏 71 | Bitmap bitmap = Bitmap.createBitmap(b1, 0, statusBarHeight, width, 72 | height - statusBarHeight); 73 | view.destroyDrawingCache(); 74 | 75 | // 保存图片 76 | savePicture(activity, bitmap); 77 | 78 | return bitmap; 79 | } 80 | 81 | /** 82 | * http://stackoverflow.com/questions/9791714/take-a-screenshot-of-a-whole-view 83 | */ 84 | @SuppressLint("ObsoleteSdkInt") 85 | public static Bitmap shotView(View v) { 86 | if (v == null) { 87 | return null; 88 | } 89 | v.setDrawingCacheEnabled(true); 90 | v.buildDrawingCache(); 91 | if (Build.VERSION.SDK_INT >= 11) { 92 | v.measure(View.MeasureSpec.makeMeasureSpec(v.getWidth(), View.MeasureSpec.EXACTLY), 93 | View.MeasureSpec.makeMeasureSpec(v.getHeight(), View.MeasureSpec.EXACTLY)); 94 | v.layout((int) v.getX(), 95 | (int) v.getY(), 96 | (int) v.getX() + v.getMeasuredWidth(), 97 | (int) v.getY() + v.getMeasuredHeight()); 98 | } else { 99 | v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), 100 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); 101 | v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); 102 | } 103 | Bitmap b = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, 104 | v.getMeasuredWidth(), v.getMeasuredHeight()); 105 | 106 | v.setDrawingCacheEnabled(false); 107 | v.destroyDrawingCache(); 108 | 109 | return b; 110 | } 111 | 112 | @SuppressLint("ObsoleteSdkInt") 113 | public static Bitmap shotViewWithoutBottom(View v) { 114 | if (v == null) { 115 | return null; 116 | } 117 | v.setDrawingCacheEnabled(true); 118 | v.buildDrawingCache(); 119 | if (Build.VERSION.SDK_INT >= 11) { 120 | v.measure(View.MeasureSpec.makeMeasureSpec(v.getWidth(), View.MeasureSpec.EXACTLY), 121 | View.MeasureSpec.makeMeasureSpec(v.getHeight(), View.MeasureSpec.EXACTLY)); 122 | v.layout((int) v.getX(), (int) v.getY(), 123 | (int) v.getX() + v.getMeasuredWidth(), 124 | (int) v.getY() + v.getMeasuredHeight()); 125 | } else { 126 | v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), 127 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); 128 | v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); 129 | } 130 | Bitmap b = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, 131 | v.getMeasuredWidth(), v.getMeasuredHeight() - v.getPaddingBottom()); 132 | 133 | v.setDrawingCacheEnabled(false); 134 | v.destroyDrawingCache(); 135 | 136 | return b; 137 | } 138 | 139 | /** 140 | * 截图View,只能截当前屏幕可见区域 141 | * 142 | * @param view 143 | * @return 144 | */ 145 | public static Bitmap shotViewInScreen(View view) { 146 | Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); 147 | Canvas canvas = new Canvas(bitmap); 148 | view.draw(canvas); 149 | 150 | // 保存图片 151 | savePicture(view.getContext(), bitmap); 152 | return bitmap; 153 | } 154 | 155 | /** 156 | * 截图NestedScrollView 157 | * http://blog.csdn.net/lyy1104/article/details/40048329 158 | **/ 159 | public static Bitmap shotNestedScrollView(NestedScrollView nestedScrollView) { 160 | if (nestedScrollView == null) { 161 | return null; 162 | } 163 | try { 164 | int h = 0; 165 | // 获取ScrollView实际高度 166 | for (int i = 0; i < nestedScrollView.getChildCount(); i++) { 167 | h += nestedScrollView.getChildAt(i).getHeight(); 168 | } 169 | // 创建对应大小的bitmap 170 | Bitmap bitmap = Bitmap.createBitmap(nestedScrollView.getWidth(), h, Bitmap.Config.ARGB_8888); 171 | final Canvas canvas = new Canvas(bitmap); 172 | nestedScrollView.draw(canvas); 173 | 174 | // 保存图片 175 | savePicture(nestedScrollView.getContext(), bitmap); 176 | 177 | return bitmap; 178 | } catch (OutOfMemoryError oom) { 179 | return null; 180 | } 181 | } 182 | 183 | /** 184 | * 截图NestedScrollView 185 | * get the bitmap of a NestedScrollView 186 | */ 187 | public static Bitmap shotNestedScrollView(Activity activity, NestedScrollView sv) { 188 | if (null == sv) { 189 | return null; 190 | } 191 | // enable something 192 | sv.setVerticalScrollBarEnabled(false); 193 | sv.setVerticalFadingEdgeEnabled(false); 194 | sv.scrollTo(0, 0); 195 | sv.setDrawingCacheEnabled(true); 196 | sv.buildDrawingCache(true); 197 | 198 | Bitmap b = shotViewWithoutBottom(sv); 199 | 200 | /* 201 | * vh : the height of the scrollView that is visible
202 | * th : the total height of the scrollView
203 | **/ 204 | int vh = sv.getHeight(); 205 | int th = sv.getChildAt(0).getHeight(); 206 | 207 | /* the total height is more than one screen */ 208 | Bitmap temp; 209 | if (th > vh) { 210 | int w = ScreenUtils.getScreenWidth(activity); 211 | int absVh = vh - sv.getPaddingTop() - sv.getPaddingBottom(); 212 | do { 213 | int restHeight = th - vh; 214 | if (restHeight <= absVh) { 215 | sv.scrollBy(0, restHeight); 216 | vh += restHeight; 217 | temp = shotView(sv); 218 | } else { 219 | sv.scrollBy(0, absVh); 220 | vh += absVh; 221 | temp = shotViewWithoutBottom(sv); 222 | } 223 | b = mergeBitmap(vh, w, temp, 0, sv.getScrollY(), b, 0, 0); 224 | } while (vh < th); 225 | } 226 | 227 | // restore something 228 | sv.scrollTo(0, 0); 229 | sv.setVerticalScrollBarEnabled(true); 230 | sv.setVerticalFadingEdgeEnabled(true); 231 | sv.setDrawingCacheEnabled(false); 232 | sv.destroyDrawingCache(); 233 | 234 | // 保存图片 235 | savePicture(sv.getContext(), b); 236 | 237 | return b; 238 | } 239 | 240 | private static Bitmap mergeBitmap(int newImageH, int newImageW, Bitmap background, 241 | float backX, float backY, Bitmap foreground, 242 | float foreX, float foreY) { 243 | if (null == background || null == foreground) { 244 | return null; 245 | } 246 | // create the new blank bitmap 创建一个新的和SRC长度宽度一样的位图 247 | Bitmap newBitmap = Bitmap.createBitmap(newImageW, newImageH, Bitmap.Config.RGB_565); 248 | Canvas cv = new Canvas(newBitmap); 249 | // draw bg into 250 | cv.drawBitmap(background, backX, backY, null); 251 | // draw fg into 252 | cv.drawBitmap(foreground, foreX, foreY, null); 253 | // save all clip 254 | cv.save(); 255 | // store 256 | cv.restore();// 存储 257 | 258 | return newBitmap; 259 | } 260 | 261 | /** 262 | * 截图ListView 263 | * http://stackoverflow.com/questions/12742343/android-get-screenshot-of-all-listview-items 264 | */ 265 | public static Bitmap shotListView(ListView listView) { 266 | if (listView == null) { 267 | return null; 268 | } 269 | 270 | try { 271 | ListViewAdapter adapter = (ListViewAdapter) listView.getAdapter(); 272 | Bitmap bigBitmap = null; 273 | if (adapter != null) { 274 | int size = adapter.getCount(); 275 | int height = 0; 276 | Paint paint = new Paint(); 277 | final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); 278 | 279 | // Use 1/8th of the available memory for this memory cache. 280 | final int cacheSize = maxMemory / 8; 281 | LruCache bitmapCache = new LruCache<>(cacheSize); 282 | SparseIntArray bitmapTop = new SparseIntArray(size); 283 | for (int i = 0; i < size; i++) { 284 | View childView = adapter.getConvertView(i, null, listView); 285 | adapter.onBindViewSync(i, childView, listView); 286 | childView.measure( 287 | View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.EXACTLY), 288 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) 289 | ); 290 | childView.layout( 291 | 0, 292 | 0, 293 | childView.getMeasuredWidth(), 294 | childView.getMeasuredHeight() 295 | ); 296 | childView.setDrawingCacheEnabled(true); 297 | childView.buildDrawingCache(); 298 | Bitmap drawingCache = childView.getDrawingCache(); 299 | if (drawingCache != null) { 300 | bitmapCache.put(String.valueOf(i), drawingCache); 301 | } 302 | 303 | bitmapTop.put(i, height); 304 | height += childView.getMeasuredHeight(); 305 | } 306 | 307 | bigBitmap = Bitmap.createBitmap(listView.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888); 308 | Canvas bigCanvas = new Canvas(bigBitmap); 309 | Drawable lBackground = listView.getBackground(); 310 | if (lBackground instanceof ColorDrawable) { 311 | ColorDrawable lColorDrawable = (ColorDrawable) lBackground; 312 | int lColor = lColorDrawable.getColor(); 313 | bigCanvas.drawColor(lColor); 314 | } 315 | 316 | for (int i = 0; i < size; i++) { 317 | Bitmap bitmap = bitmapCache.get(String.valueOf(i)); 318 | bigCanvas.drawBitmap(bitmap, 0, bitmapTop.get(i), paint); 319 | bitmap.recycle(); 320 | } 321 | } 322 | return bigBitmap; 323 | } catch (OutOfMemoryError oom) { 324 | return null; 325 | } 326 | } 327 | 328 | /** 329 | * 截图RecyclerView 330 | * https://gist.github.com/PrashamTrivedi/809d2541776c8c141d9a 331 | */ 332 | public static Bitmap shotRecyclerView(RecyclerView recyclerView) { 333 | if (recyclerView == null) { 334 | return null; 335 | } 336 | try { 337 | RecyclerViewAdapter adapter = (RecyclerViewAdapter) recyclerView.getAdapter(); 338 | Bitmap bigBitmap = null; 339 | if (adapter != null) { 340 | int size = adapter.getItemCount(); 341 | int height = 0; 342 | Paint paint = new Paint(); 343 | final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); 344 | 345 | // Use 1/8th of the available memory for this memory cache. 346 | final int cacheSize = maxMemory / 8; 347 | LruCache bitmapCache = new LruCache<>(cacheSize); 348 | SparseIntArray bitmapLeft = new SparseIntArray(size); 349 | SparseIntArray bitmapTop = new SparseIntArray(size); 350 | for (int i = 0; i < size; i++) { 351 | RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i)); 352 | adapter.onBindViewSync(holder, i); 353 | RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams(); 354 | holder.itemView.measure( 355 | View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth() - layoutParams.leftMargin - layoutParams.rightMargin, View.MeasureSpec.EXACTLY), 356 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) 357 | ); 358 | holder.itemView.layout( 359 | layoutParams.leftMargin, 360 | layoutParams.topMargin, 361 | holder.itemView.getMeasuredWidth() + layoutParams.leftMargin, 362 | holder.itemView.getMeasuredHeight() + layoutParams.topMargin 363 | ); 364 | holder.itemView.setDrawingCacheEnabled(true); 365 | holder.itemView.buildDrawingCache(); 366 | Bitmap drawingCache = holder.itemView.getDrawingCache(); 367 | if (drawingCache != null) { 368 | bitmapCache.put(String.valueOf(i), drawingCache); 369 | } 370 | 371 | height += layoutParams.topMargin; 372 | bitmapLeft.put(i, layoutParams.leftMargin); 373 | bitmapTop.put(i, height); 374 | height += holder.itemView.getMeasuredHeight() + layoutParams.bottomMargin; 375 | } 376 | 377 | bigBitmap = Bitmap.createBitmap(recyclerView.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888); 378 | Canvas bigCanvas = new Canvas(bigBitmap); 379 | Drawable lBackground = recyclerView.getBackground(); 380 | if (lBackground instanceof ColorDrawable) { 381 | ColorDrawable lColorDrawable = (ColorDrawable) lBackground; 382 | int lColor = lColorDrawable.getColor(); 383 | bigCanvas.drawColor(lColor); 384 | } 385 | 386 | for (int i = 0; i < size; i++) { 387 | Bitmap bitmap = bitmapCache.get(String.valueOf(i)); 388 | bigCanvas.drawBitmap(bitmap, bitmapLeft.get(i), bitmapTop.get(i), paint); 389 | bitmap.recycle(); 390 | } 391 | } 392 | return bigBitmap; 393 | } catch (OutOfMemoryError oom) { 394 | return null; 395 | } 396 | } 397 | 398 | /** 399 | * 截图WebView,没有使用X5内核 400 | * 401 | * @param webView 402 | * @return 403 | */ 404 | public static Bitmap shotWebView(WebView webView) { 405 | try { 406 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 407 | // Android5.0以上 408 | float scale = webView.getScale(); 409 | int width = webView.getWidth(); 410 | int height = (int) (webView.getContentHeight() * scale + 0.5); 411 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 412 | Canvas canvas = new Canvas(bitmap); 413 | webView.draw(canvas); 414 | 415 | // 保存图片 416 | savePicture(webView.getContext(), bitmap); 417 | return bitmap; 418 | } else { 419 | // Android5.0以下 420 | Picture picture = webView.capturePicture(); 421 | int width = picture.getWidth(); 422 | int height = picture.getHeight(); 423 | if (width > 0 && height > 0) { 424 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 425 | Canvas canvas = new Canvas(bitmap); 426 | picture.draw(canvas); 427 | 428 | // 保存图片 429 | savePicture(webView.getContext(), bitmap); 430 | return bitmap; 431 | } 432 | return null; 433 | } 434 | } catch (OutOfMemoryError oom) { 435 | return null; 436 | } 437 | } 438 | 439 | /** 440 | * 保存图片 441 | * 442 | * @param context 443 | * @param bitmap 444 | */ 445 | public static File savePicture(final Context context, Bitmap bitmap) { 446 | 447 | if (bitmap == null) { 448 | return null; 449 | } 450 | 451 | final File mFile; 452 | String path = Environment.getExternalStorageDirectory() + File.separator + FILE_DIR; 453 | final File dir = new File(path); 454 | if (!dir.exists()) { 455 | dir.mkdirs(); 456 | } 457 | 458 | //当前时间通过MD5命名图片 459 | String fileName = getMD5(System.currentTimeMillis() + "").toUpperCase(Locale.getDefault()); 460 | mFile = new File(dir, fileName); 461 | FileOutputStream out = null; 462 | try { 463 | out = new FileOutputStream(mFile.getAbsolutePath()); 464 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); 465 | out.flush(); 466 | } catch (FileNotFoundException e) { 467 | e.printStackTrace(); 468 | } catch (IOException e) { 469 | e.printStackTrace(); 470 | } finally { 471 | try { 472 | if (null != out) { 473 | out.close(); 474 | } 475 | if (!bitmap.isRecycled()) { 476 | bitmap.recycle(); 477 | } 478 | } catch (IOException e) { 479 | e.printStackTrace(); 480 | } 481 | } 482 | 483 | // 默认的压缩方法,多张图片只需要直接加入循环即可 484 | // File newFile = CompressHelper.getDefault(context.getApplicationContext()).compressToFile(mFile); 485 | 486 | File newFile = new CompressHelper.Builder(context.getApplicationContext()) 487 | // 默认最大宽度为720 488 | .setMaxWidth(10000) 489 | // 默认最大高度为960 490 | .setMaxHeight(50000) 491 | // 默认压缩质量为80 492 | .setQuality(80) 493 | // 设置你需要修改的文件名 494 | .setFileName(fileName) 495 | // 设置默认压缩为jpg格式 496 | .setCompressFormat(Bitmap.CompressFormat.JPEG) 497 | // .setDestinationDirectoryPath(Environment.getExternalStoragePublicDirectory( 498 | // Environment.DIRECTORY_PICTURES).getAbsolutePath()) 499 | .setDestinationDirectoryPath(dir.getAbsolutePath()) 500 | .build() 501 | .compressToFile(mFile); 502 | 503 | //更新本地图库 504 | Uri uri = Uri.fromFile(newFile); 505 | Intent mIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri); 506 | context.sendBroadcast(mIntent); 507 | 508 | return newFile; 509 | } 510 | 511 | /** 512 | * MD5加密 513 | * 514 | * @param info 515 | */ 516 | private static String getMD5(String info) { 517 | try { 518 | MessageDigest md5 = MessageDigest.getInstance("MD5"); 519 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 520 | md5.update(info.getBytes(StandardCharsets.UTF_8)); 521 | } else { 522 | md5.update(info.getBytes("UTF-8")); 523 | } 524 | byte[] encryption = md5.digest(); 525 | 526 | StringBuilder strBuilder = new StringBuilder(); 527 | for (int i = 0; i < encryption.length; i++) { 528 | if (Integer.toHexString(0xff & encryption[i]).length() == 1) { 529 | strBuilder.append("0").append(Integer.toHexString(0xff & encryption[i])); 530 | } else { 531 | strBuilder.append(Integer.toHexString(0xff & encryption[i])); 532 | } 533 | } 534 | 535 | return strBuilder.toString(); 536 | } catch (Exception e) { 537 | return ""; 538 | } 539 | } 540 | } 541 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.utils; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.WindowManager; 6 | 7 | import java.util.Objects; 8 | 9 | /** 10 | * 屏幕相关工具类 11 | * 12 | * @author Administrator 13 | * @date 2018/5/21 14 | */ 15 | public class ScreenUtils { 16 | 17 | private ScreenUtils() { 18 | /* cannot be instantiated */ 19 | throw new UnsupportedOperationException("cannot be instantiated"); 20 | } 21 | 22 | /** 23 | * 获得屏幕高度 24 | * 25 | * @param context 26 | * @return 27 | */ 28 | public static int getScreenWidth(Context context) { 29 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 30 | DisplayMetrics outMetrics = new DisplayMetrics(); 31 | Objects.requireNonNull(wm).getDefaultDisplay().getMetrics(outMetrics); 32 | return outMetrics.widthPixels; 33 | } 34 | 35 | /** 36 | * 获得屏幕宽度 37 | * 38 | * @param context 39 | * @return 40 | */ 41 | public static int getScreenHeight(Context context) { 42 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 43 | DisplayMetrics outMetrics = new DisplayMetrics(); 44 | Objects.requireNonNull(wm).getDefaultDisplay().getMetrics(outMetrics); 45 | return outMetrics.heightPixels; 46 | } 47 | 48 | /** 49 | * 获得状态栏的高度 50 | * 51 | * @param context 52 | * @return 53 | */ 54 | public static int getStatusHeight(Context context) { 55 | 56 | int statusHeight = -1; 57 | try { 58 | Class clazz = Class.forName("com.android.internal.R$dimen"); 59 | Object object = clazz.newInstance(); 60 | int height = Integer.parseInt(clazz.getField("status_bar_height") 61 | .get(object).toString()); 62 | statusHeight = context.getResources().getDimensionPixelSize(height); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | return statusHeight; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/utils/ViewUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.utils; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | 7 | /** 8 | * 视图工具类,设置某个view的padding/margin 9 | * 10 | * @author Administrator 11 | * @date 2018/3/28 12 | */ 13 | 14 | public class ViewUtils { 15 | 16 | /** 17 | * 设置某个View的padding 18 | * 19 | * @param view 需要设置的view 20 | * @param isDp 需要设置的数值是否为DP 21 | * @param left 左边距 22 | * @param top 上边距 23 | * @param right 右边距 24 | * @param bottom 下边距 25 | */ 26 | public static void setViewPadding(View view, boolean isDp, float left, float top, float right, float bottom) { 27 | if (view == null) { 28 | return; 29 | } 30 | 31 | int leftPx; 32 | int rightPx; 33 | int topPx; 34 | int bottomPx; 35 | 36 | if (isDp) { 37 | //根据DP与PX转换计算值 38 | leftPx = dp2px(view.getContext(), left); 39 | topPx = dp2px(view.getContext(), top); 40 | rightPx = dp2px(view.getContext(), right); 41 | bottomPx = dp2px(view.getContext(), bottom); 42 | } else { 43 | leftPx = (int) left; 44 | rightPx = (int) right; 45 | topPx = (int) top; 46 | bottomPx = (int) bottom; 47 | } 48 | 49 | //设置padding 50 | view.setPadding(leftPx, topPx, rightPx, bottomPx); 51 | } 52 | 53 | /** 54 | * 设置某个View的margin 55 | * 56 | * @param view 需要设置的view 57 | * @param isDp 需要设置的数值是否为DP 58 | * @param left 左边距 59 | * @param top 上边距 60 | * @param right 右边距 61 | * @param bottom 下边距 62 | */ 63 | public static void setViewMargin(View view, boolean isDp, float left, float top, float right, float bottom) { 64 | if (view == null) { 65 | return; 66 | } 67 | 68 | int leftPx; 69 | int rightPx; 70 | int topPx; 71 | int bottomPx; 72 | 73 | ViewGroup.LayoutParams params = view.getLayoutParams(); 74 | ViewGroup.MarginLayoutParams marginParams; 75 | //获取view的margin设置参数 76 | if (params instanceof ViewGroup.MarginLayoutParams) { 77 | marginParams = (ViewGroup.MarginLayoutParams) params; 78 | } else { 79 | //不存在时创建一个新的参数 80 | marginParams = new ViewGroup.MarginLayoutParams(params); 81 | } 82 | 83 | if (isDp) { 84 | //根据DP与PX转换计算值 85 | leftPx = dp2px(view.getContext(), left); 86 | topPx = dp2px(view.getContext(), top); 87 | rightPx = dp2px(view.getContext(), right); 88 | bottomPx = dp2px(view.getContext(), bottom); 89 | } else { 90 | leftPx = (int) left; 91 | rightPx = (int) right; 92 | topPx = (int) top; 93 | bottomPx = (int) bottom; 94 | } 95 | //设置margin 96 | marginParams.setMargins(leftPx, topPx, rightPx, bottomPx); 97 | view.setLayoutParams(marginParams); 98 | } 99 | 100 | /** 101 | * dp转px 102 | * 103 | * @param dpValue dp值 104 | * @return px值 105 | */ 106 | public static int dp2px(Context context, float dpValue) { 107 | final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density; 108 | return (int) (dpValue * scale + 0.5f); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/share/zxing/QRCode.java: -------------------------------------------------------------------------------- 1 | package com.wkz.share.zxing; 2 | 3 | /** 4 | * * _ _ 5 | * * __ _(_)_ _(_) __ _ _ __ 6 | * * \ \ / / \ \ / / |/ _` | '_ \ 7 | * * \ V /| |\ V /| | (_| | | | | 8 | * * \_/ |_| \_/ |_|\__,_|_| |_| 9 | *

10 | * Created by vivian on 2016/11/28. 11 | */ 12 | 13 | import android.graphics.Bitmap; 14 | import android.graphics.Matrix; 15 | import android.support.annotation.ColorInt; 16 | 17 | import com.google.zxing.BarcodeFormat; 18 | import com.google.zxing.EncodeHintType; 19 | import com.google.zxing.WriterException; 20 | import com.google.zxing.common.BitMatrix; 21 | import com.google.zxing.qrcode.QRCodeWriter; 22 | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 23 | 24 | import java.util.Hashtable; 25 | 26 | public class QRCode { 27 | private static int IMAGE_HALFWIDTH = 100; 28 | 29 | /** 30 | * 生成二维码,默认大小为500*500 31 | * 32 | * @param text 需要生成二维码的文字、网址等 33 | * @return bitmap 34 | */ 35 | public static Bitmap createQRCode(String text) { 36 | return createQRCode(text, 500); 37 | } 38 | 39 | /** 40 | * 生成二维码 41 | * 42 | * @param text 文字或网址 43 | * @param size 生成二维码的大小 44 | * @return bitmap 45 | */ 46 | public static Bitmap createQRCode(String text, int size) { 47 | try { 48 | Hashtable hints = new Hashtable<>(); 49 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 50 | //去掉白边 51 | hints.put(EncodeHintType.MARGIN, 0); 52 | 53 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, 54 | BarcodeFormat.QR_CODE, size, size, hints); 55 | int[] pixels = new int[size * size]; 56 | for (int y = 0; y < size; y++) { 57 | for (int x = 0; x < size; x++) { 58 | if (bitMatrix.get(x, y)) { 59 | pixels[y * size + x] = 0xff000000; 60 | } else { 61 | pixels[y * size + x] = 0xffffffff; 62 | } 63 | } 64 | } 65 | Bitmap bitmap = Bitmap.createBitmap(size, size, 66 | Bitmap.Config.ARGB_8888); 67 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size); 68 | return bitmap; 69 | } catch (WriterException e) { 70 | e.printStackTrace(); 71 | return null; 72 | } 73 | } 74 | 75 | /** 76 | * bitmap的颜色代替黑色的二维码 77 | * 78 | * @param text 79 | * @param size 80 | * @param mBitmap 81 | * @return 82 | */ 83 | public static Bitmap createQRCodeWithLogo2(String text, int size, Bitmap mBitmap) { 84 | try { 85 | IMAGE_HALFWIDTH = size / 10; 86 | Hashtable hints = new Hashtable<>(); 87 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 88 | //去掉白边 89 | hints.put(EncodeHintType.MARGIN, 0); 90 | 91 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 92 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, 93 | BarcodeFormat.QR_CODE, size, size, hints); 94 | 95 | //将logo图片按matrix设置的信息缩放 96 | mBitmap = Bitmap.createScaledBitmap(mBitmap, size, size, false); 97 | 98 | int[] pixels = new int[size * size]; 99 | int color = 0xffffffff; 100 | for (int y = 0; y < size; y++) { 101 | for (int x = 0; x < size; x++) { 102 | if (bitMatrix.get(x, y)) { 103 | pixels[y * size + x] = mBitmap.getPixel(x, y); 104 | } else { 105 | pixels[y * size + x] = color; 106 | } 107 | 108 | } 109 | } 110 | Bitmap bitmap = Bitmap.createBitmap(size, size, 111 | Bitmap.Config.ARGB_8888); 112 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size); 113 | return bitmap; 114 | } catch (WriterException e) { 115 | e.printStackTrace(); 116 | return null; 117 | } 118 | } 119 | 120 | /** 121 | * bitmap作为底色 122 | * 123 | * @param text 124 | * @param size 125 | * @param mBitmap 126 | * @return 127 | */ 128 | public static Bitmap createQRCodeWithLogo3(String text, int size, Bitmap mBitmap) { 129 | try { 130 | IMAGE_HALFWIDTH = size / 10; 131 | Hashtable hints = new Hashtable<>(); 132 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 133 | //去掉白边 134 | hints.put(EncodeHintType.MARGIN, 0); 135 | 136 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 137 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, 138 | BarcodeFormat.QR_CODE, size, size, hints); 139 | 140 | //将logo图片按matrix设置的信息缩放 141 | mBitmap = Bitmap.createScaledBitmap(mBitmap, size, size, false); 142 | 143 | int[] pixels = new int[size * size]; 144 | int color = 0xfff92736; 145 | for (int y = 0; y < size; y++) { 146 | for (int x = 0; x < size; x++) { 147 | if (bitMatrix.get(x, y)) { 148 | pixels[y * size + x] = color; 149 | } else { 150 | pixels[y * size + x] = mBitmap.getPixel(x, y) & 0x66ffffff; 151 | } 152 | } 153 | } 154 | Bitmap bitmap = Bitmap.createBitmap(size, size, 155 | Bitmap.Config.ARGB_8888); 156 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size); 157 | return bitmap; 158 | } catch (WriterException e) { 159 | e.printStackTrace(); 160 | return null; 161 | } 162 | } 163 | 164 | /** 165 | * 比方法2的颜色黑一些 166 | * 167 | * @param text 168 | * @param size 169 | * @param mBitmap 170 | * @return 171 | */ 172 | public static Bitmap createQRCodeWithLogo4(String text, int size, Bitmap mBitmap) { 173 | try { 174 | IMAGE_HALFWIDTH = size / 10; 175 | Hashtable hints = new Hashtable<>(); 176 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 177 | //去掉白边 178 | hints.put(EncodeHintType.MARGIN, 0); 179 | 180 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 181 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, 182 | BarcodeFormat.QR_CODE, size, size, hints); 183 | 184 | //将logo图片按matrix设置的信息缩放 185 | mBitmap = Bitmap.createScaledBitmap(mBitmap, size, size, false); 186 | 187 | int[] pixels = new int[size * size]; 188 | boolean flag = true; 189 | for (int y = 0; y < size; y++) { 190 | for (int x = 0; x < size; x++) { 191 | if (bitMatrix.get(x, y)) { 192 | if (flag) { 193 | flag = false; 194 | pixels[y * size + x] = 0xff000000; 195 | } else { 196 | pixels[y * size + x] = mBitmap.getPixel(x, y); 197 | flag = true; 198 | } 199 | } else { 200 | pixels[y * size + x] = 0xffffffff; 201 | } 202 | } 203 | } 204 | Bitmap bitmap = Bitmap.createBitmap(size, size, 205 | Bitmap.Config.ARGB_8888); 206 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size); 207 | return bitmap; 208 | } catch (WriterException e) { 209 | e.printStackTrace(); 210 | return null; 211 | } 212 | } 213 | 214 | /** 215 | * 生成带logo的二维码 216 | * 217 | * @param text 218 | * @param size 219 | * @param mBitmap 220 | * @return 221 | */ 222 | public static Bitmap createQRCodeWithLogo5(String text, int size, Bitmap mBitmap) { 223 | try { 224 | IMAGE_HALFWIDTH = size / 10; 225 | Hashtable hints = new Hashtable<>(); 226 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 227 | //去掉白边 228 | hints.put(EncodeHintType.MARGIN, 0); 229 | 230 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 231 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, 232 | BarcodeFormat.QR_CODE, size, size, hints); 233 | 234 | //将logo图片按matrix设置的信息缩放 235 | mBitmap = Bitmap.createScaledBitmap(mBitmap, size, size, false); 236 | 237 | //矩阵高度 238 | int width = bitMatrix.getWidth(); 239 | //矩阵宽度 240 | int height = bitMatrix.getHeight(); 241 | int halfW = width / 2; 242 | int halfH = height / 2; 243 | 244 | Matrix m = new Matrix(); 245 | float sx = (float) 2 * IMAGE_HALFWIDTH / mBitmap.getWidth(); 246 | float sy = (float) 2 * IMAGE_HALFWIDTH 247 | / mBitmap.getHeight(); 248 | m.setScale(sx, sy); 249 | //设置缩放信息 250 | //将logo图片按martix设置的信息缩放 251 | mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, 252 | mBitmap.getWidth(), mBitmap.getHeight(), m, false); 253 | 254 | int[] pixels = new int[size * size]; 255 | for (int y = 0; y < size; y++) { 256 | for (int x = 0; x < size; x++) { 257 | if (x > halfW - IMAGE_HALFWIDTH && x < halfW + IMAGE_HALFWIDTH 258 | && y > halfH - IMAGE_HALFWIDTH 259 | && y < halfH + IMAGE_HALFWIDTH) { 260 | //该位置用于存放图片信息 261 | //记录图片每个像素信息 262 | pixels[y * width + x] = mBitmap.getPixel(x - halfW 263 | + IMAGE_HALFWIDTH, y - halfH + IMAGE_HALFWIDTH); 264 | } else { 265 | if (bitMatrix.get(x, y)) { 266 | pixels[y * size + x] = 0xff37b19e; 267 | } else { 268 | pixels[y * size + x] = 0xffffffff; 269 | } 270 | } 271 | } 272 | } 273 | Bitmap bitmap = Bitmap.createBitmap(size, size, 274 | Bitmap.Config.ARGB_8888); 275 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size); 276 | return bitmap; 277 | } catch (WriterException e) { 278 | e.printStackTrace(); 279 | return null; 280 | } 281 | } 282 | 283 | /** 284 | * 修改三个顶角颜色的,带logo的二维码 285 | * 286 | * @param text 需要生成二维码的文字、网址等 287 | * @param size 生成二维码的大小 288 | * @param mBitmap 二维码中心图片 289 | * @return 290 | */ 291 | public static Bitmap createQRCodeWithLogo6(String text, int size, Bitmap mBitmap, @ColorInt int vertexColor) { 292 | try { 293 | IMAGE_HALFWIDTH = size / 5; 294 | Hashtable hints = new Hashtable<>(); 295 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 296 | //去掉白边 297 | hints.put(EncodeHintType.MARGIN, 0); 298 | /* 299 | * 设置容错级别,默认为ErrorCorrectionLevel.L 300 | * 因为中间加入logo所以建议你把容错级别调至H,否则可能会出现识别不了 301 | */ 302 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 303 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, 304 | BarcodeFormat.QR_CODE, size, size, hints); 305 | 306 | //将logo图片按matrix设置的信息缩放 307 | mBitmap = Bitmap.createScaledBitmap(mBitmap, size, size, false); 308 | 309 | //矩阵高度 310 | int width = bitMatrix.getWidth(); 311 | //矩阵宽度 312 | int height = bitMatrix.getHeight(); 313 | int halfW = width / 2; 314 | int halfH = height / 2; 315 | 316 | Matrix m = new Matrix(); 317 | float sx = (float) 2 * IMAGE_HALFWIDTH / mBitmap.getWidth(); 318 | float sy = (float) 2 * IMAGE_HALFWIDTH / mBitmap.getHeight(); 319 | m.setScale(sx, sy); 320 | //设置缩放信息 321 | //将logo图片按matrix设置的信息缩放 322 | mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, 323 | mBitmap.getWidth(), mBitmap.getHeight(), m, false); 324 | 325 | int[] pixels = new int[size * size]; 326 | for (int y = 0; y < size; y++) { 327 | for (int x = 0; x < size; x++) { 328 | if (x > halfW - IMAGE_HALFWIDTH && x < halfW + IMAGE_HALFWIDTH 329 | && y > halfH - IMAGE_HALFWIDTH 330 | && y < halfH + IMAGE_HALFWIDTH) { 331 | //该位置用于存放图片信息 332 | //记录图片每个像素信息 333 | pixels[y * width + x] = mBitmap.getPixel(x - halfW 334 | + IMAGE_HALFWIDTH, y - halfH + IMAGE_HALFWIDTH); 335 | } else { 336 | if (bitMatrix.get(x, y)) { 337 | //二维码像素颜色 338 | pixels[y * size + x] = 0xff111111; 339 | if (x < 115 && (y < 115 || y >= size - 115) || (y < 115 && x >= size - 115)) { 340 | //顶角颜色 341 | pixels[y * size + x] = vertexColor; 342 | } 343 | } else { 344 | //背景颜色 345 | pixels[y * size + x] = 0xffffffff; 346 | } 347 | } 348 | } 349 | } 350 | Bitmap bitmap = Bitmap.createBitmap(size, size, 351 | Bitmap.Config.ARGB_8888); 352 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size); 353 | return bitmap; 354 | } catch (WriterException e) { 355 | e.printStackTrace(); 356 | return null; 357 | } 358 | } 359 | 360 | } 361 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dialog_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dialog_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_0xffededed_cornersfive.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_0xffededed_cornersfive_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_0xffededed_cornersfive_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_0xffffffff_cornerstwo.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_list_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |