Commit 56702bb0 authored by Nature's avatar Nature

imagePicker

parents
MIT License
Copyright (c) 2017 giantss
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# cordova-plugin-ImagePicker
非常感谢[南尘](https://github.com/nanchen2251)[banchichen](https://github.com/banchichen) 提供的源码支持 多点star✨开源不容易,谢谢。扣扣群:273613165
一个支持多选,相册实现了拍照、预览、图片压缩等功能
## 功能
- 相册目录
- 多选图
- 相册内部拍照
- 预览选中的图片
- 图片压缩
## 安装要求
- Cordova Version >= 6.0.0
- Cordova-Android >= 6.0.0
- Cordova-iOS >= 4.0.0
## 安装
- `cordova plugin add https://github.com/giantss/cordova-plugin-ImagePicker.git`
注意:Android 项目先不要直接 build ,见 [android注意事项](#android注意事项)
## Android 视频演示
- [点击查看视频(mp4格式)](http://oqdxjvpc7.bkt.clouddn.com/111.mp4)<br>
- [点击查看视频(优酷)](http://v.youku.com/v_show/id_XMjg0NDg0NDIyMA==.html)
## iOS 视频演示
- [点击查看视频(mp4格式)](http://oqdxjvpc7.bkt.clouddn.com/ios1.mp4)<br>
- [点击查看视频(优酷)](http://v.youku.com/v_show/id_XMjg0NDg0NTU4OA==.html)
## 效果图
| Android | iOS |
|:---------------:|:------------:|
| <img src="./screenshots/android.png" width="270px" height="480"> | <img src="./screenshots/ios.jpg" width="270px" height="480"> |
## 使用方式
[一个粗糙的 cordova demo](https://github.com/giantss/ImagePickerDemo)
```javascript
ImagePicker.getPictures(function(result) {
alert(JSON.stringify(result));
}, function(err) {
alert(err);
}, {
maximumImagesCount : 9,
width : 1920,
height : 1440,
quality : 100
});
```
返回结果如下:
```
{
"images": [{
"path": "/data/user/0/com.pushsoft.im2/cache/ImagePicker/152783817455118.jpg",
"width": 720,
"height": 1280,
"size": 104871 // 文件体积(单位:字节)
}, {
"path": "/data/user/0/com.pushsoft.im2/cache/ImagePicker/152783817464525.jpg",
"width": 720,
"height": 1280,
"size": 109873
}],
"isOrigin": false // 是否原图
}
```
ionic 中使用本插件,需要声明: `declare let ImagePicker:any`
## 参数含义
| 配置参数 | 参数含义 |
|:------------------:|:-------------------------:|
| maximumImagesCount | 多选限制数量,默认为9 |
| width | 设置图片的width,默认为1920 |
| height | 设置图片的height,默认为1440 |
| quality | 图片质量 默认80 |
### 注意:
- 参数都是可选的,不传则使用默认值;
- 如果 width > 0 且 height > 0:Android 下压缩的图可能比原图大或者压缩率不高(比如原图4MB,压缩后也有2MB),可以 quality 设置低一些,比如 50;iOS 下会忽略 quality 参数;
- 如果 width < 0 或 height < 0:那么插件返回压缩图,压缩逻辑接近于微信,自动选取合适的分辨率和压缩品质,推荐使用这种方式。压缩库使用的是 [Luban](https://github.com/Curzibn/Luban)[Luban-iOS](https://github.com/GuoZhiQiang/Luban_iOS)。如果遇到压缩不清晰等问题,请到他们的项目上提 issues;
- 运行时,选图界面上有“原图”单选按钮,选上之后,返回的图片是未压缩的原图
## android注意事项
- 先移除安装过的旧版插件
- 如果 build 报下面的错
```
error: resource android:attr/dialogCornerRadius not found
error: resource android:attr/fontVariationSettings not found
error: resource android:attr/ttcIndex not found
```
请使用 [cordova-android-support-gradle-release](https://github.com/dpa99c/cordova-android-support-gradle-release) 这个插件统一项目中的 Android Support 库版本:
```
$ cordova plugin add cordova-android-support-gradle-release --variable ANDROID_SUPPORT_VERSION={required version}
```
其中`{required version}` 值为类似 `25.+`,`26.+`,`27.+` 这种。
- 如果你用的是 低版本 Cordova 和 Gradle,会报错不支持`implementation`
Cordova 7.1.0 及以下版本(对应Cordova-Android@6.3.0及以下版本),请将 `cordova-plugin-ImagePicker\src\android\imagepicker.gradle` 里面的 `implementation` 修改为 `compile`
因为低版本的 Cordova-Android 使用的是低版本的 Gradle, 不支持 `implementation`
- 如果还是 build 不成功
```
$ cordova platform rm android
```
```
$ cordova platform rm ios
```
移除旧的平台,然后重新 add
## 参考项目
### 多选图片项目
- [nanchen2251/ImagePicker](https://github.com/nanchen2251/ImagePicker) (Android)
- [jeasonlzy/ImagePicker](https://github.com/jeasonlzy/ImagePicker)
- [banchichen/TZImagePickerController](https://github.com/banchichen/TZImagePickerController) (iOS)
### 图片压缩库
- [nanchen2251/CompressHelper](https://github.com/nanchen2251/CompressHelper) (Android)
- [Curzibn/Luban](https://github.com/Curzibn/Luban) (Android)
- [GuoZhiQiang/Luban_iOS](https://github.com/GuoZhiQiang/Luban_iOS) (iOS)
## 更新说明
### v1.1.5
- (iOS)取消选图支持回调函数
### v1.1.4
- 返回值增加 图片宽高和文件体积
- (iOS)修复ios压缩某些图片模糊的问题
### v1.1.3
- (Android)修复低版本 Cordova-Android 和 Gradle 的情况下, build 出现 diamond 运算符异常的问题
- (Android)增加 `takePhoto` 方法,直接进入拍照
- (Android)增加失败回调,取消选图时会触发该回调
### v1.1.2
- (Android)修复部分手机图片预览页返回时,图片墙的小图全没了
### v1.1.1
- (Android)适配 Cordova@8、Cordova-Android@7
- (Android)provider_paths.xml 改名,FileProvider 改名,不会与其他插件冲突,也不需要手动复制到 cordova/platform/android/res/xml/ 下
- (Android)去除 styles.xml,改成在代码中设置样式,避免与其它插件也有这个同名的文件导致冲突
- (Android)Glide 图片库更新到最新,支持 Gif,性能大幅提升,应该没有图片墙显示不出预览图的问题了
- (Android)图片墙底栏上增加“原图”单选按钮
- (iOS)修正 iOS 勾选原图是,返回的图不是原图,以及压缩图比原图大的问题
- maximumImagesCount、width、height 等参数可选传递
- 如果 width < 0 且 height < 0,则自动选取合适的分辨率和压缩比进行压缩,接近于微信的压缩逻辑
- 修改成功回调的返回参数,原来返回图片路径数组 `['xxx', 'yyy']`,现在是 `{ images: ['xxx', 'yyy'], isOrigin: true/false }`
## License
[The MIT License (MIT)](http://www.opensource.org/licenses/mit-license.html)
-测试11111
# cordova-plugin-ImagePicker
Muito obrigado [South dust] (https://github.com/nanchen2251) e [banchichen] (https://github.com/banchichen) suporte de código-fonte para a estrela multi-estrelas O código aberto não é fácil, obrigado. Grupo de fivelas de botões: 240255635
Uma escolha múltipla de suporte, álbum de fotos para alcançar uma foto, visualização, (compressão de imagem do Android) e outras funções
## Funções
- Diretório do álbum
- Escolha mais fotos
- Foto interna do álbum de fotos
- Visualizar a imagem selecionada
- Compressão de imagem (Android)
## Requisitos de instalação
- Cordova Version> = 5.0
- Cordova-Android> = 4.0
- Cordova-iOS> = 6.0
## iOS Requisitos de requisitos
OS 6 ou posterior. Requer ARC disponível para iOS6 e acima. Ambiente ARC.
Quando a versão do sistema é iOS6 ou iOS7, Usando a AssetsLibrary. Quando a versão do sistema é iOS8 ou posterior, usando o PhotoKit. Se estiver executando no sistema iOS6 ou 7, use a biblioteca AssetsLibrary para obter recursos de fotos. Se estiver executando no iOS8 e acima, use a biblioteca PhotoKit para obter os recursos da foto.
## instalação
1. Linha de comando `plugin cordova adicionar https: // github.com / gigantes / cordova-plugin-ImagePicker.git`
2. Execute `cordova build --device` a partir da linha de comando
Nota: o projeto do Android primeiro não cria diretamente, veja [nota do Android] (# nota do Android).
# Demo de video do Android
[Clique para ver o vídeo (formato mp4)] (http://oqdxjvpc7.bkt.clouddn.com/111.mp4) <br>
[Clique para ver o vídeo (Youku)] (http://v.youku.com/v_show/id_XMjg0NDg0NDIyMA==.html)
## iOS Video Demo
[Clique para ver o vídeo (formato mp4)] (http://oqdxjvpc7.bkt.clouddn.com/ios1.mp4) <br>
[Clique para ver o vídeo (Youku)] (http://v.youku.com/v_show/id_XMjg0NDg0NTU4OA==.html)
## Renderizando
| Android | iOS |
|:---------------:|:------------:|
| <img src="../../res/android.png" width="270px" height="480"> | <img src="../../res/ios.jpg" width="270px" height="480"> |
## Use
### Nota: Os seguintes parâmetros passados na versão demo não podem ser aprovados, o programa padrão definirá os seguintes parâmetros de aprovação de demonstração, se você precisar passar parâmetros, deve passar juntos, 'não pode ser menos ', ou o erro do json será reportado .
```javascript
ImagePicker.getPictures(function(result) {
alert(result);
}, function(err) {
alert(err);
}, { maximumImagesCount : 9, width : 1920, height : 1440, quality : 100 });
```
## Explicação dos Parâmetros
Parâmetros de Configuração | Parâmetro Significado
-------------------------- | ----------------------------------------------------
maximumImagesCount | Multi-select o número de restrições, o padrão é 9
width | Definir a largura da imagem, o padrão é 1920
height | Define a altura da imagem, o padrão é 1440
quality | Qualidade da imagem padrão 100
## Android Notas
### faltando colors.xml, problema do arquivo provider_paths.xml
Ocorreu o seguinte erro
```
Error: /Users/guodapeng/Documents/Cordova/skateboard/platforms/android/gradlew: Command failed with exit code 1 Error output:
/Users/guodapeng/Documents/Cordova/skateboard/platforms/android/res/drawable/selector_back_press.xml:4:29-46: AAPT: No resource found that matches the given name (at 'drawable' with value '@color/theme_body').
```
Copie o arquivo colors.xml do diretório cordova-plugin-ImagePicker/src/android/res/values/ para platforms/android/res/values/
Ocorreu o seguinte erro
```
Error: /Users/guodapeng/Documents/Cordova/skateboard/platforms/android/gradlew: Command failed with exit code 1 Error output:
/Users/guodapeng/Documents/Cordova/skateboard/platforms/android/build/intermediates/manifests/full/debug/AndroidManifest.xml:66:35-54: AAPT: No resource found that matches the given name (at 'resource' with value '@xml/provider_paths').
```
Copie o arquivo provider_paths.xml do diretório cordova-plugin-ImagePicker/src/android/res/xml/ para platforms/android/res/xml/
### problema de seleção de mapa de recuperação flash plug-in
Ao instalar o plug-in de código QR, você pode contornar o problema de flashback alterando o suporte-v4 para a seguinte versão no arquivo patient-barcodescanner.gradle.
```
com.android.support:support-v4:25.3.1
```
## Licença
[A Licença MIT (MIT)] (http://www.opensource.org/licenses/mit-license.html)
# 测试插件的 Demo
注意 cordova.js 的引用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<title>cordova-plugin-ImagePicker Demo</title>
</head>
<body>
<button id="btn1">选择图片(最大1920*1440)</button>
<button id="btn2">选择图片(自动宽高)</button>
<div id="img_list"></div>
<script type="application/javascript">
var Demo = {
// Application Constructor
initialize: function () {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
// deviceready Event Handler
//
// Bind any cordova events here. Common events are:
// 'pause', 'resume', etc.
onDeviceReady: function () {
document.getElementById('btn1').onclick = Demo.getImage1;
document.getElementById('btn2').onclick = Demo.getImage2;
},
getImage1: function () {
ImagePicker.getPictures(function (result) {
Demo.showImage(result);
}, function (err) {
alert(err);
}, {
maximumImagesCount: 9,
width: 1920,
height: 1440,
quality: 100
});
},
getImage2: function () {
ImagePicker.getPictures(function (result) {
Demo.showImage(result);
}, function (err) {
alert(err);
}, {
maximumImagesCount: 9,
width: -1,
height: -1,
quality: 100
});
},
showImage: function (result) {
var list = result.images;
var imgContainer = document.getElementById("img_list");
imgContainer.innerHTML = "";
for (var i = 0; i < list.length; i++) {
var x = list[i];
(function (x) {
var div = document.createElement("div");
// 选图插件返回的宽高、体积
var node = document.createElement('p');
node.innerHTML = x.path + "<br>resultWidth: " + x.width + ", resultHeight: " +
x.height + ', size: ' + x.size;
div.appendChild(node);
// 创建对象
var img = new Image();
img.onload = function () {
// 实际宽高
var node = document.createElement('p');
node.innerHTML = "naturalWidth: " + img.naturalWidth + ", naturalHeight: " +
img.naturalHeight;
div.appendChild(node);
};
img.src = x.path + '?' + new Date().getTime();
img.width = 200;
div.appendChild(img);
imgContainer.appendChild(div);
})(x)
}
}
};
Demo.initialize();
</script>
<script type="text/javascript" src="cordova.js"></script>
</body>
</html>
\ No newline at end of file
#!/usr/bin/env node
var fs = require('fs');
var async = require('async');
var exec = require('child_process').exec;
var path = require('path');
var fileExists = function(filePath){
try {
return fs.statSync(filePath).isFile();
}
catch (err) {
return false;
}
};
var root = process.cwd();
var androidManifest;
var cordovaAndroid6Path = path.join(root, 'platforms/android/AndroidManifest.xml');
var cordovaAndroid7Path = path.join(root, 'platforms/android/app/src/main/AndroidManifest.xml');
if(fileExists(cordovaAndroid7Path)){
androidManifest = cordovaAndroid7Path;
} else if(fileExists(cordovaAndroid6Path)){
androidManifest = cordovaAndroid6Path;
} else{
throw "Can't find AndroidManifest.xml";
}
fs.readFile(androidManifest, 'utf8', function(err, data) {
if(err) throw err;
var lines = data.split('\n');
var searchingFor = '<application android:hardwareAccelerated="true"';
var newManifest = [];
var largeHeap = 'android:largeHeap="true"';
lines.forEach(function(line) {
if(line.trim().indexOf(searchingFor) != -1 && line.trim().indexOf(largeHeap) == -1) {
newManifest.push(line.replace(/\>$/, ' ') + largeHeap + ">");
} else {
newManifest.push(line);
}
});
fs.writeFileSync(androidManifest, newManifest.join('\n'));
});
{
"name": "cordova-plugin-imagepicker",
"version": "1.1.5",
"description": "Cordova ImagePicker Plugin",
"cordova": {
"id": "cordova-plugin-imagepicker",
"platforms": [
"ios",
"android"
]
},
"repository": {
"type": "git",
"url": "https://github.com/giantss/cordova-plugin-ImagePicker"
},
"keywords": [
"cordova",
"cordova-ios",
"cordova-android",
"ImagePicker"
],
"author": "giantss",
"license": "Apache-2.0",
"engines": {
"cordovaDependencies": {
"1.0.0": {
"cordova-android": ">6.0.0"
},
"2.0.0": {
"cordova": ">100"
}
}
},
"devDependencies": {
"jshint": "^0.1.8"
},
"dependencies": {
"async": "^2.6.0"
}
}
This diff is collapsed.
This diff is collapsed.
package com.giants.imagepicker.imageloader;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.giants.imagepicker.loader.ImageLoader;
import java.io.File;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class GlideImageLoader implements ImageLoader {
@Override
public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) {
Context appContext = activity.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
int defaultImage = resource.getIdentifier("default_image", "mipmap", pkgName);
RequestOptions options = new RequestOptions()
.placeholder(defaultImage) //设置占位图片
.error(defaultImage) //设置错误图片
.diskCacheStrategy(DiskCacheStrategy.ALL); //缓存全尺寸;
Glide.with(activity) //配置上下文
.load(Uri.fromFile(new File(path))) //设置图片路径(fix #8,文件名包含%符号 无法识别和显示)
.apply(options) //设置错误图片
.into(imageView);
}
@Override
public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) {
RequestOptions options = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL); //缓存全尺寸
Glide.with(activity) //配置上下文
.load(Uri.fromFile(new File(path))) //设置图片路径(fix #8,文件名包含%符号 无法识别和显示)
.apply(options)//缓存全尺寸
.into(imageView);
}
@Override
public void clearMemoryCache() {
}
}
\ No newline at end of file
package com.giants.imagepicker.imageloader;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import android.widget.ImageView;
import com.giants.imagepicker.loader.ImageLoader;
import com.squareup.picasso.MemoryPolicy;
import com.squareup.picasso.Picasso;
import java.io.File;
public class PicassoImageLoader implements ImageLoader {
@Override
public void displayImage(Activity activity, String path, ImageView imageView, int width, int height) {
Context appContext = activity.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
int defaultImage = resource.getIdentifier("default_image", "mipmap", pkgName);
Picasso.with(activity)//
.load(Uri.fromFile(new File(path)))//
.placeholder(defaultImage)//
.error(defaultImage)//
.resize(width, height)//
.centerInside()//
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)//
.into(imageView);
}
@Override
public void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height) {
Picasso.with(activity)//
.load(Uri.fromFile(new File(path)))//
.resize(width, height)//
.centerInside()//
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)//
.into(imageView);
}
@Override
public void clearMemoryCache() {
}
}
buildscript {
repositories {
mavenCentral()
jcenter()
}
}
repositories {
mavenCentral()
jcenter()
maven { url 'https://jitpack.io' }
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
compile 'com.android.support:recyclerview-v7:+'
compile 'com.android.support:exifinterface:+'
compile 'com.github.chrisbanes.photoview:library:1.+'
compile 'com.squareup.picasso:picasso:2.5.+'
compile 'com.github.bumptech.glide:glide:4.+'
compile 'com.github.nanchen2251:CompressHelper:1.0.+'
compile 'top.zibin:Luban:1.1.+'
}
android {
packagingOptions {
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
}
}
ext.postBuildExtras = {
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
allprojects {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
}
}
}
package com.giants.imagepicker;
import com.giants.imagepicker.bean.ImageItem;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 新的DataHolder,使用单例和弱引用解决崩溃问题
* <p>
* Author: nanchen
* Email: liushilin520@foxmail.com
* Date: 2017-03-20 07:01
*/
public class DataHolder {
public static final String DH_CURRENT_IMAGE_FOLDER_ITEMS = "dh_current_image_folder_items";
private static com.giants.imagepicker.DataHolder mInstance;
private Map<String, List<ImageItem>> data;
public static com.giants.imagepicker.DataHolder getInstance() {
if (mInstance == null){
synchronized (com.giants.imagepicker.DataHolder.class){
if (mInstance == null){
mInstance = new com.giants.imagepicker.DataHolder();
}
}
}
return mInstance;
}
private DataHolder() {
data = new HashMap<>();
}
public void save(String id, List<ImageItem> object) {
if (data != null){
data.put(id, object);
}
}
public Object retrieve(String id) {
if (data == null || mInstance == null){
throw new RuntimeException("你必须先初始化");
}
return data.get(id);
}
}
package com.giants.imagepicker;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import com.giants.imagepicker.bean.ImageFolder;
import com.giants.imagepicker.bean.ImageItem;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ImageDataSource implements LoaderManager.LoaderCallbacks<Cursor> {
private int res_all_images;
public static final int LOADER_ALL = 0; //加载所有图片
public static final int LOADER_CATEGORY = 1; //分类加载图片
private final String[] IMAGE_PROJECTION = { //查询图片需要的数据列
MediaStore.Images.Media.DISPLAY_NAME, //图片的显示名称 aaa.jpg
MediaStore.Images.Media.DATA, //图片的真实路径 /storage/emulated/0/pp/downloader/wallpaper/aaa.jpg
MediaStore.Images.Media.SIZE, //图片的大小,long型 132492
MediaStore.Images.Media.WIDTH, //图片的宽度,int型 1920
MediaStore.Images.Media.HEIGHT, //图片的高度,int型 1080
MediaStore.Images.Media.MIME_TYPE, //图片的类型 image/jpeg
MediaStore.Images.Media.DATE_ADDED}; //图片被添加的时间,long型 1450518608
private FragmentActivity activity;
private OnImagesLoadedListener loadedListener; //图片加载完成的回调接口
private ArrayList<ImageFolder> imageFolders = new ArrayList<>(); //所有的图片文件夹
private LoaderManager loaderManager=null;
/**
* @param activity 用于初始化LoaderManager,需要兼容到2.3
* @param path 指定扫描的文件夹目录,可以为 null,表示扫描所有图片
* @param loadedListener 图片加载完成的监听
*/
public ImageDataSource(FragmentActivity activity, String path, OnImagesLoadedListener loadedListener) {
this.activity = activity;
this.loadedListener = loadedListener;
Context appContext = activity.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
res_all_images = resource.getIdentifier("all_images", "string", pkgName);
loaderManager = activity.getSupportLoaderManager();
if (path == null) {
loaderManager.initLoader(LOADER_ALL, null, this);//加载所有的图片
} else {
//加载指定目录的图片
Bundle bundle = new Bundle();
bundle.putString("path", path);
loaderManager.initLoader(LOADER_CATEGORY, bundle, this);
}
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = null;
//扫描所有图片
if (id == LOADER_ALL)
cursorLoader = new CursorLoader(activity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[6] + " DESC");
//扫描某个图片文件夹
if (id == LOADER_CATEGORY)
cursorLoader = new CursorLoader(activity, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, IMAGE_PROJECTION[1] + " like '%" + args.getString("path") + "%'", null, IMAGE_PROJECTION[6] + " DESC");
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
imageFolders.clear();
if (data != null) {
ArrayList<ImageItem> allImages = new ArrayList<>(); //所有图片的集合,不分文件夹
while (data.moveToNext()) {
//查询数据
String imageName = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]));
String imagePath = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]));
File file = new File(imagePath);
if (!file.exists() || file.length() <= 0) {
continue;
}
long imageSize = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]));
int imageWidth = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[3]));
int imageHeight = data.getInt(data.getColumnIndexOrThrow(IMAGE_PROJECTION[4]));
String imageMimeType = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[5]));
long imageAddTime = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[6]));
//封装实体
ImageItem imageItem = new ImageItem();
imageItem.name = imageName;
imageItem.path = imagePath;
imageItem.size = imageSize;
imageItem.width = imageWidth;
imageItem.height = imageHeight;
imageItem.mimeType = imageMimeType;
imageItem.addTime = imageAddTime;
allImages.add(imageItem);
//根据父路径分类存放图片
File imageFile = new File(imagePath);
File imageParentFile = imageFile.getParentFile();
ImageFolder imageFolder = new ImageFolder();
imageFolder.name = imageParentFile.getName();
imageFolder.path = imageParentFile.getAbsolutePath();
if (!imageFolders.contains(imageFolder)) {
ArrayList<ImageItem> images = new ArrayList<>();
images.add(imageItem);
imageFolder.cover = imageItem;
imageFolder.images = images;
imageFolders.add(imageFolder);
} else {
imageFolders.get(imageFolders.indexOf(imageFolder)).images.add(imageItem);
}
}
//防止没有图片报异常
if (data.getCount() > 0 && allImages.size()>0) {
//构造所有图片的集合
ImageFolder allImagesFolder = new ImageFolder();
allImagesFolder.name = activity.getResources().getString(res_all_images);
allImagesFolder.path = "/";
allImagesFolder.cover = allImages.get(0);
allImagesFolder.images = allImages;
imageFolders.add(0, allImagesFolder); //确保第一条是所有图片
}
}
//回调接口,通知图片数据准备完成
ImagePicker.getInstance().setImageFolders(imageFolders);
loadedListener.onImagesLoaded(imageFolders);
// fix: 点击图片返回后图片没有了
if(loaderManager.getLoader(LOADER_ALL)!=null) {
loaderManager.destroyLoader(LOADER_ALL);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
System.out.println("--------");
}
/** 所有图片加载完成的回调接口 */
public interface OnImagesLoadedListener {
void onImagesLoaded(List<ImageFolder> imageFolders);
}
}
This diff is collapsed.
package com.giants.imagepicker;
import android.support.v4.content.FileProvider;
/**
* 自定义一个Provider,以免和引入的项目的provider冲突
*
* Author: nanchen
* Email: liushilin520@foxmail.com
* Date: 2017-03-17 16:10
*/
public class ImagePickerProvider extends FileProvider {
}
package com.giants.imagepicker.adapter;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.util.Utils;
import com.giants.imagepicker.bean.ImageFolder;
import java.util.ArrayList;
import java.util.List;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class ImageFolderAdapter extends BaseAdapter {
private ImagePicker imagePicker;
private Activity mActivity;
private int res_adapter_folder_list_item;
private int res_folder_image_count;
private int res_iv_cover;
private int res_tv_folder_name;
private int res_tv_image_count;
private int res_iv_folder_check;
private LayoutInflater mInflater;
private int mImageSize;
private List<ImageFolder> imageFolders;
private int lastSelected = 0;
public ImageFolderAdapter(Activity activity, List<ImageFolder> folders) {
mActivity = activity;
Context appContext = activity.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
res_adapter_folder_list_item = resource.getIdentifier("adapter_folder_list_item", "layout", pkgName);
res_folder_image_count = resource.getIdentifier("folder_image_count", "string", pkgName);
res_iv_cover = resource.getIdentifier("iv_cover", "id", pkgName);
res_tv_folder_name = resource.getIdentifier("tv_folder_name", "id", pkgName);
res_tv_image_count = resource.getIdentifier("tv_image_count", "id", pkgName);
res_iv_folder_check = resource.getIdentifier("iv_folder_check", "id", pkgName);
if (folders != null && folders.size() > 0) imageFolders = folders;
else imageFolders = new ArrayList<>();
imagePicker = ImagePicker.getInstance();
mImageSize = Utils.getImageItemWidth(mActivity);
mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void refreshData(List<ImageFolder> folders) {
if (folders != null && folders.size() > 0) imageFolders = folders;
else imageFolders.clear();
notifyDataSetChanged();
}
@Override
public int getCount() {
return imageFolders.size();
}
@Override
public ImageFolder getItem(int position) {
return imageFolders.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(res_adapter_folder_list_item, parent, false);
holder = new ViewHolder(convertView);
} else {
holder = (ViewHolder) convertView.getTag();
}
ImageFolder folder = getItem(position);
holder.folderName.setText(folder.name);
holder.imageCount.setText(mActivity.getString(res_folder_image_count, folder.images.size()));
imagePicker.getImageLoader().displayImage(mActivity, folder.cover.path, holder.cover, mImageSize, mImageSize);
if (lastSelected == position) {
holder.folderCheck.setVisibility(View.VISIBLE);
} else {
holder.folderCheck.setVisibility(View.INVISIBLE);
}
return convertView;
}
public void setSelectIndex(int i) {
if (lastSelected == i) {
return;
}
lastSelected = i;
notifyDataSetChanged();
}
public int getSelectIndex() {
return lastSelected;
}
private class ViewHolder {
ImageView cover;
TextView folderName;
TextView imageCount;
ImageView folderCheck;
public ViewHolder(View view) {
cover = (ImageView) view.findViewById(res_iv_cover);
folderName = (TextView) view.findViewById(res_tv_folder_name);
imageCount = (TextView) view.findViewById(res_tv_image_count);
folderCheck = (ImageView) view.findViewById(res_iv_folder_check);
view.setTag(this);
}
}
}
package com.giants.imagepicker.adapter;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.app.ActivityCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.Toast;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.util.Utils;
import com.giants.imagepicker.bean.ImageItem;
import com.giants.imagepicker.ui.ImageBaseActivity;
import com.giants.imagepicker.ui.ImageGridActivity;
import com.giants.imagepicker.view.SuperCheckBox;
import java.util.ArrayList;
/**
* ================================================
* 作 者:jeasongiants(廖子尧 Github地址:https://github.com/jeasongiants0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class ImageGridAdapter extends BaseAdapter {
private static final int ITEM_TYPE_CAMERA = 0; //第一个条目是相机
private static final int ITEM_TYPE_NORMAL = 1; //第一个条目不是相机
private ImagePicker imagePicker;
private Activity mActivity;
private int res_adapter_camera_item;
private int res_adapter_image_list_item;
private int res_iv_thumb;
private int res_mask;
private int res_cb_check;
private int res_select_limit;
private ArrayList<ImageItem> images = new ArrayList<>(); //当前需要显示的所有的图片数据
private ArrayList<ImageItem> mSelectedImages; //全局保存的已经选中的图片数据
private boolean isShowCamera; //是否显示拍照按钮
private int mImageSize; //每个条目的大小
private OnImageItemClickListener listener; //图片被点击的监听
public ImageGridAdapter(Activity activity, ArrayList<ImageItem> images) {
this.mActivity = activity;
Context appContext = activity.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
res_adapter_camera_item = resource.getIdentifier("adapter_camera_item", "layout", pkgName);
res_adapter_image_list_item = resource.getIdentifier("adapter_image_list_item", "layout", pkgName);
res_iv_thumb = resource.getIdentifier("iv_thumb", "id", pkgName);
res_mask = resource.getIdentifier("mask", "id", pkgName);
res_cb_check = resource.getIdentifier("cb_check", "id", pkgName);
res_select_limit = resource.getIdentifier("select_limit", "string", pkgName);
if (images != null) {
this.images = images;
}
mImageSize = Utils.getImageItemWidth(mActivity);
imagePicker = ImagePicker.getInstance();
isShowCamera = imagePicker.isShowCamera();
mSelectedImages = imagePicker.getSelectedImages();
}
public void refreshData(ArrayList<ImageItem> images) {
if (images != null) {
this.images = images;
notifyDataSetChanged();
}
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
if (isShowCamera) return position == 0 ? ITEM_TYPE_CAMERA : ITEM_TYPE_NORMAL;
return ITEM_TYPE_NORMAL;
}
@Override
public int getCount() {
return isShowCamera ? images.size() + 1 : images.size();
}
@Override
public ImageItem getItem(int position) {
if (isShowCamera) {
if (position == 0) return null;
return images.get(position - 1);
} else {
return images.get(position);
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
int itemViewType = getItemViewType(position);
if (itemViewType == ITEM_TYPE_CAMERA) {
convertView = LayoutInflater.from(mActivity).inflate(res_adapter_camera_item, parent, false);
convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mImageSize)); //让图片是个正方形
convertView.setTag(null);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!((ImageBaseActivity) mActivity).checkPermission(Manifest.permission.CAMERA)) {
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.CAMERA}, ImageGridActivity.REQUEST_PERMISSION_CAMERA);
} else {
imagePicker.takePicture(mActivity, ImagePicker.REQUEST_CODE_TAKE);
}
}
});
} else {
final ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(mActivity).inflate(res_adapter_image_list_item, parent, false);
convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mImageSize)); //让图片是个正方形
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final ImageItem imageItem = getItem(position);
holder.ivThumb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) listener.onImageItemClick(holder.rootView, imageItem, position);
}
});
holder.cbCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int selectLimit = imagePicker.getSelectLimit();
if (holder.cbCheck.isChecked() && mSelectedImages.size() >= selectLimit) {
Toast.makeText(mActivity.getApplicationContext(), mActivity.getString(res_select_limit, selectLimit), Toast.LENGTH_SHORT).show();
holder.cbCheck.setChecked(false);
holder.mask.setVisibility(View.GONE);
} else {
imagePicker.addSelectedImageItem(position, imageItem, holder.cbCheck.isChecked());
holder.mask.setVisibility(View.VISIBLE);
}
}
});
//根据是否多选,显示或隐藏checkbox
if (imagePicker.isMultiMode()) {
holder.cbCheck.setVisibility(View.VISIBLE);
boolean checked = mSelectedImages.contains(imageItem);
if (checked) {
holder.mask.setVisibility(View.VISIBLE);
holder.cbCheck.setChecked(true);
} else {
holder.mask.setVisibility(View.GONE);
holder.cbCheck.setChecked(false);
}
} else {
holder.cbCheck.setVisibility(View.GONE);
}
imagePicker.getImageLoader().displayImage(mActivity, imageItem.path, holder.ivThumb, mImageSize, mImageSize); //显示图片
}
return convertView;
}
private class ViewHolder {
public View rootView;
public ImageView ivThumb;
public View mask;
public SuperCheckBox cbCheck;
public ViewHolder(View view) {
rootView = view;
ivThumb = (ImageView) view.findViewById(res_iv_thumb);
mask = view.findViewById(res_mask);
cbCheck = (SuperCheckBox) view.findViewById(res_cb_check);
}
}
public void setOnImageItemClickListener(OnImageItemClickListener listener) {
this.listener = listener;
}
public interface OnImageItemClickListener {
void onImageItemClick(View view, ImageItem imageItem, int position);
}
}
\ No newline at end of file
package com.giants.imagepicker.adapter;
import android.app.Activity;
import android.support.v4.view.PagerAdapter;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.util.Utils;
import com.giants.imagepicker.bean.ImageItem;
import java.util.ArrayList;
import uk.co.senab.photoview.PhotoView;
import uk.co.senab.photoview.PhotoViewAttacher;
/**
* ================================================
* 作 者:jeasongiants(廖子尧 Github地址:https://github.com/jeasongiants0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class ImagePageAdapter extends PagerAdapter {
private int screenWidth;
private int screenHeight;
private ImagePicker imagePicker;
private ArrayList<ImageItem> images = new ArrayList<>();
private Activity mActivity;
public PhotoViewClickListener listener;
public ImagePageAdapter(Activity activity, ArrayList<ImageItem> images) {
this.mActivity = activity;
this.images = images;
DisplayMetrics dm = Utils.getScreenPix(activity);
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
imagePicker = ImagePicker.getInstance();
}
public void setData(ArrayList<ImageItem> images) {
this.images = images;
}
public void setPhotoViewClickListener(PhotoViewClickListener listener) {
this.listener = listener;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
PhotoView photoView = new PhotoView(mActivity);
ImageItem imageItem = images.get(position);
imagePicker.getImageLoader().displayImagePreview(mActivity, imageItem.path, photoView, screenWidth, screenHeight);
photoView.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
@Override
public void onPhotoTap(View view, float x, float y) {
if (listener != null) listener.OnPhotoTapListener(view, x, y);
}
});
container.addView(photoView);
return photoView;
}
@Override
public int getCount() {
return images.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public interface PhotoViewClickListener {
void OnPhotoTapListener(View view, float v, float v1);
}
}
package com.giants.imagepicker.adapter;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.support.v4.app.ActivityCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.Toast;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.bean.ImageItem;
import com.giants.imagepicker.ui.ImageBaseActivity;
import com.giants.imagepicker.ui.ImageGridActivity;
import com.giants.imagepicker.util.Utils;
import com.giants.imagepicker.view.SuperCheckBox;
import java.util.ArrayList;
/**
* 加载相册图片的RecyclerView适配器
*
* 用于替换原项目的GridView,使用局部刷新解决选中照片出现闪动问题
*
* 替换为RecyclerView后只是不再会导致全局刷新,
*
* 但还是会出现明显的重新加载图片,可能是picasso图片加载框架的问题
*
* Author: nanchen
* Email: liushilin520@foxmail.com
* Date: 2017-04-05 10:04
*/
public class ImageRecyclerAdapter extends RecyclerView.Adapter<ViewHolder> {
private static final int ITEM_TYPE_CAMERA = 0; //第一个条目是相机
private static final int ITEM_TYPE_NORMAL = 1; //第一个条目不是相机
private ImagePicker imagePicker;
private Activity mActivity;
private int res_adapter_camera_item;
private int res_adapter_image_list_item;
private int res_iv_thumb;
private int res_mask;
private int res_cb_check;
private int res_select_limit;
private ArrayList<ImageItem> images; //当前需要显示的所有的图片数据
private ArrayList<ImageItem> mSelectedImages; //全局保存的已经选中的图片数据
private boolean isShowCamera; //是否显示拍照按钮
private int mImageSize; //每个条目的大小
private LayoutInflater mInflater;
private OnImageItemClickListener listener; //图片被点击的监听
public void setOnImageItemClickListener(OnImageItemClickListener listener) {
this.listener = listener;
}
public interface OnImageItemClickListener {
void onImageItemClick(View view, ImageItem imageItem, int position);
}
public void refreshData(ArrayList<ImageItem> images) {
if (images == null || images.size() == 0) this.images = new ArrayList<>();
else this.images = images;
notifyDataSetChanged();
}
/**
* 构造方法
*/
public ImageRecyclerAdapter(Activity activity, ArrayList<ImageItem> images) {
this.mActivity = activity;
Context appContext = activity.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
res_adapter_camera_item = resource.getIdentifier("adapter_camera_item", "layout", pkgName);
res_adapter_image_list_item = resource.getIdentifier("adapter_image_list_item", "layout", pkgName);
res_iv_thumb = resource.getIdentifier("iv_thumb", "id", pkgName);
res_mask = resource.getIdentifier("mask", "id", pkgName);
res_cb_check = resource.getIdentifier("cb_check", "id", pkgName);
res_select_limit = resource.getIdentifier("select_limit", "string", pkgName);
if (images == null || images.size() == 0) this.images = new ArrayList<>();
else this.images = images;
mImageSize = Utils.getImageItemWidth(mActivity);
imagePicker = ImagePicker.getInstance();
isShowCamera = imagePicker.isShowCamera();
mSelectedImages = imagePicker.getSelectedImages();
mInflater = LayoutInflater.from(activity);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE_CAMERA){
return new CameraViewHolder(mInflater.inflate(res_adapter_camera_item,parent,false));
}
return new ImageViewHolder(mInflater.inflate(res_adapter_image_list_item,parent,false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (holder instanceof CameraViewHolder){
((CameraViewHolder)holder).bindCamera();
}else if (holder instanceof ImageViewHolder){
((ImageViewHolder)holder).bind(position);
}
}
@Override
public int getItemViewType(int position) {
if (isShowCamera) return position == 0 ? ITEM_TYPE_CAMERA : ITEM_TYPE_NORMAL;
return ITEM_TYPE_NORMAL;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return isShowCamera ? images.size() + 1 : images.size();
}
public ImageItem getItem(int position) {
if (isShowCamera) {
if (position == 0) return null;
return images.get(position - 1);
} else {
return images.get(position);
}
}
private class ImageViewHolder extends ViewHolder{
View rootView;
ImageView ivThumb;
View mask;
SuperCheckBox cbCheck;
ImageViewHolder(View itemView) {
super(itemView);
rootView = itemView;
ivThumb = (ImageView) itemView.findViewById(res_iv_thumb);
mask = itemView.findViewById(res_mask);
cbCheck = (SuperCheckBox) itemView.findViewById(res_cb_check);
itemView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mImageSize)); //让图片是个正方形
}
void bind(final int position){
final ImageItem imageItem = getItem(position);
ivThumb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) listener.onImageItemClick(rootView, imageItem, position);
}
});
cbCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int selectLimit = imagePicker.getSelectLimit();
if (cbCheck.isChecked() && mSelectedImages.size() >= selectLimit) {
Toast.makeText(mActivity.getApplicationContext(), mActivity.getString(res_select_limit, selectLimit), Toast.LENGTH_SHORT).show();
cbCheck.setChecked(false);
mask.setVisibility(View.GONE);
} else {
imagePicker.addSelectedImageItem(position, imageItem, cbCheck.isChecked());
mask.setVisibility(View.VISIBLE);
}
}
});
//根据是否多选,显示或隐藏checkbox
if (imagePicker.isMultiMode()) {
cbCheck.setVisibility(View.VISIBLE);
boolean checked = mSelectedImages.contains(imageItem);
if (checked) {
mask.setVisibility(View.VISIBLE);
cbCheck.setChecked(true);
} else {
mask.setVisibility(View.GONE);
cbCheck.setChecked(false);
}
} else {
cbCheck.setVisibility(View.GONE);
}
imagePicker.getImageLoader().displayImage(mActivity, imageItem.path, ivThumb, mImageSize, mImageSize); //显示图片
}
}
private class CameraViewHolder extends ViewHolder{
View mItemView;
CameraViewHolder(View itemView) {
super(itemView);
mItemView = itemView;
}
void bindCamera(){
mItemView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mImageSize)); //让图片是个正方形
mItemView.setTag(null);
mItemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!((ImageBaseActivity) mActivity).checkPermission(Manifest.permission.CAMERA)) {
ActivityCompat.requestPermissions(mActivity, new String[]{Manifest.permission.CAMERA}, ImageGridActivity.REQUEST_PERMISSION_CAMERA);
} else {
imagePicker.takePicture(mActivity, ImagePicker.REQUEST_CODE_TAKE);
}
}
});
}
}
}
package com.giants.imagepicker.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:图片文件夹
* 修订历史:
* ================================================
*/
public class ImageFolder implements Serializable {
public String name; //当前文件夹的名字
public String path; //当前文件夹的路径
public ImageItem cover; //当前文件夹需要要显示的缩略图,默认为最近的一次图片
public ArrayList<ImageItem> images; //当前文件夹下所有图片的集合
/** 只要文件夹的路径和名字相同,就认为是相同的文件夹 */
@Override
public boolean equals(Object o) {
try {
ImageFolder other = (ImageFolder) o;
return this.path.equalsIgnoreCase(other.path) && this.name.equalsIgnoreCase(other.name);
} catch (ClassCastException e) {
e.printStackTrace();
}
return super.equals(o);
}
}
package com.giants.imagepicker.bean;
import java.io.Serializable;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:图片信息
* 修订历史:
* ================================================
*/
public class ImageItem implements Serializable {
public String name; //图片的名字
public String path; //图片的路径
public long size; //图片的大小
public int width; //图片的宽度
public int height; //图片的高度
public String mimeType; //图片的类型
public long addTime; //图片的创建时间
/** 图片的路径和创建时间相同就认为是同一张图片 */
@Override
public boolean equals(Object o) {
if (o instanceof ImageItem) {
ImageItem item = (ImageItem) o;
return this.path.equalsIgnoreCase(item.path) && this.addTime == item.addTime;
}
return super.equals(o);
}
}
package com.giants.imagepicker.loader;
import android.app.Activity;
import android.widget.ImageView;
import java.io.Serializable;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:ImageLoader抽象类,外部需要实现这个类去加载图片, 尽力减少对第三方库的依赖,所以这么干了
* 修订历史:
* ================================================
*/
public interface ImageLoader extends Serializable {
void displayImage(Activity activity, String path, ImageView imageView, int width, int height);
void displayImagePreview(Activity activity, String path, ImageView imageView, int width, int height);
void clearMemoryCache();
}
package com.giants.imagepicker.ui;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.view.SystemBarTintManager;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class ImageBaseActivity extends AppCompatActivity {
protected SystemBarTintManager tintManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTranslucentStatus(true);
}
tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
Context appContext = getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
tintManager.setStatusBarTintResource(resource.getIdentifier("status_bar", "color", pkgName)); //设置上方状态栏的颜色
}
@TargetApi(19)
private void setTranslucentStatus(boolean on) {
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
public boolean checkPermission(@NonNull String permission) {
return ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
}
public void showToast(String toastText) {
Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_SHORT).show();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
ImagePicker.getInstance().restoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
ImagePicker.getInstance().saveInstanceState(outState);
}
}
package com.giants.imagepicker.ui;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.giants.imagepicker.util.BitmapUtil;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.bean.ImageItem;
import com.giants.imagepicker.view.CropImageView;
import java.io.File;
import java.util.ArrayList;
/**
* ================================================
* 作 者:jeasongiants(廖子尧 Github地址:https://github.com/jeasongiants0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class ImageCropActivity extends ImageBaseActivity implements View.OnClickListener, CropImageView.OnBitmapSaveCompleteListener {
private CropImageView mCropImageView;
private Bitmap mBitmap;
private boolean mIsSaveRectangle;
private int mOutputX;
private int mOutputY;
private ArrayList<ImageItem> mImageItems;
private ImagePicker imagePicker;
private int res_btn_ok;
private int res_btn_back;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context appContext = getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
res_btn_ok = resource.getIdentifier("btn_ok", "id", pkgName);
res_btn_back = resource.getIdentifier("btn_back", "id", pkgName);
setContentView(resource.getIdentifier("activity_image_crop", "layout", pkgName));
imagePicker = ImagePicker.getInstance();
//初始化View
findViewById(res_btn_back).setOnClickListener(this);
Button btn_ok = (Button) findViewById(res_btn_ok);
btn_ok.setText(getString(resource.getIdentifier("complete", "string", pkgName)));
btn_ok.setOnClickListener(this);
TextView tv_des = (TextView) findViewById(resource.getIdentifier("tv_des", "id", pkgName));
tv_des.setText(getString(resource.getIdentifier("photo_crop", "string", pkgName)));
mCropImageView = (CropImageView) findViewById(resource.getIdentifier("cv_crop_image", "id", pkgName));
mCropImageView.setOnBitmapSaveCompleteListener(this);
//获取需要的参数
mOutputX = imagePicker.getOutPutX();
mOutputY = imagePicker.getOutPutY();
mIsSaveRectangle = imagePicker.isSaveRectangle();
mImageItems = imagePicker.getSelectedImages();
String imagePath = mImageItems.get(0).path;
mCropImageView.setFocusStyle(imagePicker.getStyle());
mCropImageView.setFocusWidth(imagePicker.getFocusWidth());
mCropImageView.setFocusHeight(imagePicker.getFocusHeight());
//缩放图片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
options.inSampleSize = calculateInSampleSize(options, displayMetrics.widthPixels, displayMetrics.heightPixels);
options.inJustDecodeBounds = false;
mBitmap = BitmapFactory.decodeFile(imagePath, options);
// mCropImageView.setImageBitmap(mBitmap);
//设置默认旋转角度
mCropImageView.setImageBitmap(mCropImageView.rotate(mBitmap, BitmapUtil.getBitmapDegree(imagePath)));
// mCropImageView.setImageURI(Uri.fromFile(new File(imagePath)));
}
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = width / reqWidth;
} else {
inSampleSize = height / reqHeight;
}
}
return inSampleSize;
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == res_btn_back) {
setResult(RESULT_CANCELED);
finish();
} else if (id == res_btn_ok) {
mCropImageView.saveBitmapToFile(imagePicker.getCropCacheFolder(this), mOutputX, mOutputY, mIsSaveRectangle);
}
}
@Override
public void onBitmapSaveSuccess(File file) {
// Toast.makeText(ImageCropActivity.this, "裁剪成功:" + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
//裁剪后替换掉返回数据的内容,但是不要改变全局中的选中数据
mImageItems.remove(0);
ImageItem imageItem = new ImageItem();
imageItem.path = file.getAbsolutePath();
mImageItems.add(imageItem);
Intent intent = new Intent();
intent.putExtra(ImagePicker.EXTRA_RESULT_ITEMS, mImageItems);
setResult(ImagePicker.RESULT_CODE_ITEMS, intent); //单选不需要裁剪,返回数据
finish();
}
@Override
public void onBitmapSaveError(File file) {
}
@Override
protected void onDestroy() {
super.onDestroy();
mCropImageView.setOnBitmapSaveCompleteListener(null);
if (null != mBitmap && !mBitmap.isRecycled()) {
mBitmap.recycle();
mBitmap = null;
}
}
}
This diff is collapsed.
This diff is collapsed.
package com.giants.imagepicker.ui;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.util.Utils;
import com.giants.imagepicker.adapter.ImagePageAdapter;
import com.giants.imagepicker.DataHolder;
import com.giants.imagepicker.bean.ImageItem;
import com.giants.imagepicker.view.ViewPagerFixed;
import java.util.ArrayList;
/**
* ================================================
* 作 者:jeasongiants(廖子尧 Github地址:https://github.com/jeasongiants0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:图片预览的基类
* ================================================
*/
public abstract class ImagePreviewBaseActivity extends ImageBaseActivity {
protected ImagePicker imagePicker;
protected ArrayList<ImageItem> mImageItems; //跳转进ImagePreviewFragment的图片文件夹
protected int mCurrentPosition = 0; //跳转进ImagePreviewFragment时的序号,第几个图片
protected TextView mTitleCount; //显示当前图片的位置 例如 5/31
protected ArrayList<ImageItem> selectedImages; //所有已经选中的图片
protected View content;
protected View topBar;
protected ViewPagerFixed mViewPager;
protected ImagePageAdapter mAdapter;
protected boolean isFromItems = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context appContext = getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
setContentView(resource.getIdentifier("activity_image_preview", "layout", pkgName));
mCurrentPosition = getIntent().getIntExtra(ImagePicker.EXTRA_SELECTED_IMAGE_POSITION, 0);
isFromItems = getIntent().getBooleanExtra(ImagePicker.EXTRA_FROM_ITEMS,false);
if (isFromItems){
// 据说这样会导致大量图片崩溃
mImageItems = (ArrayList<ImageItem>) getIntent().getSerializableExtra(ImagePicker.EXTRA_IMAGE_ITEMS);
}else{
// 下面采用弱引用会导致预览崩溃
mImageItems = (ArrayList<ImageItem>) DataHolder.getInstance().retrieve(DataHolder.DH_CURRENT_IMAGE_FOLDER_ITEMS);
}
imagePicker = ImagePicker.getInstance();
selectedImages = imagePicker.getSelectedImages();
//初始化控件
content = findViewById(resource.getIdentifier("content", "id", pkgName));
//因为状态栏透明后,布局整体会上移,所以给头部加上状态栏的margin值,保证头部不会被覆盖
topBar = findViewById(resource.getIdentifier("top_bar", "id", pkgName));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) topBar.getLayoutParams();
params.topMargin = Utils.getStatusHeight(this);
topBar.setLayoutParams(params);
}
topBar.findViewById(resource.getIdentifier("btn_ok", "id", pkgName)).setVisibility(View.GONE);
topBar.findViewById(resource.getIdentifier("btn_back", "id", pkgName)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mTitleCount = (TextView) findViewById(resource.getIdentifier("tv_des", "id", pkgName));
mViewPager = (ViewPagerFixed) findViewById(resource.getIdentifier("viewpager", "id", pkgName));
mAdapter = new ImagePageAdapter(this, mImageItems);
mAdapter.setPhotoViewClickListener(new ImagePageAdapter.PhotoViewClickListener() {
@Override
public void OnPhotoTapListener(View view, float v, float v1) {
onImageSingleTap();
}
});
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(mCurrentPosition, false);
//初始化当前页面的状态
mTitleCount.setText(getString(resource.getIdentifier("preview_image_count", "string", pkgName), mCurrentPosition + 1, mImageItems.size()));
}
/** 单击时,隐藏头和尾 */
public abstract void onImageSingleTap();
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
ImagePicker.getInstance().restoreInstanceState(savedInstanceState);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
ImagePicker.getInstance().saveInstanceState(outState);
}
}
\ No newline at end of file
package com.giants.imagepicker.ui;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import com.giants.imagepicker.ImagePicker;
import com.giants.imagepicker.util.NavigationBarChangeListener;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧),ikkong (ikkong@163.com)
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:预览已经选择的图片,并可以删除, 感谢 ikkong 的提交
* ================================================
*/
public class ImagePreviewDelActivity extends ImagePreviewBaseActivity implements View.OnClickListener {
private int res_btn_del;
private int res_btn_back;
private int res_preview_image_count;
private int res_top_out;
private int res_top_in;
private int res_transparent;
private int res_status_bar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context appContext = getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
res_btn_del = resource.getIdentifier("btn_del", "id", pkgName);
res_btn_back = resource.getIdentifier("btn_back", "id", pkgName);
res_preview_image_count = resource.getIdentifier("preview_image_count", "string", pkgName);
res_top_out = resource.getIdentifier("top_out", "anim", pkgName);
res_top_in = resource.getIdentifier("top_in", "anim", pkgName);
res_transparent = resource.getIdentifier("transparent", "color", pkgName);
res_status_bar = resource.getIdentifier("status_bar", "color", pkgName);
ImageView mBtnDel = (ImageView) findViewById(res_btn_del);
mBtnDel.setOnClickListener(this);
mBtnDel.setVisibility(View.VISIBLE);
topBar.findViewById(res_btn_back).setOnClickListener(this);
mTitleCount.setText(getString(res_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
//滑动ViewPager的时候,根据外界的数据改变当前的选中状态和当前的图片的位置描述文本
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mCurrentPosition = position;
mTitleCount.setText(getString(res_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
}
});
NavigationBarChangeListener.with(this, NavigationBarChangeListener.ORIENTATION_HORIZONTAL)
.setListener(new NavigationBarChangeListener.OnSoftInputStateChangeListener() {
@Override
public void onNavigationBarShow(int orientation, int height) {
topBar.setPadding(0, 0, height, 0);
}
@Override
public void onNavigationBarHide(int orientation) {
topBar.setPadding(0, 0, 0, 0);
}
});
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == res_btn_del) {
showDeleteDialog();
} else if (id == res_btn_back) {
onBackPressed();
}
}
/** 是否删除此张图片 */
private void showDeleteDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("要删除这张照片吗?");
builder.setNegativeButton("取消", null);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//移除当前图片刷新界面
mImageItems.remove(mCurrentPosition);
if (mImageItems.size() > 0) {
mAdapter.setData(mImageItems);
mAdapter.notifyDataSetChanged();
mTitleCount.setText(getString(res_preview_image_count, mCurrentPosition + 1, mImageItems.size()));
} else {
onBackPressed();
}
}
});
builder.show();
}
@Override
public void onBackPressed() {
Intent intent = new Intent();
//带回最新数据
intent.putExtra(ImagePicker.EXTRA_IMAGE_ITEMS, mImageItems);
setResult(ImagePicker.RESULT_CODE_BACK, intent);
finish();
super.onBackPressed();
}
/** 单击时,隐藏头和尾 */
@Override
public void onImageSingleTap() {
if (topBar.getVisibility() == View.VISIBLE) {
topBar.setAnimation(AnimationUtils.loadAnimation(this, res_top_out));
topBar.setVisibility(View.GONE);
tintManager.setStatusBarTintResource(res_transparent);//通知栏所需颜色
//给最外层布局加上这个属性表示,Activity全屏显示,且状态栏被隐藏覆盖掉。
// if (Build.VERSION.SDK_INT >= 16) content.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
} else {
topBar.setAnimation(AnimationUtils.loadAnimation(this, res_top_in));
topBar.setVisibility(View.VISIBLE);
tintManager.setStatusBarTintResource(res_status_bar);//通知栏所需颜色
//Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住
// if (Build.VERSION.SDK_INT >= 16) content.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
}
\ No newline at end of file
package com.giants.imagepicker.util;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import java.io.File;
import java.io.IOException;
/**
*
* Bitmap工具类,主要是解决拍照旋转的适配
*
* Author: nanchen
* Email: liushilin520@foxmail.com
* Date: 2017-03-20 13:27
*/
public class BitmapUtil {
private BitmapUtil() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* 获取图片的旋转角度
*
* @param path 图片绝对路径
* @return 图片的旋转角度
*/
public static int getBitmapDegree(String path) {
int degree = 0;
try {
// 从指定路径下读取图片,并获取其EXIF信息
ExifInterface exifInterface = new ExifInterface(path);
// 获取图片的旋转信息
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
}
/**
* 将图片按照指定的角度进行旋转
*
* @param bitmap 需要旋转的图片
* @param degree 指定的旋转角度
* @return 旋转后的图片
*/
public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degree) {
// 根据旋转角度,生成旋转矩阵
Matrix matrix = new Matrix();
matrix.postRotate(degree);
// 将原始图片按照旋转矩阵进行旋转,并得到新的图片
Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
return newBitmap;
}
/**
* 获取我们需要的整理过旋转角度的Uri
* @param activity 上下文环境
* @param path 路径
* @return 正常的Uri
*/
public static Uri getRotatedUri(Activity activity, String path){
int degree = BitmapUtil.getBitmapDegree(path);
if (degree != 0){
Bitmap bitmap = BitmapFactory.decodeFile(path);
Bitmap newBitmap = BitmapUtil.rotateBitmapByDegree(bitmap,degree);
return Uri.parse(MediaStore.Images.Media.insertImage(activity.getContentResolver(),newBitmap,null,null));
}else{
return Uri.fromFile(new File(path));
}
}
/**
* 将图片按照指定的角度进行旋转
*
* @param path 需要旋转的图片的路径
* @param degree 指定的旋转角度
* @return 旋转后的图片
*/
public static Bitmap rotateBitmapByDegree(String path, int degree) {
Bitmap bitmap = BitmapFactory.decodeFile(path);
return rotateBitmapByDegree(bitmap,degree);
}
}
package com.giants.imagepicker.util;
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
/**
* Created by z-chu on 2017/9/4
* 用于监听导航栏的显示和隐藏,主要用于适配华为EMUI系统上虚拟导航栏可随时收起和展开的情况
*/
public class NavigationBarChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
/**
* 监听竖屏模式导航栏的显示和隐藏
*/
public static final int ORIENTATION_VERTICAL = 1;
/**
* 监听横屏模式导航栏的显示和隐藏
*/
public static final int ORIENTATION_HORIZONTAL = 2;
private Rect rect;
private View rootView;
private boolean isShowNavigationBar = false;
private int orientation;
private OnSoftInputStateChangeListener listener;
public NavigationBarChangeListener(View rootView, int orientation) {
this.rootView = rootView;
this.orientation = orientation;
rect = new Rect();
}
@Override
public void onGlobalLayout() {
rect.setEmpty();
rootView.getWindowVisibleDisplayFrame(rect);
int heightDiff = 0;
if (orientation == ORIENTATION_VERTICAL) {
heightDiff = rootView.getHeight() - (rect.bottom - rect.top);
} else if (orientation == ORIENTATION_HORIZONTAL) {
heightDiff = rootView.getWidth() - (rect.right - rect.left);
}
int navigationBarHeight = Utils.hasVirtualNavigationBar(rootView.getContext()) ?
Utils.getNavigationBarHeight(rootView.getContext()) : 0;
if (heightDiff >= navigationBarHeight && heightDiff < navigationBarHeight * 2) {
if (!isShowNavigationBar && listener != null) {
listener.onNavigationBarShow(orientation, heightDiff);
}
isShowNavigationBar = true;
} else {
if (isShowNavigationBar && listener != null) {
listener.onNavigationBarHide(orientation);
}
isShowNavigationBar = false;
}
}
public void setListener(OnSoftInputStateChangeListener listener) {
this.listener = listener;
}
public interface OnSoftInputStateChangeListener {
void onNavigationBarShow(int orientation, int height);
void onNavigationBarHide(int orientation);
}
public static NavigationBarChangeListener with(View rootView) {
return with(rootView, ORIENTATION_VERTICAL);
}
public static NavigationBarChangeListener with(Activity activity) {
return with(activity.findViewById(android.R.id.content), ORIENTATION_VERTICAL);
}
public static NavigationBarChangeListener with(View rootView, int orientation) {
NavigationBarChangeListener softInputHeightListener = new NavigationBarChangeListener(rootView, orientation);
rootView.getViewTreeObserver().addOnGlobalLayoutListener(softInputHeightListener);
return softInputHeightListener;
}
public static NavigationBarChangeListener with(Activity activity, int orientation) {
return with(activity.findViewById(android.R.id.content), orientation);
}
}
\ No newline at end of file
package com.giants.imagepicker.util;
import android.content.Context;
/**
* 用于解决provider冲突的util
*
* Author: nanchen
* Email: liushilin520@foxmail.com
* Date: 2017-03-22 18:55
*/
public class ProviderUtil {
public static String getFileProviderName(Context context){
return context.getPackageName()+".imagepicker.provider";
}
}
package com.giants.imagepicker.util;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import android.view.WindowManager;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:
* 修订历史:
* ================================================
*/
public class Utils {
/** 获得状态栏的高度 */
public static int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
/** 根据屏幕宽度与密度计算GridView显示的列数, 最少为三列,并获取Item宽度 */
public static int getImageItemWidth(Activity activity) {
int screenWidth = activity.getResources().getDisplayMetrics().widthPixels;
int densityDpi = activity.getResources().getDisplayMetrics().densityDpi;
int cols = screenWidth / densityDpi;
cols = cols < 3 ? 3 : cols;
int columnSpace = (int) (2 * activity.getResources().getDisplayMetrics().density);
return (screenWidth - columnSpace * (cols - 1)) / cols;
}
/**
* 判断SDCard是否可用
*/
public static boolean existSDCard() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
/**
* 获取手机大小(分辨率)
*/
public static DisplayMetrics getScreenPix(Activity activity) {
DisplayMetrics displaysMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displaysMetrics);
return displaysMetrics;
}
/** dp转px */
public static int dp2px(Context context, float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
}
/**
* 判断手机是否含有虚拟按键 99%
*/
public static boolean hasVirtualNavigationBar(Context context) {
boolean hasSoftwareKeys = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Display d = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
d.getRealMetrics(realDisplayMetrics);
int realHeight = realDisplayMetrics.heightPixels;
int realWidth = realDisplayMetrics.widthPixels;
DisplayMetrics displayMetrics = new DisplayMetrics();
d.getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
int displayWidth = displayMetrics.widthPixels;
hasSoftwareKeys = (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
hasSoftwareKeys = !hasMenuKey && !hasBackKey;
}
return hasSoftwareKeys;
}
/**
* 获取导航栏高度,有些没有虚拟导航栏的手机也能获取到,建议先判断是否有虚拟按键
*/
public static int getNavigationBarHeight(Context context) {
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
return resourceId > 0 ? context.getResources().getDimensionPixelSize(resourceId) : 0;
}
}
This diff is collapsed.
package com.giants.imagepicker.view;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
public class FolderPopUpWindow extends PopupWindow implements View.OnClickListener {
private ListView listView;
private OnItemClickListener onItemClickListener;
private final View masker;
private final View marginView;
private int marginPx;
public FolderPopUpWindow(Context context, BaseAdapter adapter) {
super(context);
Context appContext = context.getApplicationContext();
Resources resource = appContext.getResources();
String pkgName = appContext.getPackageName();
final View view = View.inflate(context, resource.getIdentifier("pop_folder", "layout", pkgName), null);
masker = view.findViewById(resource.getIdentifier("masker", "id", pkgName));
masker.setOnClickListener(this);
marginView = view.findViewById(resource.getIdentifier("margin", "id", pkgName));
marginView.setOnClickListener(this);
listView = (ListView) view.findViewById(resource.getIdentifier("listView", "id", pkgName));
listView.setAdapter(adapter);
setContentView(view);
setWidth(ViewGroup.LayoutParams.MATCH_PARENT); //如果不设置,就是 AnchorView 的宽度
setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
setFocusable(true);
setOutsideTouchable(true);
setBackgroundDrawable(new ColorDrawable(0));
setAnimationStyle(0);
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int maxHeight = view.getHeight() * 5 / 8;
int realHeight = listView.getHeight();
ViewGroup.LayoutParams listParams = listView.getLayoutParams();
listParams.height = realHeight > maxHeight ? maxHeight : realHeight;
listView.setLayoutParams(listParams);
LinearLayout.LayoutParams marginParams = (LinearLayout.LayoutParams) marginView.getLayoutParams();
marginParams.height = marginPx;
marginView.setLayoutParams(marginParams);
enterAnimator();
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
if (onItemClickListener != null) onItemClickListener.onItemClick(adapterView, view, position, l);
}
});
}
private void enterAnimator() {
ObjectAnimator alpha = ObjectAnimator.ofFloat(masker, "alpha", 0, 1);
ObjectAnimator translationY = ObjectAnimator.ofFloat(listView, "translationY", listView.getHeight(), 0);
AnimatorSet set = new AnimatorSet();
set.setDuration(400);
set.playTogether(alpha, translationY);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.start();
}
@Override
public void dismiss() {
exitAnimator();
}
private void exitAnimator() {
ObjectAnimator alpha = ObjectAnimator.ofFloat(masker, "alpha", 1, 0);
ObjectAnimator translationY = ObjectAnimator.ofFloat(listView, "translationY", 0, listView.getHeight());
AnimatorSet set = new AnimatorSet();
set.setDuration(300);
set.playTogether(alpha, translationY);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
listView.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
FolderPopUpWindow.super.dismiss();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
set.start();
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
public void setSelection(int selection) {
listView.setSelection(selection);
}
public void setMargin(int marginPx) {
this.marginPx = marginPx;
}
@Override
public void onClick(View v) {
dismiss();
}
public interface OnItemClickListener {
void onItemClick(AdapterView<?> adapterView, View view, int position, long l);
}
}
package com.giants.imagepicker.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.SoundEffectConstants;
import android.widget.CheckBox;
/**
* ================================================
* 作 者:jeasonlzy(廖子尧 Github地址:https://github.com/jeasonlzy0216
* 版 本:1.0
* 创建日期:2016/5/19
* 描 述:带声音的CheckBox
* 修订历史:
* ================================================
*/
public class SuperCheckBox extends android.support.v7.widget.AppCompatCheckBox {
public SuperCheckBox(Context context) {
super(context);
}
public SuperCheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SuperCheckBox(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean performClick() {
final boolean handled = super.performClick();
if (!handled) {
// View only makes a sound effect if the onClickListener was
// called, so we'll need to make one here instead.
playSoundEffect(SoundEffectConstants.CLICK);
}
return handled;
}
}
This diff is collapsed.
package com.giants.imagepicker.view;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class ViewPagerFixed extends ViewPager {
public ViewPagerFixed(Context context) {
super(context);
}
public ViewPagerFixed(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="600"
android:fromYDelta="-150%p"
android:toYDelta="0"/>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment