集成图库选图第三方库
@ -62,8 +62,11 @@ dependencies {
|
||||
implementation 'com.sackcentury:shinebutton:1.0.0'
|
||||
//工具类
|
||||
implementation 'com.blankj:utilcodex:1.28.4'
|
||||
//图库选择
|
||||
//implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.5.6'
|
||||
//测试用例
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation project(path: ':picture_library')
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<application
|
||||
android:name=".comm.SDUApp"
|
||||
@ -17,7 +18,7 @@
|
||||
android:maxAspectRatio="2.4"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:theme="@style/MyAppTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:replace="android:allowBackup">
|
||||
|
@ -6,4 +6,9 @@ public class Const {
|
||||
public static final String LOGIN_USER_NAME = "LoginUserName";
|
||||
public static final String LOGIN_NICKNAME = "LoginNickname";
|
||||
public static final String LOGIN_HEAD_URL = "LoginHeadUrl";
|
||||
|
||||
public static final int CAMERA_OK = 1;
|
||||
public static final int PIC_OK = 2;
|
||||
|
||||
|
||||
}
|
||||
|
236
app/src/main/java/com/yuxihan/sdu/comm/util/GlideEngine.java
Normal file
@ -0,0 +1,236 @@
|
||||
package com.yuxihan.sdu.comm.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.BitmapImageViewTarget;
|
||||
import com.bumptech.glide.request.target.ImageViewTarget;
|
||||
import com.luck.picture.lib.engine.ImageEngine;
|
||||
import com.luck.picture.lib.listener.OnImageCompleteCallback;
|
||||
import com.luck.picture.lib.tools.MediaUtils;
|
||||
import com.luck.picture.lib.widget.longimage.ImageSource;
|
||||
import com.luck.picture.lib.widget.longimage.ImageViewState;
|
||||
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
|
||||
import com.yuxihan.sdu.R;
|
||||
|
||||
/**
|
||||
* @describe:Glide加载引擎
|
||||
*/
|
||||
public class GlideEngine implements ImageEngine {
|
||||
|
||||
/**
|
||||
* 加载图片
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
@Override
|
||||
public void loadImage(@NonNull Context context, @NonNull String url,
|
||||
@NonNull ImageView imageView) {
|
||||
Glide.with(context)
|
||||
.load(url)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载网络图片适配长图方案
|
||||
* # 注意:此方法只有加载网络图片才会回调
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
* @param longImageView
|
||||
* @param callback 网络图片加载回调监听 {link after version 2.5.1 Please use the
|
||||
* #OnImageCompleteCallback#}
|
||||
*/
|
||||
@Override
|
||||
public void loadImage(@NonNull Context context, @NonNull String url,
|
||||
@NonNull ImageView imageView,
|
||||
SubsamplingScaleImageView longImageView,
|
||||
OnImageCompleteCallback callback) {
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.into(new ImageViewTarget<Bitmap>(imageView) {
|
||||
@Override
|
||||
public void onLoadStarted(@Nullable Drawable placeholder) {
|
||||
super.onLoadStarted(placeholder);
|
||||
if (callback != null) {
|
||||
callback.onShowLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(@Nullable Drawable errorDrawable) {
|
||||
super.onLoadFailed(errorDrawable);
|
||||
if (callback != null) {
|
||||
callback.onHideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setResource(@Nullable Bitmap resource) {
|
||||
if (callback != null) {
|
||||
callback.onHideLoading();
|
||||
}
|
||||
if (resource != null) {
|
||||
boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),
|
||||
resource.getHeight());
|
||||
longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);
|
||||
imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);
|
||||
if (eqLongImage) {
|
||||
// 加载长图
|
||||
longImageView.setQuickScaleEnabled(true);
|
||||
longImageView.setZoomEnabled(true);
|
||||
longImageView.setPanEnabled(true);
|
||||
longImageView.setDoubleTapZoomDuration(100);
|
||||
longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
|
||||
longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
|
||||
longImageView.setImage(ImageSource.bitmap(resource),
|
||||
new ImageViewState(0, new PointF(0, 0), 0));
|
||||
} else {
|
||||
// 普通图片
|
||||
imageView.setImageBitmap(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载网络图片适配长图方案
|
||||
* # 注意:此方法只有加载网络图片才会回调
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
* @param longImageView
|
||||
* @ 已废弃
|
||||
*/
|
||||
@Override
|
||||
public void loadImage(@NonNull Context context, @NonNull String url,
|
||||
@NonNull ImageView imageView,
|
||||
SubsamplingScaleImageView longImageView) {
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.into(new ImageViewTarget<Bitmap>(imageView) {
|
||||
@Override
|
||||
protected void setResource(@Nullable Bitmap resource) {
|
||||
if (resource != null) {
|
||||
boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),
|
||||
resource.getHeight());
|
||||
longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);
|
||||
imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);
|
||||
if (eqLongImage) {
|
||||
// 加载长图
|
||||
longImageView.setQuickScaleEnabled(true);
|
||||
longImageView.setZoomEnabled(true);
|
||||
longImageView.setPanEnabled(true);
|
||||
longImageView.setDoubleTapZoomDuration(100);
|
||||
longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
|
||||
longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
|
||||
longImageView.setImage(ImageSource.bitmap(resource),
|
||||
new ImageViewState(0, new PointF(0, 0), 0));
|
||||
} else {
|
||||
// 普通图片
|
||||
imageView.setImageBitmap(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载相册目录
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param url 图片路径
|
||||
* @param imageView 承载图片ImageView
|
||||
*/
|
||||
@Override
|
||||
public void loadFolderImage(@NonNull Context context, @NonNull String url,
|
||||
@NonNull ImageView imageView) {
|
||||
Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.override(180, 180)
|
||||
.centerCrop()
|
||||
.sizeMultiplier(0.5f)
|
||||
.apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder))
|
||||
.into(new BitmapImageViewTarget(imageView) {
|
||||
@Override
|
||||
protected void setResource(Bitmap resource) {
|
||||
RoundedBitmapDrawable circularBitmapDrawable =
|
||||
RoundedBitmapDrawableFactory.
|
||||
create(context.getResources(), resource);
|
||||
circularBitmapDrawable.setCornerRadius(8);
|
||||
imageView.setImageDrawable(circularBitmapDrawable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 加载gif
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param url 图片路径
|
||||
* @param imageView 承载图片ImageView
|
||||
*/
|
||||
@Override
|
||||
public void loadAsGifImage(@NonNull Context context, @NonNull String url,
|
||||
@NonNull ImageView imageView) {
|
||||
Glide.with(context)
|
||||
.asGif()
|
||||
.load(url)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载图片列表图片
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param url 图片路径
|
||||
* @param imageView 承载图片ImageView
|
||||
*/
|
||||
@Override
|
||||
public void loadGridImage(@NonNull Context context, @NonNull String url,
|
||||
@NonNull ImageView imageView) {
|
||||
Glide.with(context)
|
||||
.load(url)
|
||||
.override(200, 200)
|
||||
.centerCrop()
|
||||
.apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder))
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
|
||||
private GlideEngine() {
|
||||
}
|
||||
|
||||
private static GlideEngine instance;
|
||||
|
||||
public static GlideEngine createGlideEngine() {
|
||||
if (null == instance) {
|
||||
synchronized (GlideEngine.class) {
|
||||
if (null == instance) {
|
||||
instance = new GlideEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
@ -1,17 +1,108 @@
|
||||
package com.yuxihan.sdu.ui.info;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.luck.picture.lib.PictureSelector;
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.yuxihan.sdu.R;
|
||||
import com.yuxihan.sdu.comm.BaseActivity;
|
||||
import com.yuxihan.sdu.comm.Const;
|
||||
import com.yuxihan.sdu.comm.util.GlideEngine;
|
||||
import com.yuxihan.sdu.comm.widget.ActionSheetDialog;
|
||||
|
||||
public class InfoEditActivity extends BaseActivity {
|
||||
|
||||
private Context mContext = InfoEditActivity.this;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_info_edit);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
String[] fileFrom = new String[]{"相机", "图库"};
|
||||
//头像控件点击事件
|
||||
findViewById(R.id.rl_head_icon).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
ActionSheetDialog actionSheetDialog = new ActionSheetDialog(
|
||||
mContext).builder().setCancelable(false)
|
||||
.setCanceledOnTouchOutside(true);
|
||||
for (int i = 0; i < fileFrom.length; i++) {
|
||||
actionSheetDialog.addSheetItem(fileFrom[i],
|
||||
ActionSheetDialog.SheetItemColor.Blue,
|
||||
new ActionSheetDialog.OnSheetItemClickListener() {
|
||||
@Override
|
||||
public void onClick(int which) {
|
||||
getFile(which);
|
||||
}
|
||||
});
|
||||
}
|
||||
actionSheetDialog.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//处理点击事件
|
||||
private void getFile(int index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
takePic();
|
||||
break;
|
||||
case 2:
|
||||
gallery();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//去图库选择
|
||||
private void gallery() {
|
||||
PictureSelector.create(this)
|
||||
.openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()
|
||||
// 、视频.ofVideo()、音频.ofAudio()
|
||||
.theme(R.style.picture_white_style)// 主题样式设置 具体参考 values/styles 用法:R.style
|
||||
// .picture_white_style
|
||||
.maxSelectNum(1)// 最大图片选择数量
|
||||
.minSelectNum(1)// 最小选择数量
|
||||
.isCamera(false)// 是否显示拍照按钮
|
||||
.imageSpanCount(5)// 每行显示个数
|
||||
.compress(false)// 是否压缩 true or false
|
||||
.maxSelectNum(1)// 最大图片选择数量
|
||||
.isZoomAnim(true)// 图片列表点击 缩放效果 默认true
|
||||
.synOrAsy(true)//同步true或异步false 压缩 默认同步
|
||||
.glideOverride(120, 120)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
|
||||
//.selectionMedia(picList)// 是否传入已选图片
|
||||
.minimumCompressSize(100)// 小于100kb的图片不压缩
|
||||
.loadImageEngine(GlideEngine.createGlideEngine())
|
||||
.forResult(Const.PIC_OK);//结果回调onActivityResult code
|
||||
}
|
||||
|
||||
|
||||
//拍照
|
||||
private void takePic() {
|
||||
//单独拍照
|
||||
PictureSelector.create(this)
|
||||
.openCamera(PictureMimeType.ofImage())
|
||||
.theme(R.style.picture_white_style)// 主题样式设置 具体参考 values/styles
|
||||
.minSelectNum(1)// 最小选择数量
|
||||
.compress(false)
|
||||
.selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选
|
||||
.isCamera(false)// 是否显示拍照按钮
|
||||
.glideOverride(120, 120)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
|
||||
//.selectionMedia(picList)// 是否传入已选图片
|
||||
.imageSpanCount(5)// 每行显示个数
|
||||
.maxSelectNum(1)// 最大图片选择数量
|
||||
.isZoomAnim(true)// 图片列表点击 缩放效果 默认true
|
||||
.synOrAsy(true)//同步true或异步false 压缩 默认同步
|
||||
.minimumCompressSize(100)// 小于100kb的图片不压缩
|
||||
.forResult(Const.CAMERA_OK);
|
||||
}
|
||||
}
|
||||
|
7
app/src/main/res/color/picture_list_sina_text_color.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/app_color_e0ff6100" android:state_selected="true" />
|
||||
<item android:color="@color/app_color_e0ff6100" android:state_checked="true" />
|
||||
<item android:color="@color/app_color_9b" />
|
||||
|
||||
</selector>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/app_color_e0ff6100" android:state_selected="true" />
|
||||
<item android:color="@color/app_color_e0ff6100" android:state_checked="true" />
|
||||
<item android:color="@color/app_color_9b" />
|
||||
|
||||
</selector>
|
5
app/src/main/res/drawable/checkbox_num_selector.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/num_oval_blue_def" android:state_selected="false"></item>
|
||||
<item android:drawable="@drawable/num_oval_blue" android:state_selected="true"></item>
|
||||
</selector>
|
5
app/src/main/res/drawable/checkbox_selector.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/picture_icon_def" android:state_selected="false"></item>
|
||||
<item android:drawable="@drawable/picture_icon_sel" android:state_selected="true"></item>
|
||||
</selector>
|
5
app/src/main/res/drawable/custom_qq_cb.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/message_oval_white" android:state_selected="false"></item>
|
||||
<item android:drawable="@drawable/message_oval_orange" android:state_selected="true"></item>
|
||||
</selector>
|
BIN
app/src/main/res/drawable/ic_add_image.png
Normal file
After Width: | Height: | Size: 897 B |
BIN
app/src/main/res/drawable/ic_back_arrow.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
app/src/main/res/drawable/ic_delete_menu.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable/ic_let_go_delete.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable/ic_minus.png
Normal file
After Width: | Height: | Size: 159 B |
BIN
app/src/main/res/drawable/ic_orange_arrow_down.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable/ic_orange_arrow_up.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable/ic_play.png
Normal file
After Width: | Height: | Size: 498 B |
BIN
app/src/main/res/drawable/ic_plus.png
Normal file
After Width: | Height: | Size: 212 B |
13
app/src/main/res/drawable/message_oval_orange.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
android:useLevel="false">
|
||||
|
||||
<solid android:color="@color/app_color_c51" />
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="@color/app_color_white" />
|
||||
<size
|
||||
android:width="18dp"
|
||||
android:height="18dp" />
|
||||
</shape>
|
13
app/src/main/res/drawable/message_oval_white.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
android:useLevel="false">
|
||||
|
||||
<solid android:color="@color/app_color_transparent" />
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="@color/app_color_white" />
|
||||
<size
|
||||
android:width="18dp"
|
||||
android:height="18dp" />
|
||||
</shape>
|
13
app/src/main/res/drawable/num_oval_blue.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
android:useLevel="false">
|
||||
|
||||
<solid android:color="@color/app_color_blue" />
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="@color/app_color_white" />
|
||||
<size
|
||||
android:width="18dp"
|
||||
android:height="18dp" />
|
||||
</shape>
|
13
app/src/main/res/drawable/num_oval_blue_def.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
android:useLevel="false">
|
||||
|
||||
<solid android:color="@color/app_color_transparent" />
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="@color/app_color_white" />
|
||||
<size
|
||||
android:width="18dp"
|
||||
android:height="18dp" />
|
||||
</shape>
|
13
app/src/main/res/drawable/num_oval_orange.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval"
|
||||
android:useLevel="false">
|
||||
|
||||
<solid android:color="@color/app_color_e0ff6100" />
|
||||
<stroke
|
||||
android:width="0.5dp"
|
||||
android:color="@color/app_color_white" />
|
||||
<size
|
||||
android:width="18dp"
|
||||
android:height="18dp" />
|
||||
</shape>
|
7
app/src/main/res/drawable/picture_new_item_select_bg.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@color/app_color_white_transparent" android:state_pressed="true" />
|
||||
<item android:drawable="@color/app_color_white_transparent" android:state_selected="true" />
|
||||
<item android:drawable="@color/app_color_white" />
|
||||
</selector>
|
@ -44,6 +44,7 @@
|
||||
<include layout="@layout/view_divider" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_head_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="80dp">
|
||||
|
||||
|
@ -14,4 +14,21 @@
|
||||
<color name="shape2">#5EB9F8</color>
|
||||
<color name="shape3">#5CC2F8</color>
|
||||
<color name="text_hint">#888888</color>
|
||||
|
||||
<!-- 图片选择器使用的颜色 -->
|
||||
<color name="app_color_grey">#393a3e</color>
|
||||
<color name="app_color_black">#000000</color>
|
||||
<color name="app_color_f6">#f6f6f6</color>
|
||||
<color name="app_color_fa">#fafafa</color>
|
||||
<color name="app_color_divider">#B6B6B6</color>
|
||||
<color name="app_color_c51">#f94c51</color>
|
||||
<color name="app_color_green">#43c117</color>
|
||||
<color name="app_color_53575e">#53575e</color>
|
||||
<color name="app_color_transparent">#00000000</color>
|
||||
<color name="app_color_white">#FFFFFF</color>
|
||||
<color name="app_color_white_transparent">#E0DBDBDB</color>
|
||||
<color name="app_color_blue">#7D7DFF</color>
|
||||
<color name="app_color_9b">#9b9b9b</color>
|
||||
<color name="app_color_e0ff6100">#E0FF6100</color>
|
||||
<color name="app_color_red">#FF0000</color>
|
||||
</resources>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<style name="DetailTheme" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||
|
||||
<style name="SplashTheme" parent="AppTheme">
|
||||
<style name="SplashTheme" parent="MyAppTheme">
|
||||
<item name="android:windowBackground">@drawable/splash</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
</style>
|
||||
@ -41,6 +41,421 @@
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<!-- Dialog进入及退出动画 -->
|
||||
<item name="android:windowAnimationStyle">@style/ActionSheetDialogAnimation</item>
|
||||
</style>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
|
||||
|
||||
<style name="AppTheme" parent="BaseNoActionBarTheme">
|
||||
|
||||
<!-- Customize your theme here. -->
|
||||
|
||||
|
||||
<item name="colorPrimary">@color/app_color_grey</item>
|
||||
|
||||
<item name="colorPrimaryDark">@color/app_color_grey</item>
|
||||
|
||||
<item name="colorAccent">@color/app_color_grey</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="BaseNoActionBarTheme" parent="Theme.AppCompat.Light.NoActionBar" />
|
||||
|
||||
<!--白色主题样式,,注意每一项都不能少-->
|
||||
|
||||
|
||||
-
|
||||
|
||||
<style name="picture.white.style" parent="BaseNoActionBarTheme">
|
||||
|
||||
<!-- Customize your theme here. -->
|
||||
|
||||
|
||||
<!--标题栏背景色-->
|
||||
|
||||
|
||||
<item name="colorPrimary">@color/app_color_white</item>
|
||||
|
||||
<!--状态栏背景色-->
|
||||
|
||||
|
||||
<item name="colorPrimaryDark">@color/app_color_white</item>
|
||||
|
||||
<!--是否改变图片列表界面状态栏字体颜色为黑色-->
|
||||
|
||||
|
||||
<item name="picture.statusFontColor">true</item>
|
||||
|
||||
<!--返回键图标-->
|
||||
|
||||
|
||||
<item name="picture.leftBack.icon">@drawable/ic_back_arrow</item>
|
||||
|
||||
<!--标题下拉箭头-->
|
||||
|
||||
|
||||
<item name="picture.arrow_down.icon">@drawable/ic_orange_arrow_down</item>
|
||||
|
||||
<!--标题上拉箭头-->
|
||||
|
||||
|
||||
<item name="picture.arrow_up.icon">@drawable/ic_orange_arrow_up</item>
|
||||
|
||||
<!--标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.title.textColor">@color/app_color_black</item>
|
||||
|
||||
<!--标题栏右边文字-->
|
||||
|
||||
|
||||
<item name="picture.right.textColor">@color/app_color_black</item>
|
||||
|
||||
<!--图片列表勾选样式-->
|
||||
|
||||
|
||||
<item name="picture.checked.style">@drawable/picture_checkbox_selector</item>
|
||||
|
||||
<!--开启图片列表勾选数字模式,开启的话勾选样式要换-->
|
||||
|
||||
|
||||
<item name="picture.style.checkNumMode">false</item>
|
||||
|
||||
<!--选择图片样式0/9-->
|
||||
|
||||
|
||||
<item name="picture.style.numComplete">true</item>
|
||||
|
||||
<!--图片列表底部背景色-->
|
||||
|
||||
|
||||
<item name="picture.bottom.bg">@color/app_color_fa</item>
|
||||
|
||||
<!--图片列表预览文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.preview.textColor">@color/picture_list_sina_text_color</item>
|
||||
|
||||
<!--图片列表已完成文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.complete.textColor">@color/picture_list_sina_text_color</item>
|
||||
|
||||
<!--图片已选数量圆点背景色-->
|
||||
|
||||
|
||||
<item name="picture.num.style">@drawable/picture_num_oval</item>
|
||||
|
||||
<!--预览界面标题栏背景色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.title.bg">@color/app_color_white</item>
|
||||
|
||||
<!--预览界面标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.title.textColor">@color/app_color_black</item>
|
||||
|
||||
<!--预览界面已完成文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.complete.textColor">@color/picture_list_sina_text_color
|
||||
</item>
|
||||
|
||||
<!--预览界面底部背景色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.bottom.bg">@color/picture_color_fa</item>
|
||||
|
||||
<!--预览界面返回箭头-->
|
||||
|
||||
|
||||
<item name="picture.preview.leftBack.icon">@drawable/ic_back_arrow</item>
|
||||
|
||||
<!--裁剪页面标题背景色-->
|
||||
|
||||
|
||||
<item name="picture.crop.toolbar.bg">@color/app_color_white</item>
|
||||
|
||||
<!--裁剪页面状态栏颜色-->
|
||||
|
||||
|
||||
<item name="picture.crop.status.color">@color/app_color_white</item>
|
||||
|
||||
<!--裁剪页面标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.crop.title.color">@color/app_color_black</item>
|
||||
|
||||
<!--相册文件夹列表选中图标-->
|
||||
|
||||
|
||||
<item name="picture.folder_checked_dot">@drawable/picture_orange_oval</item>
|
||||
|
||||
</style>
|
||||
|
||||
<!--QQ数字风格样式,注意每一项都不能少-->
|
||||
|
||||
|
||||
-
|
||||
|
||||
<style name="picture.QQ.style" parent="BaseNoActionBarTheme">
|
||||
|
||||
<!-- Customize your theme here. -->
|
||||
|
||||
|
||||
<!--标题栏背景色-->
|
||||
|
||||
|
||||
<item name="colorPrimary">@color/app_color_blue</item>
|
||||
|
||||
<!--状态栏背景色-->
|
||||
|
||||
|
||||
<item name="colorPrimaryDark">@color/app_color_blue</item>
|
||||
|
||||
<!--是否改变图片列表界面状态栏字体颜色为黑色-->
|
||||
|
||||
|
||||
<item name="picture.statusFontColor">false</item>
|
||||
|
||||
<!--返回键图标-->
|
||||
|
||||
|
||||
<item name="picture.leftBack.icon">@drawable/picture_icon_back</item>
|
||||
|
||||
<!--标题下拉箭头-->
|
||||
|
||||
|
||||
<item name="picture.arrow_down.icon">@drawable/picture_icon_arrow_down</item>
|
||||
|
||||
<!--标题上拉箭头-->
|
||||
|
||||
|
||||
<item name="picture.arrow_up.icon">@drawable/picture_icon_arrow_up</item>
|
||||
|
||||
<!--标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.title.textColor">@color/app_color_white</item>
|
||||
|
||||
<!--标题栏右边文字-->
|
||||
|
||||
|
||||
<item name="picture.right.textColor">@color/app_color_white</item>
|
||||
|
||||
<!--图片列表勾选样式-->
|
||||
|
||||
|
||||
<item name="picture.checked.style">@drawable/checkbox_num_selector</item>
|
||||
|
||||
<!--开启图片列表勾选数字模式,开启的话勾选样式要换-->
|
||||
|
||||
|
||||
<item name="picture.style.checkNumMode">true</item>
|
||||
|
||||
<!--选择图片样式0/9-->
|
||||
|
||||
|
||||
<item name="picture.style.numComplete">false</item>
|
||||
|
||||
<!--图片列表底部背景色-->
|
||||
|
||||
|
||||
<item name="picture.bottom.bg">@color/app_color_fa</item>
|
||||
|
||||
<!--图片列表预览文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.preview.textColor">@color/app_color_blue</item>
|
||||
|
||||
<!--图片列表已完成文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.complete.textColor">@color/app_color_blue</item>
|
||||
|
||||
<!--图片已选数量圆点背景色-->
|
||||
|
||||
|
||||
<item name="picture.num.style">@drawable/num_oval_blue</item>
|
||||
|
||||
<!--预览界面标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.title.textColor">@color/app_color_white</item>
|
||||
|
||||
<!--预览界面已完成文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.complete.textColor">@color/app_color_blue</item>
|
||||
|
||||
<!--预览界面标题栏背景色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.title.bg">@color/app_color_blue</item>
|
||||
|
||||
<!--预览界面底部背景色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.bottom.bg">@color/app_color_fa</item>
|
||||
|
||||
<!--预览界面返回箭头-->
|
||||
|
||||
|
||||
<item name="picture.preview.leftBack.icon">@drawable/picture_icon_back</item>
|
||||
|
||||
<!--裁剪页面标题背景色-->
|
||||
|
||||
|
||||
<item name="picture.crop.toolbar.bg">@color/app_color_blue</item>
|
||||
|
||||
<!--裁剪页面状态栏颜色-->
|
||||
|
||||
|
||||
<item name="picture.crop.status.color">@color/app_color_blue</item>
|
||||
|
||||
<!--裁剪页面标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.crop.title.color">@color/app_color_white</item>
|
||||
|
||||
<!--相册文件夹列表选中图标-->
|
||||
|
||||
|
||||
<item name="picture.folder_checked_dot">@drawable/picture_orange_oval</item>
|
||||
|
||||
</style>
|
||||
|
||||
<!--新浪微博样式,注意每一项都不能少-->
|
||||
|
||||
|
||||
-
|
||||
|
||||
<style name="picture.Sina.style" parent="BaseNoActionBarTheme">
|
||||
|
||||
<!-- Customize your theme here. -->
|
||||
|
||||
|
||||
<!--标题栏背景色-->
|
||||
|
||||
|
||||
<item name="colorPrimary">@color/app_color_white</item>
|
||||
|
||||
<!--状态栏背景色-->
|
||||
|
||||
|
||||
<item name="colorPrimaryDark">@color/app_color_white</item>
|
||||
|
||||
<!--是否改变图片列表界面状态栏字体颜色为黑色-->
|
||||
|
||||
|
||||
<item name="picture.statusFontColor">true</item>
|
||||
|
||||
<!--返回键图标-->
|
||||
|
||||
|
||||
<item name="picture.leftBack.icon">@drawable/ic_back_arrow</item>
|
||||
|
||||
<!--标题下拉箭头-->
|
||||
|
||||
|
||||
<item name="picture.arrow_down.icon">@drawable/ic_orange_arrow_down</item>
|
||||
|
||||
<!--标题上拉箭头-->
|
||||
|
||||
|
||||
<item name="picture.arrow_up.icon">@drawable/ic_orange_arrow_up</item>
|
||||
|
||||
<!--标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.title.textColor">@color/app_color_53575e</item>
|
||||
|
||||
<!--标题栏右边文字-->
|
||||
|
||||
|
||||
<item name="picture.right.textColor">@color/app_color_53575e</item>
|
||||
|
||||
<!--图片列表勾选样式-->
|
||||
|
||||
|
||||
<item name="picture.checked.style">@drawable/picture_checkbox_selector</item>
|
||||
|
||||
<!--开启图片列表勾选数字模式,开启的话勾选样式要换-->
|
||||
|
||||
|
||||
<item name="picture.style.checkNumMode">false</item>
|
||||
|
||||
<!--选择图片样式0/9-->
|
||||
|
||||
|
||||
<item name="picture.style.numComplete">false</item>
|
||||
|
||||
<!--图片列表底部背景色-->
|
||||
|
||||
|
||||
<item name="picture.bottom.bg">@color/app_color_fa</item>
|
||||
|
||||
<!--图片列表预览文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.preview.textColor">@color/picture_list_sina_text_color</item>
|
||||
|
||||
<!--图片列表已完成文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.complete.textColor">@color/picture_list_sina_text_color</item>
|
||||
|
||||
<!--图片已选数量圆点背景色-->
|
||||
|
||||
|
||||
<item name="picture.num.style">@drawable/num_oval_orange</item>
|
||||
|
||||
<!--预览界面标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.title.textColor">@color/app_color_53575e</item>
|
||||
|
||||
<!--预览界面已完成文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.complete.textColor">@color/picture_list_sina_text_color
|
||||
</item>
|
||||
|
||||
<!--预览界面标题栏背景色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.title.bg">@color/app_color_white</item>
|
||||
|
||||
<!--预览界面底部背景色-->
|
||||
|
||||
|
||||
<item name="picture.ac_preview.bottom.bg">@color/app_color_fa</item>
|
||||
|
||||
<!--预览界面返回箭头-->
|
||||
|
||||
|
||||
<item name="picture.preview.leftBack.icon">@drawable/ic_arrow_left</item>
|
||||
|
||||
<!--裁剪页面标题背景色-->
|
||||
|
||||
|
||||
<item name="picture.crop.toolbar.bg">@color/app_color_white</item>
|
||||
|
||||
<!--裁剪页面状态栏颜色-->
|
||||
|
||||
|
||||
<item name="picture.crop.status.color">@color/app_color_white</item>
|
||||
|
||||
<!--裁剪页面标题文字颜色-->
|
||||
|
||||
|
||||
<item name="picture.crop.title.color">@color/app_color_black</item>
|
||||
|
||||
<!--相册文件夹列表选中图标-->
|
||||
|
||||
|
||||
<item name="picture.folder_checked_dot">@drawable/picture_orange_oval</item>
|
||||
|
||||
</style>
|
||||
</resources>
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
apply from: "config.gradle"
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
|
38
config.gradle
Normal file
@ -0,0 +1,38 @@
|
||||
ext {
|
||||
cfgs = [
|
||||
compileSdkVersion : 29,
|
||||
buildToolsVersion : "28.0.3",
|
||||
minSdkVersion : 19,
|
||||
targetSdkVersion : 29,
|
||||
versionCode : 26,
|
||||
versionName : "2.5.6",
|
||||
ucropVersionCode : 24,
|
||||
ucropVersionName : "2.2.4-non-native",
|
||||
|
||||
//open version control
|
||||
androidSupportVersion : "27.0.2",
|
||||
version_recyclerview : "1.1.0",
|
||||
version_appcompat : "1.1.0",
|
||||
localbroadcastmanager : "1.0.0",
|
||||
|
||||
camerax_view : "1.0.0-alpha10",
|
||||
camerax_version : "1.0.0-beta03",
|
||||
camera_core_version : "1.0.0-beta03",
|
||||
futures_version : "1.0.0",
|
||||
|
||||
// ucrop
|
||||
androidx_appcompat_version : "1.1.0",
|
||||
androidx_exifinterface_version: "1.3.0-alpha01",
|
||||
androidx_transition_version : "1.3.1",
|
||||
|
||||
// okio
|
||||
okio_version : "2.6.0",
|
||||
|
||||
// glide
|
||||
glide_version : "4.11.0",
|
||||
|
||||
// picasso
|
||||
picasso_version : "2.71828"
|
||||
|
||||
]
|
||||
}
|
1
picture_library/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
36
picture_library/build.gradle
Normal file
@ -0,0 +1,36 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion cfgs.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion cfgs.minSdkVersion
|
||||
targetSdkVersion cfgs.targetSdkVersion
|
||||
versionCode cfgs.versionCode
|
||||
versionName cfgs.versionName
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation "androidx.appcompat:appcompat:${cfgs.version_appcompat}"
|
||||
implementation "androidx.recyclerview:recyclerview:${cfgs.version_recyclerview}"
|
||||
implementation "androidx.concurrent:concurrent-futures:${cfgs.futures_version}"
|
||||
implementation "com.squareup.okio:okio:${cfgs.okio_version}"
|
||||
implementation "androidx.camera:camera-lifecycle:${cfgs.camerax_version}"
|
||||
implementation "androidx.localbroadcastmanager:localbroadcastmanager:${cfgs.localbroadcastmanager}"
|
||||
implementation "androidx.camera:camera-view:${cfgs.camerax_view}"
|
||||
api project(':ucrop')
|
||||
}
|
25
picture_library/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/luck/Documents/android-sdk-macosx-2/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
63
picture_library/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.luck.picture.lib">
|
||||
|
||||
<uses-sdk tools:overrideLibrary="androidx.camera.view,
|
||||
androidx.camera:camera-camera2,
|
||||
androidx.camera.camera2,androidx.camera.lifecycle,
|
||||
androidx.camera.core" />
|
||||
|
||||
<application>
|
||||
<provider
|
||||
android:name="com.luck.picture.lib.PictureFileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name=".PictureSelectorActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
<activity
|
||||
android:name=".PictureSelectorWeChatStyleActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
<activity
|
||||
android:name=".PictureSelectorCameraEmptyActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@style/Picture.Theme.Translucent" />
|
||||
<activity
|
||||
android:name=".PictureCustomCameraActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
|
||||
<activity
|
||||
android:name=".PicturePreviewActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
<activity
|
||||
android:name=".PictureSelectorPreviewWeChatStyleActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
<activity
|
||||
android:name=".PictureVideoPlayActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:screenOrientation="sensor" />
|
||||
<activity
|
||||
android:name=".PictureExternalPreviewActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
|
||||
<activity
|
||||
android:name=".PicturePlayAudioActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:theme="@style/Base.Theme.NoActionBar" />
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.PictureMultiCuttingActivity"
|
||||
android:theme="@style/Base.Theme.NoActionBar" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,23 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
|
||||
import com.luck.picture.lib.language.PictureLanguageUtils;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-12-15 19:34
|
||||
* @describe:ContextWrapper
|
||||
*/
|
||||
public class PictureContextWrapper extends ContextWrapper {
|
||||
|
||||
public PictureContextWrapper(Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
public static ContextWrapper wrap(Context context, int language) {
|
||||
PictureLanguageUtils.setAppLanguage(context, language);
|
||||
return new PictureContextWrapper(context);
|
||||
}
|
||||
}
|
@ -0,0 +1,286 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.camera.core.CameraX;
|
||||
import androidx.camera.view.CameraView;
|
||||
|
||||
import com.luck.picture.lib.camera.CustomCameraView;
|
||||
import com.luck.picture.lib.camera.listener.CameraListener;
|
||||
import com.luck.picture.lib.camera.view.CaptureLayout;
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.dialog.PictureCustomDialog;
|
||||
import com.luck.picture.lib.permissions.PermissionChecker;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-04 14:05
|
||||
* @describe:Custom photos and videos
|
||||
*/
|
||||
public class PictureCustomCameraActivity extends PictureSelectorCameraEmptyActivity {
|
||||
private final static String TAG = PictureCustomCameraActivity.class.getSimpleName();
|
||||
|
||||
private CustomCameraView mCameraView;
|
||||
protected boolean isEnterSetting;
|
||||
|
||||
@Override
|
||||
public boolean isImmersive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
WindowManager.LayoutParams lp = getWindow().getAttributes();
|
||||
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
getWindow().setAttributes(lp);
|
||||
}
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
super.onCreate(savedInstanceState);
|
||||
// 验证存储权限
|
||||
boolean isExternalStorage = PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) &&
|
||||
PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (!isExternalStorage) {
|
||||
PermissionChecker.requestPermissions(this, new String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证相机权限和麦克风权限
|
||||
if (PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.CAMERA)) {
|
||||
boolean isRecordAudio = PermissionChecker.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
|
||||
if (isRecordAudio) {
|
||||
createCameraView();
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(this,
|
||||
new String[]{Manifest.permission.RECORD_AUDIO}, PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE);
|
||||
}
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(this,
|
||||
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建CameraView
|
||||
*/
|
||||
private void createCameraView() {
|
||||
if (mCameraView == null) {
|
||||
mCameraView = new CustomCameraView(getContext());
|
||||
setContentView(mCameraView);
|
||||
initView();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// 这里只针对权限被手动拒绝后进入设置页面重新获取权限后的操作
|
||||
if (isEnterSetting) {
|
||||
boolean isExternalStorage = PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) &&
|
||||
PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (isExternalStorage) {
|
||||
boolean isCameraPermissionChecker = PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.CAMERA);
|
||||
if (isCameraPermissionChecker) {
|
||||
boolean isRecordAudio = PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
|
||||
if (isRecordAudio) {
|
||||
createCameraView();
|
||||
} else {
|
||||
showPermissionsDialog(false, getString(R.string.picture_audio));
|
||||
}
|
||||
} else {
|
||||
showPermissionsDialog(false, getString(R.string.picture_camera));
|
||||
}
|
||||
} else {
|
||||
showPermissionsDialog(false, getString(R.string.picture_jurisdiction));
|
||||
}
|
||||
isEnterSetting = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化控件
|
||||
*/
|
||||
protected void initView() {
|
||||
mCameraView.setPictureSelectionConfig(config);
|
||||
// 绑定生命周期
|
||||
mCameraView.setBindToLifecycle(new WeakReference<>(this).get());
|
||||
// 视频最大拍摄时长
|
||||
if (config.recordVideoSecond > 0) {
|
||||
mCameraView.setRecordVideoMaxTime(config.recordVideoSecond);
|
||||
}
|
||||
// 视频最小拍摄时长
|
||||
if (config.recordVideoMinSecond > 0) {
|
||||
mCameraView.setRecordVideoMinTime(config.recordVideoMinSecond);
|
||||
}
|
||||
// 获取CameraView
|
||||
CameraView cameraView = mCameraView.getCameraView();
|
||||
if (cameraView != null && config.isCameraAroundState) {
|
||||
cameraView.toggleCamera();
|
||||
}
|
||||
// 获取录制按钮
|
||||
CaptureLayout captureLayout = mCameraView.getCaptureLayout();
|
||||
if (captureLayout != null) {
|
||||
captureLayout.setButtonFeatures(config.buttonFeatures);
|
||||
}
|
||||
// 拍照预览
|
||||
mCameraView.setImageCallbackListener((file, imageView) -> {
|
||||
if (config != null && PictureSelectionConfig.imageEngine != null && file != null) {
|
||||
PictureSelectionConfig.imageEngine.loadImage(getContext(), file.getAbsolutePath(), imageView);
|
||||
}
|
||||
});
|
||||
// 设置拍照或拍视频回调监听
|
||||
mCameraView.setCameraListener(new CameraListener() {
|
||||
@Override
|
||||
public void onPictureSuccess(@NonNull File file) {
|
||||
config.cameraMimeType = PictureMimeType.ofImage();
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(PictureConfig.EXTRA_MEDIA_PATH, file.getAbsolutePath());
|
||||
intent.putExtra(PictureConfig.EXTRA_CONFIG, config);
|
||||
if (config.camera) {
|
||||
dispatchHandleCamera(intent);
|
||||
} else {
|
||||
setResult(RESULT_OK, intent);
|
||||
onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordSuccess(@NonNull File file) {
|
||||
config.cameraMimeType = PictureMimeType.ofVideo();
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(PictureConfig.EXTRA_MEDIA_PATH, file.getAbsolutePath());
|
||||
intent.putExtra(PictureConfig.EXTRA_CONFIG, config);
|
||||
if (config.camera) {
|
||||
dispatchHandleCamera(intent);
|
||||
} else {
|
||||
setResult(RESULT_OK, intent);
|
||||
onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
|
||||
Log.i(TAG, "onError: " + message);
|
||||
}
|
||||
});
|
||||
|
||||
//左边按钮点击事件
|
||||
mCameraView.setOnClickListener(() -> onBackPressed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (config != null && config.camera && PictureSelectionConfig.listener != null) {
|
||||
PictureSelectionConfig.listener.onCancel();
|
||||
}
|
||||
closeActivity();
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mCameraView != null) {
|
||||
CameraX.unbindAll();
|
||||
mCameraView = null;
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE:
|
||||
// 存储权限
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
PermissionChecker.requestPermissions(this,
|
||||
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
|
||||
} else {
|
||||
showPermissionsDialog(true, getString(R.string.picture_jurisdiction));
|
||||
}
|
||||
break;
|
||||
case PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE:
|
||||
// 相机权限
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
boolean isRecordAudio = PermissionChecker.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
|
||||
if (isRecordAudio) {
|
||||
createCameraView();
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(this,
|
||||
new String[]{Manifest.permission.RECORD_AUDIO}, PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE);
|
||||
}
|
||||
} else {
|
||||
showPermissionsDialog(true, getString(R.string.picture_camera));
|
||||
}
|
||||
break;
|
||||
case PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE:
|
||||
// 录音权限
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
createCameraView();
|
||||
} else {
|
||||
showPermissionsDialog(false, getString(R.string.picture_audio));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showPermissionsDialog(boolean isCamera, String errorMsg) {
|
||||
if (isFinishing()) {
|
||||
return;
|
||||
}
|
||||
final PictureCustomDialog dialog =
|
||||
new PictureCustomDialog(getContext(), R.layout.picture_wind_base_dialog);
|
||||
dialog.setCancelable(false);
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
Button btn_cancel = dialog.findViewById(R.id.btn_cancel);
|
||||
Button btn_commit = dialog.findViewById(R.id.btn_commit);
|
||||
btn_commit.setText(getString(R.string.picture_go_setting));
|
||||
TextView tvTitle = dialog.findViewById(R.id.tvTitle);
|
||||
TextView tv_content = dialog.findViewById(R.id.tv_content);
|
||||
tvTitle.setText(getString(R.string.picture_prompt));
|
||||
tv_content.setText(errorMsg);
|
||||
btn_cancel.setOnClickListener(v -> {
|
||||
if (!isFinishing()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
closeActivity();
|
||||
});
|
||||
btn_commit.setOnClickListener(v -> {
|
||||
if (!isFinishing()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
PermissionChecker.launchAppDetailsSettings(getContext());
|
||||
isEnterSetting = true;
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
}
|
@ -0,0 +1,640 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.PointF;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.luck.picture.lib.broadcast.BroadcastAction;
|
||||
import com.luck.picture.lib.broadcast.BroadcastManager;
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.dialog.PictureCustomDialog;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.listener.OnImageCompleteCallback;
|
||||
import com.luck.picture.lib.permissions.PermissionChecker;
|
||||
import com.luck.picture.lib.photoview.PhotoView;
|
||||
import com.luck.picture.lib.thread.PictureThreadUtils;
|
||||
import com.luck.picture.lib.tools.AttrsUtils;
|
||||
import com.luck.picture.lib.tools.DateUtils;
|
||||
import com.luck.picture.lib.tools.JumpUtils;
|
||||
import com.luck.picture.lib.tools.MediaUtils;
|
||||
import com.luck.picture.lib.tools.PictureFileUtils;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
import com.luck.picture.lib.tools.ToastUtils;
|
||||
import com.luck.picture.lib.tools.ValueOf;
|
||||
import com.luck.picture.lib.widget.PreviewViewPager;
|
||||
import com.luck.picture.lib.widget.longimage.ImageSource;
|
||||
import com.luck.picture.lib.widget.longimage.ImageViewState;
|
||||
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import okio.BufferedSource;
|
||||
import okio.Okio;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2017/01/18 下午1:00
|
||||
* @描述: 预览图片
|
||||
*/
|
||||
public class PictureExternalPreviewActivity extends PictureBaseActivity implements View.OnClickListener {
|
||||
|
||||
private ImageButton ibLeftBack;
|
||||
private TextView tvTitle;
|
||||
private PreviewViewPager viewPager;
|
||||
private List<LocalMedia> images = new ArrayList<>();
|
||||
private int position = 0;
|
||||
private SimpleFragmentAdapter adapter;
|
||||
private String downloadPath;
|
||||
private String mMimeType;
|
||||
private ImageButton ibDelete;
|
||||
private View titleViewBg;
|
||||
|
||||
@Override
|
||||
public int getResourceId() {
|
||||
return R.layout.picture_activity_external_preview;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initWidgets() {
|
||||
super.initWidgets();
|
||||
titleViewBg = findViewById(R.id.titleViewBg);
|
||||
tvTitle = findViewById(R.id.picture_title);
|
||||
ibLeftBack = findViewById(R.id.left_back);
|
||||
ibDelete = findViewById(R.id.ib_delete);
|
||||
viewPager = findViewById(R.id.preview_pager);
|
||||
position = getIntent().getIntExtra(PictureConfig.EXTRA_POSITION, 0);
|
||||
images = (List<LocalMedia>) getIntent().getSerializableExtra(PictureConfig.EXTRA_PREVIEW_SELECT_LIST);
|
||||
ibLeftBack.setOnClickListener(this);
|
||||
ibDelete.setOnClickListener(this);
|
||||
ibDelete.setVisibility(config.style != null ? config.style.pictureExternalPreviewGonePreviewDelete
|
||||
? View.VISIBLE : View.GONE : View.GONE);
|
||||
initViewPageAdapterData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置样式
|
||||
*/
|
||||
@Override
|
||||
public void initPictureSelectorStyle() {
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureTitleTextColor != 0) {
|
||||
tvTitle.setTextColor(config.style.pictureTitleTextColor);
|
||||
}
|
||||
if (config.style.pictureTitleTextSize != 0) {
|
||||
tvTitle.setTextSize(config.style.pictureTitleTextSize);
|
||||
}
|
||||
if (config.style.pictureLeftBackIcon != 0) {
|
||||
ibLeftBack.setImageResource(config.style.pictureLeftBackIcon);
|
||||
}
|
||||
if (config.style.pictureExternalPreviewDeleteStyle != 0) {
|
||||
ibDelete.setImageResource(config.style.pictureExternalPreviewDeleteStyle);
|
||||
}
|
||||
if (config.style.pictureTitleBarBackgroundColor != 0) {
|
||||
titleViewBg.setBackgroundColor(colorPrimary);
|
||||
}
|
||||
} else {
|
||||
int previewBgColor = AttrsUtils.getTypeValueColor(getContext(), R.attr.picture_ac_preview_title_bg);
|
||||
if (previewBgColor != 0) {
|
||||
titleViewBg.setBackgroundColor(previewBgColor);
|
||||
} else {
|
||||
titleViewBg.setBackgroundColor(colorPrimary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initViewPageAdapterData() {
|
||||
tvTitle.setText(getString(R.string.picture_preview_image_num,
|
||||
position + 1, images.size()));
|
||||
adapter = new SimpleFragmentAdapter();
|
||||
viewPager.setAdapter(adapter);
|
||||
viewPager.setCurrentItem(position);
|
||||
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int index) {
|
||||
tvTitle.setText(getString(R.string.picture_preview_image_num,
|
||||
index + 1, images.size()));
|
||||
position = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
if (id == R.id.left_back) {
|
||||
finish();
|
||||
exitAnimation();
|
||||
} else if (id == R.id.ib_delete) {
|
||||
if (images != null && images.size() > 0) {
|
||||
int currentItem = viewPager.getCurrentItem();
|
||||
images.remove(currentItem);
|
||||
adapter.removeCacheView(currentItem);
|
||||
// 删除通知用户更新
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(PictureConfig.EXTRA_PREVIEW_DELETE_POSITION, currentItem);
|
||||
BroadcastManager.getInstance(getContext())
|
||||
.action(BroadcastAction.ACTION_DELETE_PREVIEW_POSITION)
|
||||
.extras(bundle).broadcast();
|
||||
if (images.size() == 0) {
|
||||
onBackPressed();
|
||||
return;
|
||||
}
|
||||
tvTitle.setText(getString(R.string.picture_preview_image_num,
|
||||
position + 1, images.size()));
|
||||
position = currentItem;
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SimpleFragmentAdapter extends PagerAdapter {
|
||||
|
||||
/**
|
||||
* 最大缓存图片数量
|
||||
*/
|
||||
private static final int MAX_CACHE_SIZE = 20;
|
||||
/**
|
||||
* 缓存view
|
||||
*/
|
||||
private SparseArray<View> mCacheView;
|
||||
|
||||
private void clear() {
|
||||
if (null != mCacheView) {
|
||||
mCacheView.clear();
|
||||
mCacheView = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeCacheView(int position) {
|
||||
if (mCacheView != null && position < mCacheView.size()) {
|
||||
mCacheView.removeAt(position);
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleFragmentAdapter() {
|
||||
super();
|
||||
this.mCacheView = new SparseArray<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return images != null ? images.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
(container).removeView((View) object);
|
||||
if (mCacheView.size() > MAX_CACHE_SIZE) {
|
||||
mCacheView.remove(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(@NonNull Object object) {
|
||||
return POSITION_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return view == object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
View contentView = mCacheView.get(position);
|
||||
if (contentView == null) {
|
||||
contentView = LayoutInflater.from(container.getContext())
|
||||
.inflate(R.layout.picture_image_preview, container, false);
|
||||
mCacheView.put(position, contentView);
|
||||
}
|
||||
// 常规图控件
|
||||
final PhotoView imageView = contentView.findViewById(R.id.preview_image);
|
||||
// 长图控件
|
||||
final SubsamplingScaleImageView longImageView = contentView.findViewById(R.id.longImg);
|
||||
// 视频播放按钮
|
||||
ImageView ivPlay = contentView.findViewById(R.id.iv_play);
|
||||
LocalMedia media = images.get(position);
|
||||
if (media != null) {
|
||||
final String path;
|
||||
if (media.isCut() && !media.isCompressed()) {
|
||||
// 裁剪过
|
||||
path = media.getCutPath();
|
||||
} else if (media.isCompressed() || (media.isCut() && media.isCompressed())) {
|
||||
// 压缩过,或者裁剪同时压缩过,以最终压缩过图片为准
|
||||
path = media.getCompressPath();
|
||||
} else if (!TextUtils.isEmpty(media.getAndroidQToPath())) {
|
||||
// AndroidQ特有path
|
||||
path = media.getAndroidQToPath();
|
||||
} else {
|
||||
// 原图
|
||||
path = media.getPath();
|
||||
}
|
||||
boolean isHttp = PictureMimeType.isHasHttp(path);
|
||||
String mimeType = isHttp ? PictureMimeType.getImageMimeType(media.getPath()) : media.getMimeType();
|
||||
boolean isHasVideo = PictureMimeType.isHasVideo(mimeType);
|
||||
ivPlay.setVisibility(isHasVideo ? View.VISIBLE : View.GONE);
|
||||
boolean isGif = PictureMimeType.isGif(mimeType);
|
||||
boolean eqLongImg = MediaUtils.isLongImg(media);
|
||||
imageView.setVisibility(eqLongImg && !isGif ? View.GONE : View.VISIBLE);
|
||||
longImageView.setVisibility(eqLongImg && !isGif ? View.VISIBLE : View.GONE);
|
||||
// 压缩过的gif就不是gif了
|
||||
if (isGif && !media.isCompressed()) {
|
||||
if (config != null && PictureSelectionConfig.imageEngine != null) {
|
||||
PictureSelectionConfig.imageEngine.loadAsGifImage
|
||||
(getContext(), path, imageView);
|
||||
}
|
||||
} else {
|
||||
if (config != null && PictureSelectionConfig.imageEngine != null) {
|
||||
if (isHttp) {
|
||||
// 网络图片
|
||||
PictureSelectionConfig.imageEngine.loadImage(contentView.getContext(), path,
|
||||
imageView, longImageView, new OnImageCompleteCallback() {
|
||||
@Override
|
||||
public void onShowLoading() {
|
||||
showPleaseDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHideLoading() {
|
||||
dismissDialog();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (eqLongImg) {
|
||||
displayLongPic(PictureMimeType.isContent(path)
|
||||
? Uri.parse(path) : Uri.fromFile(new File(path)), longImageView);
|
||||
} else {
|
||||
PictureSelectionConfig.imageEngine.loadImage(contentView.getContext(), path, imageView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
imageView.setOnViewTapListener((view, x, y) -> {
|
||||
finish();
|
||||
exitAnimation();
|
||||
});
|
||||
longImageView.setOnClickListener(v -> {
|
||||
finish();
|
||||
exitAnimation();
|
||||
});
|
||||
if (!isHasVideo) {
|
||||
longImageView.setOnLongClickListener(v -> {
|
||||
if (config.isNotPreviewDownload) {
|
||||
if (PermissionChecker.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
downloadPath = path;
|
||||
String currentMimeType = PictureMimeType.isHasHttp(path) ? PictureMimeType.getImageMimeType(media.getPath()) : media.getMimeType();
|
||||
mMimeType = PictureMimeType.isJPG(currentMimeType) ? PictureMimeType.MIME_TYPE_JPEG : currentMimeType;
|
||||
showDownLoadDialog();
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(PictureExternalPreviewActivity.this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (!isHasVideo) {
|
||||
imageView.setOnLongClickListener(v -> {
|
||||
if (config.isNotPreviewDownload) {
|
||||
if (PermissionChecker.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
downloadPath = path;
|
||||
String currentMimeType = PictureMimeType.isHasHttp(path) ? PictureMimeType.getImageMimeType(media.getPath()) : media.getMimeType();
|
||||
mMimeType = PictureMimeType.isJPG(currentMimeType) ? PictureMimeType.MIME_TYPE_JPEG : currentMimeType;
|
||||
showDownLoadDialog();
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(PictureExternalPreviewActivity.this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
ivPlay.setOnClickListener(v -> {
|
||||
if (PictureSelectionConfig.customVideoPlayCallback != null) {
|
||||
PictureSelectionConfig.customVideoPlayCallback.startPlayVideo(media);
|
||||
} else {
|
||||
Intent intent = new Intent();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(PictureConfig.EXTRA_VIDEO_PATH, path);
|
||||
intent.putExtras(bundle);
|
||||
JumpUtils.startPictureVideoPlayActivity(container.getContext(), bundle, PictureConfig.PREVIEW_VIDEO_CODE);
|
||||
}
|
||||
});
|
||||
}
|
||||
(container).addView(contentView, 0);
|
||||
return contentView;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载长图
|
||||
*
|
||||
* @param uri
|
||||
* @param longImg
|
||||
*/
|
||||
private void displayLongPic(Uri uri, SubsamplingScaleImageView longImg) {
|
||||
longImg.setQuickScaleEnabled(true);
|
||||
longImg.setZoomEnabled(true);
|
||||
longImg.setPanEnabled(true);
|
||||
longImg.setDoubleTapZoomDuration(100);
|
||||
longImg.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
|
||||
longImg.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
|
||||
longImg.setImage(ImageSource.uri(uri), new ImageViewState(0, new PointF(0, 0), 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载图片提示
|
||||
*/
|
||||
private void showDownLoadDialog() {
|
||||
if (!isFinishing() && !TextUtils.isEmpty(downloadPath)) {
|
||||
final PictureCustomDialog dialog =
|
||||
new PictureCustomDialog(getContext(), R.layout.picture_wind_base_dialog);
|
||||
Button btn_cancel = dialog.findViewById(R.id.btn_cancel);
|
||||
Button btn_commit = dialog.findViewById(R.id.btn_commit);
|
||||
TextView tvTitle = dialog.findViewById(R.id.tvTitle);
|
||||
TextView tv_content = dialog.findViewById(R.id.tv_content);
|
||||
tvTitle.setText(getString(R.string.picture_prompt));
|
||||
tv_content.setText(getString(R.string.picture_prompt_content));
|
||||
btn_cancel.setOnClickListener(v -> {
|
||||
if (!isFinishing()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
btn_commit.setOnClickListener(view -> {
|
||||
boolean isHttp = PictureMimeType.isHasHttp(downloadPath);
|
||||
showPleaseDialog();
|
||||
if (isHttp) {
|
||||
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<String>() {
|
||||
@Override
|
||||
public String doInBackground() {
|
||||
return showLoadingImage(downloadPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
onSuccessful(result);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 有可能本地图片
|
||||
try {
|
||||
if (PictureMimeType.isContent(downloadPath)) {
|
||||
savePictureAlbumAndroidQ(PictureMimeType.isContent(downloadPath) ? Uri.parse(downloadPath) : Uri.fromFile(new File(downloadPath)));
|
||||
} else {
|
||||
// 把文件插入到系统图库
|
||||
savePictureAlbum();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_save_error) + "\n" + e.getMessage());
|
||||
dismissDialog();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (!isFinishing()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存相片至本地相册
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private void savePictureAlbum() throws Exception {
|
||||
String suffix = PictureMimeType.getLastImgSuffix(mMimeType);
|
||||
String state = Environment.getExternalStorageState();
|
||||
File rootDir = state.equals(Environment.MEDIA_MOUNTED)
|
||||
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
|
||||
: getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
if (rootDir != null && !rootDir.exists() && rootDir.mkdirs()) {
|
||||
}
|
||||
File folderDir = new File(SdkVersionUtils.checkedAndroid_Q() || !state.equals(Environment.MEDIA_MOUNTED)
|
||||
? rootDir.getAbsolutePath() : rootDir.getAbsolutePath() + File.separator + PictureMimeType.CAMERA + File.separator);
|
||||
if (folderDir != null && !folderDir.exists() && folderDir.mkdirs()) {
|
||||
}
|
||||
String fileName = DateUtils.getCreateFileName("IMG_") + suffix;
|
||||
File file = new File(folderDir, fileName);
|
||||
PictureFileUtils.copyFile(downloadPath, file.getAbsolutePath());
|
||||
onSuccessful(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片保存成功
|
||||
*
|
||||
* @param result
|
||||
*/
|
||||
private void onSuccessful(String result) {
|
||||
dismissDialog();
|
||||
if (!TextUtils.isEmpty(result)) {
|
||||
try {
|
||||
if (!SdkVersionUtils.checkedAndroid_Q()) {
|
||||
File file = new File(result);
|
||||
MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), null);
|
||||
new PictureMediaScannerConnection(getContext(), file.getAbsolutePath(), () -> {
|
||||
});
|
||||
}
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_save_success) + "\n" + result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_save_error));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片到picture 目录,Android Q适配,最简单的做法就是保存到公共目录,不用SAF存储
|
||||
*
|
||||
* @param inputUri
|
||||
*/
|
||||
private void savePictureAlbumAndroidQ(Uri inputUri) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, DateUtils.getCreateFileName("IMG_"));
|
||||
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, ValueOf.toString(System.currentTimeMillis()));
|
||||
contentValues.put(MediaStore.Images.Media.MIME_TYPE, mMimeType);
|
||||
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM);
|
||||
Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
|
||||
if (uri == null) {
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_save_error));
|
||||
return;
|
||||
}
|
||||
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<String>() {
|
||||
|
||||
@Override
|
||||
public String doInBackground() {
|
||||
BufferedSource buffer = null;
|
||||
try {
|
||||
buffer = Okio.buffer(Okio.source(Objects.requireNonNull(getContentResolver().openInputStream(inputUri))));
|
||||
OutputStream outputStream = getContentResolver().openOutputStream(uri);
|
||||
boolean bufferCopy = PictureFileUtils.bufferCopy(buffer, outputStream);
|
||||
if (bufferCopy) {
|
||||
return PictureFileUtils.getPath(getContext(), uri);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (buffer != null && buffer.isOpen()) {
|
||||
PictureFileUtils.close(buffer);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
PictureThreadUtils.cancel(PictureThreadUtils.getIoPool());
|
||||
onSuccessful(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 针对Q版本创建uri
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Uri createOutImageUri() {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, DateUtils.getCreateFileName("IMG_"));
|
||||
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, ValueOf.toString(System.currentTimeMillis()));
|
||||
contentValues.put(MediaStore.Images.Media.MIME_TYPE, mMimeType);
|
||||
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM);
|
||||
|
||||
return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
|
||||
}
|
||||
|
||||
// 下载图片保存至手机
|
||||
public String showLoadingImage(String urlPath) {
|
||||
Uri outImageUri = null;
|
||||
OutputStream outputStream = null;
|
||||
InputStream inputStream = null;
|
||||
BufferedSource inBuffer = null;
|
||||
try {
|
||||
if (SdkVersionUtils.checkedAndroid_Q()) {
|
||||
outImageUri = createOutImageUri();
|
||||
} else {
|
||||
String suffix = PictureMimeType.getLastImgSuffix(mMimeType);
|
||||
String state = Environment.getExternalStorageState();
|
||||
File rootDir =
|
||||
state.equals(Environment.MEDIA_MOUNTED)
|
||||
? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
|
||||
: getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
if (rootDir != null) {
|
||||
if (!rootDir.exists()) {
|
||||
rootDir.mkdirs();
|
||||
}
|
||||
File folderDir = new File(!state.equals(Environment.MEDIA_MOUNTED)
|
||||
? rootDir.getAbsolutePath() : rootDir.getAbsolutePath() + File.separator + PictureMimeType.CAMERA + File.separator);
|
||||
if (!folderDir.exists() && folderDir.mkdirs()) {
|
||||
}
|
||||
String fileName = DateUtils.getCreateFileName("IMG_") + suffix;
|
||||
File file = new File(folderDir, fileName);
|
||||
outImageUri = Uri.fromFile(file);
|
||||
}
|
||||
}
|
||||
if (outImageUri != null) {
|
||||
outputStream = Objects.requireNonNull(getContentResolver().openOutputStream(outImageUri));
|
||||
URL u = new URL(urlPath);
|
||||
inputStream = u.openStream();
|
||||
inBuffer = Okio.buffer(Okio.source(inputStream));
|
||||
boolean bufferCopy = PictureFileUtils.bufferCopy(inBuffer, outputStream);
|
||||
if (bufferCopy) {
|
||||
return PictureFileUtils.getPath(this, outImageUri);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (outImageUri != null && SdkVersionUtils.checkedAndroid_Q()) {
|
||||
getContentResolver().delete(outImageUri, null, null);
|
||||
}
|
||||
} finally {
|
||||
PictureFileUtils.close(inputStream);
|
||||
PictureFileUtils.close(outputStream);
|
||||
PictureFileUtils.close(inBuffer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
exitAnimation();
|
||||
}
|
||||
|
||||
private void exitAnimation() {
|
||||
overridePendingTransition(R.anim.picture_anim_fade_in, config.windowAnimationStyle != null
|
||||
&& config.windowAnimationStyle.activityPreviewExitAnimation != 0
|
||||
? config.windowAnimationStyle.activityPreviewExitAnimation : R.anim.picture_anim_exit);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (adapter != null) {
|
||||
adapter.clear();
|
||||
}
|
||||
if (PictureSelectionConfig.customVideoPlayCallback != null) {
|
||||
PictureSelectionConfig.customVideoPlayCallback = null;
|
||||
}
|
||||
if (PictureSelectionConfig.onCustomCameraInterfaceListener != null) {
|
||||
PictureSelectionConfig.onCustomCameraInterfaceListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
switch (requestCode) {
|
||||
case PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE:
|
||||
// 存储权限
|
||||
for (int i = 0; i < grantResults.length; i++) {
|
||||
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
|
||||
showDownLoadDialog();
|
||||
} else {
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_jurisdiction));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2016/3/28 下午2:00
|
||||
* @描述: 自定义FileProvider 解决FileProvider冲突问题
|
||||
*/
|
||||
|
||||
public class PictureFileProvider extends FileProvider {
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-12-03 10:41
|
||||
* @describe:刷新相册
|
||||
*/
|
||||
public class PictureMediaScannerConnection implements MediaScannerConnection.MediaScannerConnectionClient {
|
||||
public interface ScanListener {
|
||||
void onScanFinish();
|
||||
}
|
||||
|
||||
private MediaScannerConnection mMs;
|
||||
private String mPath;
|
||||
private ScanListener mListener;
|
||||
|
||||
public PictureMediaScannerConnection(Context context, String path, ScanListener l) {
|
||||
this.mListener = l;
|
||||
this.mPath = path;
|
||||
this.mMs = new MediaScannerConnection(context.getApplicationContext(), this);
|
||||
this.mMs.connect();
|
||||
}
|
||||
|
||||
public PictureMediaScannerConnection(Context context, String path) {
|
||||
this.mPath = path;
|
||||
this.mMs = new MediaScannerConnection(context.getApplicationContext(), this);
|
||||
this.mMs.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaScannerConnected() {
|
||||
if (!TextUtils.isEmpty(mPath)) {
|
||||
mMs.scanFile(mPath, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanCompleted(String path, Uri uri) {
|
||||
mMs.disconnect();
|
||||
if (mListener != null) {
|
||||
mListener.onScanFinish();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.tools.DateUtils;
|
||||
|
||||
/**
|
||||
* # No longer maintain audio related functions,
|
||||
* but can continue to use but there will be phone compatibility issues.
|
||||
* <p>
|
||||
* 不再维护音频相关功能,但可以继续使用但会有机型兼容性问题
|
||||
*/
|
||||
@Deprecated
|
||||
public class PicturePlayAudioActivity extends PictureBaseActivity implements View.OnClickListener {
|
||||
private String audio_path;
|
||||
private MediaPlayer mediaPlayer;
|
||||
private SeekBar musicSeekBar;
|
||||
private boolean isPlayAudio = false;
|
||||
private TextView tv_PlayPause, tv_Stop, tv_Quit,
|
||||
tv_musicStatus, tv_musicTotal, tv_musicTime;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResourceId() {
|
||||
return R.layout.picture_play_audio;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initWidgets() {
|
||||
super.initWidgets();
|
||||
audio_path = getIntent().getStringExtra(PictureConfig.EXTRA_AUDIO_PATH);
|
||||
tv_musicStatus = findViewById(R.id.tv_musicStatus);
|
||||
tv_musicTime = findViewById(R.id.tv_musicTime);
|
||||
musicSeekBar = findViewById(R.id.musicSeekBar);
|
||||
tv_musicTotal = findViewById(R.id.tv_musicTotal);
|
||||
tv_PlayPause = findViewById(R.id.tv_PlayPause);
|
||||
tv_Stop = findViewById(R.id.tv_Stop);
|
||||
tv_Quit = findViewById(R.id.tv_Quit);
|
||||
handler.postDelayed(() -> initPlayer(audio_path), 30);
|
||||
tv_PlayPause.setOnClickListener(this);
|
||||
tv_Stop.setOnClickListener(this);
|
||||
tv_Quit.setOnClickListener(this);
|
||||
musicSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (fromUser) {
|
||||
mediaPlayer.seekTo(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 通过 Handler 更新 UI 上的组件状态
|
||||
public Handler handler = new Handler();
|
||||
public Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (mediaPlayer != null) {
|
||||
tv_musicTime.setText(DateUtils.formatDurationTime(mediaPlayer.getCurrentPosition()));
|
||||
musicSeekBar.setProgress(mediaPlayer.getCurrentPosition());
|
||||
musicSeekBar.setMax(mediaPlayer.getDuration());
|
||||
tv_musicTotal.setText(DateUtils.formatDurationTime(mediaPlayer.getDuration()));
|
||||
handler.postDelayed(runnable, 200);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化音频播放组件
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
private void initPlayer(String path) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(path);
|
||||
mediaPlayer.prepare();
|
||||
mediaPlayer.setLooping(true);
|
||||
playAudio();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int i = v.getId();
|
||||
if (i == R.id.tv_PlayPause) {
|
||||
playAudio();
|
||||
|
||||
}
|
||||
if (i == R.id.tv_Stop) {
|
||||
tv_musicStatus.setText(getString(R.string.picture_stop_audio));
|
||||
tv_PlayPause.setText(getString(R.string.picture_play_audio));
|
||||
stop(audio_path);
|
||||
|
||||
}
|
||||
if (i == R.id.tv_Quit) {
|
||||
handler.removeCallbacks(runnable);
|
||||
new Handler().postDelayed(() -> stop(audio_path), 30);
|
||||
try {
|
||||
closeActivity();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 播放音频
|
||||
*/
|
||||
private void playAudio() {
|
||||
if (mediaPlayer != null) {
|
||||
musicSeekBar.setProgress(mediaPlayer.getCurrentPosition());
|
||||
musicSeekBar.setMax(mediaPlayer.getDuration());
|
||||
}
|
||||
String ppStr = tv_PlayPause.getText().toString();
|
||||
if (ppStr.equals(getString(R.string.picture_play_audio))) {
|
||||
tv_PlayPause.setText(getString(R.string.picture_pause_audio));
|
||||
tv_musicStatus.setText(getString(R.string.picture_play_audio));
|
||||
playOrPause();
|
||||
} else {
|
||||
tv_PlayPause.setText(getString(R.string.picture_play_audio));
|
||||
tv_musicStatus.setText(getString(R.string.picture_pause_audio));
|
||||
playOrPause();
|
||||
}
|
||||
if (!isPlayAudio) {
|
||||
handler.post(runnable);
|
||||
isPlayAudio = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
public void stop(String path) {
|
||||
if (mediaPlayer != null) {
|
||||
try {
|
||||
mediaPlayer.stop();
|
||||
mediaPlayer.reset();
|
||||
mediaPlayer.setDataSource(path);
|
||||
mediaPlayer.prepare();
|
||||
mediaPlayer.seekTo(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停播放
|
||||
*/
|
||||
public void playOrPause() {
|
||||
try {
|
||||
if (mediaPlayer != null) {
|
||||
if (mediaPlayer.isPlaying()) {
|
||||
mediaPlayer.pause();
|
||||
} else {
|
||||
mediaPlayer.start();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
closeActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mediaPlayer != null && handler != null) {
|
||||
handler.removeCallbacks(runnable);
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.style.PictureParameterStyle;
|
||||
import com.luck.picture.lib.tools.DoubleUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2017-5-24 22:30
|
||||
* @describe:PictureSelector
|
||||
*/
|
||||
|
||||
public final class PictureSelector {
|
||||
|
||||
private final WeakReference<Activity> mActivity;
|
||||
private final WeakReference<Fragment> mFragment;
|
||||
|
||||
private PictureSelector(Activity activity) {
|
||||
this(activity, null);
|
||||
}
|
||||
|
||||
private PictureSelector(Fragment fragment) {
|
||||
this(fragment.getActivity(), fragment);
|
||||
}
|
||||
|
||||
private PictureSelector(Activity activity, Fragment fragment) {
|
||||
mActivity = new WeakReference<>(activity);
|
||||
mFragment = new WeakReference<>(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start PictureSelector for Activity.
|
||||
*
|
||||
* @param activity
|
||||
* @return PictureSelector instance.
|
||||
*/
|
||||
public static PictureSelector create(Activity activity) {
|
||||
return new PictureSelector(activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start PictureSelector for Fragment.
|
||||
*
|
||||
* @param fragment
|
||||
* @return PictureSelector instance.
|
||||
*/
|
||||
public static PictureSelector create(Fragment fragment) {
|
||||
return new PictureSelector(fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chooseMode Select the type of picture you want,all or Picture or Video .
|
||||
* @return LocalMedia PictureSelectionModel
|
||||
* Use {@link PictureMimeType.ofAll(),ofImage(),ofVideo(),ofAudio()}.
|
||||
*/
|
||||
public PictureSelectionModel openGallery(int chooseMode) {
|
||||
return new PictureSelectionModel(this, chooseMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chooseMode Select the type of picture you want,Picture or Video.
|
||||
* @return LocalMedia PictureSelectionModel
|
||||
* Use {@link PictureMimeType.ofImage(),ofVideo()}.
|
||||
*/
|
||||
public PictureSelectionModel openCamera(int chooseMode) {
|
||||
return new PictureSelectionModel(this, chooseMode, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部预览时设置样式
|
||||
*
|
||||
* @param themeStyle
|
||||
* @return
|
||||
*/
|
||||
public PictureSelectionModel themeStyle(int themeStyle) {
|
||||
return new PictureSelectionModel(this, PictureMimeType.ofImage())
|
||||
.theme(themeStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部预览时动态代码设置样式
|
||||
*
|
||||
* @param style
|
||||
* @return
|
||||
*/
|
||||
public PictureSelectionModel setPictureStyle(PictureParameterStyle style) {
|
||||
return new PictureSelectionModel(this, PictureMimeType.ofImage())
|
||||
.setPictureStyle(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* @return Selector Multiple LocalMedia
|
||||
*/
|
||||
public static List<LocalMedia> obtainMultipleResult(Intent data) {
|
||||
if (data != null) {
|
||||
List<LocalMedia> result = data.getParcelableArrayListExtra(PictureConfig.EXTRA_RESULT_SELECTION);
|
||||
return result == null ? new ArrayList<>() : result;
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* @return Put image Intent Data
|
||||
*/
|
||||
public static Intent putIntentResult(List<LocalMedia> data) {
|
||||
return new Intent().putParcelableArrayListExtra(PictureConfig.EXTRA_RESULT_SELECTION,
|
||||
(ArrayList<? extends Parcelable>) data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bundle
|
||||
* @return get Selector LocalMedia
|
||||
*/
|
||||
public static List<LocalMedia> obtainSelectorList(Bundle bundle) {
|
||||
if (bundle != null) {
|
||||
List<LocalMedia> selectionMedias = bundle.getParcelableArrayList(PictureConfig.EXTRA_SELECT_LIST);
|
||||
return selectionMedias == null ? new ArrayList<>() : selectionMedias;
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selectedImages
|
||||
* @return put Selector LocalMedia
|
||||
*/
|
||||
public static void saveSelectorList(Bundle outState, List<LocalMedia> selectedImages) {
|
||||
outState.putParcelableArrayList(PictureConfig.EXTRA_SELECT_LIST,
|
||||
(ArrayList<? extends Parcelable>) selectedImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* set preview image
|
||||
*
|
||||
* @param position
|
||||
* @param medias
|
||||
*/
|
||||
public void externalPicturePreview(int position, List<LocalMedia> medias, int enterAnimation) {
|
||||
if (!DoubleUtils.isFastDoubleClick()) {
|
||||
if (getActivity() != null) {
|
||||
Intent intent = new Intent(getActivity(), PictureExternalPreviewActivity.class);
|
||||
intent.putParcelableArrayListExtra(PictureConfig.EXTRA_PREVIEW_SELECT_LIST,
|
||||
(ArrayList<? extends Parcelable>) medias);
|
||||
intent.putExtra(PictureConfig.EXTRA_POSITION, position);
|
||||
getActivity().startActivity(intent);
|
||||
getActivity().overridePendingTransition(enterAnimation != 0
|
||||
? enterAnimation : R.anim.picture_anim_enter, R.anim.picture_anim_fade_in);
|
||||
} else {
|
||||
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set preview image
|
||||
*
|
||||
* @param position
|
||||
* @param medias
|
||||
* @param directory_path
|
||||
*/
|
||||
public void externalPicturePreview(int position, String directory_path, List<LocalMedia> medias, int enterAnimation) {
|
||||
if (!DoubleUtils.isFastDoubleClick()) {
|
||||
if (getActivity() != null) {
|
||||
Intent intent = new Intent(getActivity(), PictureExternalPreviewActivity.class);
|
||||
intent.putParcelableArrayListExtra(PictureConfig.EXTRA_PREVIEW_SELECT_LIST, (ArrayList<? extends Parcelable>) medias);
|
||||
intent.putExtra(PictureConfig.EXTRA_POSITION, position);
|
||||
intent.putExtra(PictureConfig.EXTRA_DIRECTORY_PATH, directory_path);
|
||||
getActivity().startActivity(intent);
|
||||
getActivity().overridePendingTransition(enterAnimation != 0
|
||||
? enterAnimation : R.anim.picture_anim_enter, R.anim.picture_anim_fade_in);
|
||||
} else {
|
||||
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set preview video
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
public void externalPictureVideo(String path) {
|
||||
if (!DoubleUtils.isFastDoubleClick()) {
|
||||
if (getActivity() != null) {
|
||||
Intent intent = new Intent(getActivity(), PictureVideoPlayActivity.class);
|
||||
intent.putExtra(PictureConfig.EXTRA_VIDEO_PATH, path);
|
||||
intent.putExtra(PictureConfig.EXTRA_PREVIEW_VIDEO, true);
|
||||
getActivity().startActivity(intent);
|
||||
} else {
|
||||
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set preview audio
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
public void externalPictureAudio(String path) {
|
||||
if (!DoubleUtils.isFastDoubleClick()) {
|
||||
if (getActivity() != null) {
|
||||
Intent intent = new Intent(getActivity(), PicturePlayAudioActivity.class);
|
||||
intent.putExtra(PictureConfig.EXTRA_AUDIO_PATH, path);
|
||||
getActivity().startActivity(intent);
|
||||
getActivity().overridePendingTransition(R.anim.picture_anim_enter, 0);
|
||||
} else {
|
||||
throw new NullPointerException("Starting the PictureSelector Activity cannot be empty ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Activity.
|
||||
*/
|
||||
@Nullable
|
||||
Activity getActivity() {
|
||||
return mActivity.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Fragment.
|
||||
*/
|
||||
@Nullable
|
||||
Fragment getFragment() {
|
||||
return mFragment != null ? mFragment.get() : null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,395 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.immersive.ImmersiveManage;
|
||||
import com.luck.picture.lib.permissions.PermissionChecker;
|
||||
import com.luck.picture.lib.thread.PictureThreadUtils;
|
||||
import com.luck.picture.lib.tools.BitmapUtils;
|
||||
import com.luck.picture.lib.tools.MediaUtils;
|
||||
import com.luck.picture.lib.tools.PictureFileUtils;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
import com.luck.picture.lib.tools.ToastUtils;
|
||||
import com.luck.picture.lib.tools.ValueOf;
|
||||
import com.yalantis.ucrop.UCrop;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-15 21:41
|
||||
* @describe:PictureSelectorCameraEmptyActivity
|
||||
*/
|
||||
public class PictureSelectorCameraEmptyActivity extends PictureBaseActivity {
|
||||
|
||||
@Override
|
||||
public void immersive() {
|
||||
ImmersiveManage.immersiveAboveAPI23(this
|
||||
, ContextCompat.getColor(this, R.color.picture_color_transparent)
|
||||
, ContextCompat.getColor(this, R.color.picture_color_transparent)
|
||||
, openWhiteStatusBar);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (config == null) {
|
||||
closeActivity();
|
||||
return;
|
||||
}
|
||||
if (!config.isUseCustomCamera) {
|
||||
if (savedInstanceState == null) {
|
||||
if (PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) &&
|
||||
PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
|
||||
if (PictureSelectionConfig.onCustomCameraInterfaceListener != null) {
|
||||
if (config.chooseMode == PictureConfig.TYPE_VIDEO) {
|
||||
PictureSelectionConfig.onCustomCameraInterfaceListener.onCameraClick(getContext(), config, PictureConfig.TYPE_VIDEO);
|
||||
} else {
|
||||
PictureSelectionConfig.onCustomCameraInterfaceListener.onCameraClick(getContext(), config, PictureConfig.TYPE_IMAGE);
|
||||
}
|
||||
} else {
|
||||
onTakePhoto();
|
||||
}
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(this, new String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE}, PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE);
|
||||
}
|
||||
}
|
||||
setTheme(R.style.Picture_Theme_Translucent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getResourceId() {
|
||||
return R.layout.picture_empty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* open camera
|
||||
*/
|
||||
private void onTakePhoto() {
|
||||
if (PermissionChecker
|
||||
.checkSelfPermission(this, Manifest.permission.CAMERA)) {
|
||||
boolean isPermissionChecker = true;
|
||||
if (config != null && config.isUseCustomCamera) {
|
||||
isPermissionChecker = PermissionChecker.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);
|
||||
}
|
||||
if (isPermissionChecker) {
|
||||
startCamera();
|
||||
} else {
|
||||
PermissionChecker
|
||||
.requestPermissions(this,
|
||||
new String[]{Manifest.permission.RECORD_AUDIO}, PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE);
|
||||
}
|
||||
} else {
|
||||
PermissionChecker.requestPermissions(this,
|
||||
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the Camera by type
|
||||
*/
|
||||
private void startCamera() {
|
||||
switch (config.chooseMode) {
|
||||
case PictureConfig.TYPE_ALL:
|
||||
case PictureConfig.TYPE_IMAGE:
|
||||
startOpenCamera();
|
||||
break;
|
||||
case PictureConfig.TYPE_VIDEO:
|
||||
startOpenCameraVideo();
|
||||
break;
|
||||
case PictureConfig.TYPE_AUDIO:
|
||||
startOpenCameraAudio();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode == RESULT_OK) {
|
||||
switch (requestCode) {
|
||||
case UCrop.REQUEST_CROP:
|
||||
singleCropHandleResult(data);
|
||||
break;
|
||||
case PictureConfig.REQUEST_CAMERA:
|
||||
dispatchHandleCamera(data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (resultCode == RESULT_CANCELED) {
|
||||
if (config != null && PictureSelectionConfig.listener != null) {
|
||||
PictureSelectionConfig.listener.onCancel();
|
||||
}
|
||||
closeActivity();
|
||||
} else if (resultCode == UCrop.RESULT_ERROR) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
Throwable throwable = (Throwable) data.getSerializableExtra(UCrop.EXTRA_ERROR);
|
||||
ToastUtils.s(getContext(), throwable.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single picture clipping callback
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
protected void singleCropHandleResult(Intent data) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
List<LocalMedia> medias = new ArrayList<>();
|
||||
Uri resultUri = UCrop.getOutput(data);
|
||||
if (resultUri == null) {
|
||||
return;
|
||||
}
|
||||
String cutPath = resultUri.getPath();
|
||||
boolean isCutEmpty = TextUtils.isEmpty(cutPath);
|
||||
LocalMedia media = new LocalMedia(config.cameraPath, 0, false,
|
||||
config.isCamera ? 1 : 0, 0, config.chooseMode);
|
||||
if (SdkVersionUtils.checkedAndroid_Q()) {
|
||||
int lastIndexOf = config.cameraPath.lastIndexOf("/") + 1;
|
||||
media.setId(lastIndexOf > 0 ? ValueOf.toLong(config.cameraPath.substring(lastIndexOf)) : -1);
|
||||
media.setAndroidQToPath(cutPath);
|
||||
if (isCutEmpty) {
|
||||
if (PictureMimeType.isContent(config.cameraPath)) {
|
||||
String path = PictureFileUtils.getPath(this, Uri.parse(config.cameraPath));
|
||||
media.setSize(!TextUtils.isEmpty(path) ? new File(path).length() : 0);
|
||||
} else {
|
||||
media.setSize(new File(config.cameraPath).length());
|
||||
}
|
||||
} else {
|
||||
media.setSize(new File(cutPath).length());
|
||||
}
|
||||
} else {
|
||||
// Taking a photo generates a temporary id
|
||||
media.setId(System.currentTimeMillis());
|
||||
media.setSize(new File(isCutEmpty ? media.getPath() : cutPath).length());
|
||||
}
|
||||
media.setCut(!isCutEmpty);
|
||||
media.setCutPath(cutPath);
|
||||
String mimeType = PictureMimeType.getImageMimeType(cutPath);
|
||||
media.setMimeType(mimeType);
|
||||
int width = 0, height = 0;
|
||||
media.setOrientation(-1);
|
||||
if (PictureMimeType.isContent(media.getPath())) {
|
||||
if (PictureMimeType.isHasVideo(media.getMimeType())) {
|
||||
int[] size = MediaUtils.getVideoSizeForUri(getContext(), Uri.parse(media.getPath()));
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
} else if (PictureMimeType.isHasImage(media.getMimeType())) {
|
||||
int[] size = MediaUtils.getImageSizeForUri(getContext(), Uri.parse(media.getPath()));
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
}
|
||||
} else {
|
||||
if (PictureMimeType.isHasVideo(media.getMimeType())) {
|
||||
int[] size = MediaUtils.getVideoSizeForUrl(media.getPath());
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
} else if (PictureMimeType.isHasImage(media.getMimeType())) {
|
||||
int[] size = MediaUtils.getImageSizeForUrl(media.getPath());
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
}
|
||||
}
|
||||
media.setWidth(width);
|
||||
media.setHeight(height);
|
||||
// The width and height of the image are reversed if there is rotation information
|
||||
MediaUtils.setOrientationAsynchronous(getContext(), media, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH,
|
||||
item -> {
|
||||
medias.add(item);
|
||||
handlerResult(medias);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatchHandleCamera
|
||||
*
|
||||
* @param intent
|
||||
*/
|
||||
protected void dispatchHandleCamera(Intent intent) {
|
||||
boolean isAudio = config.chooseMode == PictureMimeType.ofAudio();
|
||||
config.cameraPath = isAudio ? getAudioPath(intent) : config.cameraPath;
|
||||
if (TextUtils.isEmpty(config.cameraPath)) {
|
||||
return;
|
||||
}
|
||||
showPleaseDialog();
|
||||
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<LocalMedia>() {
|
||||
|
||||
@Override
|
||||
public LocalMedia doInBackground() {
|
||||
LocalMedia media = new LocalMedia();
|
||||
String mimeType = isAudio ? PictureMimeType.MIME_TYPE_AUDIO : "";
|
||||
int[] newSize = new int[2];
|
||||
long duration = 0;
|
||||
if (!isAudio) {
|
||||
if (PictureMimeType.isContent(config.cameraPath)) {
|
||||
// content: Processing rules
|
||||
String path = PictureFileUtils.getPath(getContext(), Uri.parse(config.cameraPath));
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
File cameraFile = new File(path);
|
||||
mimeType = PictureMimeType.getMimeType(config.cameraMimeType);
|
||||
media.setSize(cameraFile.length());
|
||||
}
|
||||
if (PictureMimeType.isHasImage(mimeType)) {
|
||||
newSize = MediaUtils.getImageSizeForUrlToAndroidQ(getContext(), config.cameraPath);
|
||||
} else if (PictureMimeType.isHasVideo(mimeType)) {
|
||||
newSize = MediaUtils.getVideoSizeForUri(getContext(), Uri.parse(config.cameraPath));
|
||||
duration = MediaUtils.extractDuration(getContext(), SdkVersionUtils.checkedAndroid_Q(), config.cameraPath);
|
||||
}
|
||||
int lastIndexOf = config.cameraPath.lastIndexOf("/") + 1;
|
||||
media.setId(lastIndexOf > 0 ? ValueOf.toLong(config.cameraPath.substring(lastIndexOf)) : -1);
|
||||
media.setRealPath(path);
|
||||
// Custom photo has been in the application sandbox into the file
|
||||
String mediaPath = intent != null ? intent.getStringExtra(PictureConfig.EXTRA_MEDIA_PATH) : null;
|
||||
media.setAndroidQToPath(mediaPath);
|
||||
} else {
|
||||
File cameraFile = new File(config.cameraPath);
|
||||
mimeType = PictureMimeType.getMimeType(config.cameraMimeType);
|
||||
media.setSize(cameraFile.length());
|
||||
if (PictureMimeType.isHasImage(mimeType)) {
|
||||
int degree = PictureFileUtils.readPictureDegree(getContext(), config.cameraPath);
|
||||
BitmapUtils.rotateImage(degree, config.cameraPath);
|
||||
newSize = MediaUtils.getImageSizeForUrl(config.cameraPath);
|
||||
} else if (PictureMimeType.isHasVideo(mimeType)) {
|
||||
newSize = MediaUtils.getVideoSizeForUrl(config.cameraPath);
|
||||
duration = MediaUtils.extractDuration(getContext(), SdkVersionUtils.checkedAndroid_Q(), config.cameraPath);
|
||||
}
|
||||
// Taking a photo generates a temporary id
|
||||
media.setId(System.currentTimeMillis());
|
||||
}
|
||||
media.setPath(config.cameraPath);
|
||||
media.setDuration(duration);
|
||||
media.setMimeType(mimeType);
|
||||
media.setWidth(newSize[0]);
|
||||
media.setHeight(newSize[1]);
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isHasVideo(media.getMimeType())) {
|
||||
media.setParentFolderName(Environment.DIRECTORY_MOVIES);
|
||||
} else {
|
||||
media.setParentFolderName(PictureMimeType.CAMERA);
|
||||
}
|
||||
media.setChooseModel(config.chooseMode);
|
||||
long bucketId = MediaUtils.getCameraFirstBucketId(getContext());
|
||||
media.setBucketId(bucketId);
|
||||
// The width and height of the image are reversed if there is rotation information
|
||||
MediaUtils.setOrientationSynchronous(getContext(), media, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH);
|
||||
}
|
||||
return media;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(LocalMedia result) {
|
||||
// Refresh the system library
|
||||
dismissDialog();
|
||||
if (!SdkVersionUtils.checkedAndroid_Q()) {
|
||||
if (config.isFallbackVersion3) {
|
||||
new PictureMediaScannerConnection(getContext(), config.cameraPath);
|
||||
} else {
|
||||
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(config.cameraPath))));
|
||||
}
|
||||
}
|
||||
dispatchCameraHandleResult(result);
|
||||
// Solve some phone using Camera, DCIM will produce repetitive problems
|
||||
if (!SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isHasImage(result.getMimeType())) {
|
||||
int lastImageId = MediaUtils.getDCIMLastImageId(getContext());
|
||||
if (lastImageId != -1) {
|
||||
MediaUtils.removeMedia(getContext(), lastImageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatchCameraHandleResult
|
||||
*
|
||||
* @param media
|
||||
*/
|
||||
private void dispatchCameraHandleResult(LocalMedia media) {
|
||||
boolean isHasImage = PictureMimeType.isHasImage(media.getMimeType());
|
||||
if (config.enableCrop && isHasImage) {
|
||||
config.originalPath = config.cameraPath;
|
||||
startCrop(config.cameraPath, media.getMimeType());
|
||||
} else if (config.isCompress && isHasImage && !config.isCheckOriginalImage) {
|
||||
List<LocalMedia> result = new ArrayList<>();
|
||||
result.add(media);
|
||||
compressImage(result);
|
||||
} else {
|
||||
List<LocalMedia> result = new ArrayList<>();
|
||||
result.add(media);
|
||||
onResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
switch (requestCode) {
|
||||
case PictureConfig.APPLY_STORAGE_PERMISSIONS_CODE:
|
||||
// Store Permissions
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
PermissionChecker.requestPermissions(this,
|
||||
new String[]{Manifest.permission.CAMERA}, PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE);
|
||||
} else {
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_jurisdiction));
|
||||
closeActivity();
|
||||
}
|
||||
break;
|
||||
case PictureConfig.APPLY_CAMERA_PERMISSIONS_CODE:
|
||||
// Camera Permissions
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
onTakePhoto();
|
||||
} else {
|
||||
closeActivity();
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_camera));
|
||||
}
|
||||
break;
|
||||
case PictureConfig.APPLY_RECORD_AUDIO_PERMISSIONS_CODE:
|
||||
// Recording Permissions
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
onTakePhoto();
|
||||
} else {
|
||||
closeActivity();
|
||||
ToastUtils.s(getContext(), getString(R.string.picture_audio));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
closeActivity();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.ExifInterface;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.tools.PictureFileUtils;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-12 13:13
|
||||
* @describe:PictureSelector对外提供的一些方法
|
||||
*/
|
||||
public class PictureSelectorExternalUtils {
|
||||
/**
|
||||
* 获取ExifInterface
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static ExifInterface getExifInterface(Context context, String url) {
|
||||
ExifInterface exifInterface = null;
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(url)) {
|
||||
inputStream = context.getContentResolver().openInputStream(Uri.parse(url));
|
||||
if (inputStream != null) {
|
||||
exifInterface = new ExifInterface(inputStream);
|
||||
}
|
||||
} else {
|
||||
exifInterface = new ExifInterface(url);
|
||||
}
|
||||
return exifInterface;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
PictureFileUtils.close(inputStream);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,387 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.luck.picture.lib.adapter.PictureWeChatPreviewGalleryAdapter;
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.decoration.GridSpacingItemDecoration;
|
||||
import com.luck.picture.lib.decoration.WrapContentLinearLayoutManager;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.tools.ScreenUtils;
|
||||
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-30 17:16
|
||||
* @describe:PictureSelector WeChatStyle
|
||||
*/
|
||||
public class PictureSelectorPreviewWeChatStyleActivity extends PicturePreviewActivity {
|
||||
/**
|
||||
* alpha duration
|
||||
*/
|
||||
private final static int ALPHA_DURATION = 300;
|
||||
private TextView mPictureSendView;
|
||||
private RecyclerView mRvGallery;
|
||||
private TextView tvSelected;
|
||||
private View bottomLine;
|
||||
private PictureWeChatPreviewGalleryAdapter mGalleryAdapter;
|
||||
|
||||
@Override
|
||||
public int getResourceId() {
|
||||
return R.layout.picture_wechat_style_preview;
|
||||
}
|
||||
|
||||
private void goneParent() {
|
||||
if (tvMediaNum.getVisibility() == View.VISIBLE) {
|
||||
tvMediaNum.setVisibility(View.GONE);
|
||||
}
|
||||
if (mTvPictureOk.getVisibility() == View.VISIBLE) {
|
||||
mTvPictureOk.setVisibility(View.GONE);
|
||||
}
|
||||
if (!TextUtils.isEmpty(check.getText())) {
|
||||
check.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initWidgets() {
|
||||
super.initWidgets();
|
||||
goneParent();
|
||||
mRvGallery = findViewById(R.id.rv_gallery);
|
||||
bottomLine = findViewById(R.id.bottomLine);
|
||||
tvSelected = findViewById(R.id.tv_selected);
|
||||
mPictureSendView = findViewById(R.id.picture_send);
|
||||
mPictureSendView.setOnClickListener(this);
|
||||
mPictureSendView.setText(getString(R.string.picture_send));
|
||||
mCbOriginal.setTextSize(16);
|
||||
mGalleryAdapter = new PictureWeChatPreviewGalleryAdapter(config);
|
||||
WrapContentLinearLayoutManager layoutManager = new WrapContentLinearLayoutManager(getContext());
|
||||
layoutManager.setOrientation(WrapContentLinearLayoutManager.HORIZONTAL);
|
||||
mRvGallery.setLayoutManager(layoutManager);
|
||||
mRvGallery.addItemDecoration(new GridSpacingItemDecoration(Integer.MAX_VALUE,
|
||||
ScreenUtils.dip2px(this, 8), false));
|
||||
mRvGallery.setAdapter(mGalleryAdapter);
|
||||
mGalleryAdapter.setItemClickListener((position, media, v) -> {
|
||||
if (viewPager != null && media != null) {
|
||||
if (isEqualsDirectory(media.getParentFolderName(), currentDirectory)) {
|
||||
int newPosition = isBottomPreview ? position : isShowCamera ? media.position - 1 : media.position;
|
||||
viewPager.setCurrentItem(newPosition);
|
||||
} else {
|
||||
// TODO The picture is not in the album directory, click invalid
|
||||
}
|
||||
}
|
||||
});
|
||||
if (isBottomPreview) {
|
||||
if (selectData != null && selectData.size() > position) {
|
||||
int size = selectData.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
LocalMedia media = selectData.get(i);
|
||||
media.setChecked(false);
|
||||
}
|
||||
LocalMedia media = selectData.get(position);
|
||||
media.setChecked(true);
|
||||
}
|
||||
} else {
|
||||
int size = selectData != null ? selectData.size() : 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
LocalMedia media = selectData.get(i);
|
||||
if (isEqualsDirectory(media.getParentFolderName(), currentDirectory)) {
|
||||
media.setChecked(isShowCamera ? media.position - 1 == position : media.position == position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it the same directory
|
||||
*
|
||||
* @param parentFolderName
|
||||
* @param currentDirectory
|
||||
* @return
|
||||
*/
|
||||
private boolean isEqualsDirectory(String parentFolderName, String currentDirectory) {
|
||||
return isBottomPreview
|
||||
|| TextUtils.isEmpty(parentFolderName)
|
||||
|| TextUtils.isEmpty(currentDirectory)
|
||||
|| currentDirectory.equals(getString(R.string.picture_camera_roll))
|
||||
|| parentFolderName.equals(currentDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPictureSelectorStyle() {
|
||||
super.initPictureSelectorStyle();
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureCompleteBackgroundStyle != 0) {
|
||||
mPictureSendView.setBackgroundResource(config.style.pictureCompleteBackgroundStyle);
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
|
||||
}
|
||||
if (config.style.pictureRightTextSize != 0) {
|
||||
mPictureSendView.setTextSize(config.style.pictureRightTextSize);
|
||||
}
|
||||
if (!TextUtils.isEmpty(config.style.pictureWeChatPreviewSelectedText)) {
|
||||
tvSelected.setText(config.style.pictureWeChatPreviewSelectedText);
|
||||
}
|
||||
if (config.style.pictureWeChatPreviewSelectedTextSize != 0) {
|
||||
tvSelected.setTextSize(config.style.pictureWeChatPreviewSelectedTextSize);
|
||||
}
|
||||
if (config.style.picturePreviewBottomBgColor != 0) {
|
||||
selectBarLayout.setBackgroundColor(config.style.picturePreviewBottomBgColor);
|
||||
} else {
|
||||
selectBarLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_half_grey));
|
||||
}
|
||||
if (config.style.pictureCompleteTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureCompleteTextColor);
|
||||
} else {
|
||||
if (config.style.pictureCancelTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureCancelTextColor);
|
||||
} else {
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
}
|
||||
}
|
||||
if (config.style.pictureOriginalFontColor == 0) {
|
||||
mCbOriginal.setTextColor(ContextCompat
|
||||
.getColor(this, R.color.picture_color_white));
|
||||
}
|
||||
if (config.style.pictureWeChatChooseStyle != 0) {
|
||||
check.setBackgroundResource(config.style.pictureWeChatChooseStyle);
|
||||
} else {
|
||||
check.setBackgroundResource(R.drawable.picture_wechat_select_cb);
|
||||
}
|
||||
if (config.isOriginalControl) {
|
||||
if (config.style.pictureOriginalControlStyle == 0) {
|
||||
mCbOriginal.setButtonDrawable(ContextCompat
|
||||
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
|
||||
}
|
||||
}
|
||||
if (config.style.pictureWeChatLeftBackStyle != 0) {
|
||||
pictureLeftBack.setImageResource(config.style.pictureWeChatLeftBackStyle);
|
||||
} else {
|
||||
pictureLeftBack.setImageResource(R.drawable.picture_icon_back);
|
||||
}
|
||||
if (!TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
|
||||
mPictureSendView.setText(config.style.pictureUnCompleteText);
|
||||
}
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
selectBarLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_half_grey));
|
||||
check.setBackgroundResource(R.drawable.picture_wechat_select_cb);
|
||||
pictureLeftBack.setImageResource(R.drawable.picture_icon_back);
|
||||
mCbOriginal.setTextColor(ContextCompat
|
||||
.getColor(this, R.color.picture_color_white));
|
||||
if (config.isOriginalControl) {
|
||||
mCbOriginal.setButtonDrawable(ContextCompat
|
||||
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
|
||||
}
|
||||
}
|
||||
|
||||
onSelectNumChange(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
super.onClick(v);
|
||||
int id = v.getId();
|
||||
if (id == R.id.picture_send) {
|
||||
boolean enable = selectData.size() != 0;
|
||||
if (enable) {
|
||||
mTvPictureOk.performClick();
|
||||
} else {
|
||||
btnCheck.performClick();
|
||||
boolean isNewEnableStatus = selectData.size() != 0;
|
||||
if (isNewEnableStatus) {
|
||||
mTvPictureOk.performClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUpdateSelectedChange(LocalMedia media) {
|
||||
onChangeMediaStatus(media);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSelectedChange(boolean isAddRemove, LocalMedia media) {
|
||||
if (isAddRemove) {
|
||||
media.setChecked(true);
|
||||
if (config.selectionMode == PictureConfig.SINGLE) {
|
||||
mGalleryAdapter.addSingleMediaToData(media);
|
||||
}
|
||||
} else {
|
||||
media.setChecked(false);
|
||||
mGalleryAdapter.removeMediaToData(media);
|
||||
if (isBottomPreview) {
|
||||
if (selectData != null && selectData.size() > position) {
|
||||
selectData.get(position).setChecked(true);
|
||||
}
|
||||
if (mGalleryAdapter.isDataEmpty()) {
|
||||
onActivityBackPressed();
|
||||
} else {
|
||||
int currentItem = viewPager.getCurrentItem();
|
||||
adapter.remove(currentItem);
|
||||
adapter.removeCacheView(currentItem);
|
||||
position = currentItem;
|
||||
tvTitle.setText(getString(R.string.picture_preview_image_num,
|
||||
position + 1, adapter.getSize()));
|
||||
check.setSelected(true);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
int itemCount = mGalleryAdapter.getItemCount();
|
||||
if (itemCount > 5) {
|
||||
mRvGallery.smoothScrollToPosition(itemCount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPageSelectedChange(LocalMedia media) {
|
||||
super.onPageSelectedChange(media);
|
||||
goneParent();
|
||||
if (!config.previewEggs) {
|
||||
onChangeMediaStatus(media);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* onChangeMediaStatus
|
||||
*
|
||||
* @param media
|
||||
*/
|
||||
private void onChangeMediaStatus(LocalMedia media) {
|
||||
if (mGalleryAdapter != null) {
|
||||
int itemCount = mGalleryAdapter.getItemCount();
|
||||
if (itemCount > 0) {
|
||||
boolean isChangeData = false;
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
LocalMedia item = mGalleryAdapter.getItem(i);
|
||||
if (item == null || TextUtils.isEmpty(item.getPath())) {
|
||||
continue;
|
||||
}
|
||||
boolean isOldChecked = item.isChecked();
|
||||
boolean isNewChecked = item.getPath().equals(media.getPath()) || item.getId() == media.getId();
|
||||
if (!isChangeData) {
|
||||
isChangeData = (isOldChecked && !isNewChecked) || (!isOldChecked && isNewChecked);
|
||||
}
|
||||
item.setChecked(isNewChecked);
|
||||
}
|
||||
if (isChangeData) {
|
||||
mGalleryAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSelectNumChange(boolean isRefresh) {
|
||||
if (mPictureSendView == null) {
|
||||
return;
|
||||
}
|
||||
goneParent();
|
||||
boolean enable = selectData.size() != 0;
|
||||
if (enable) {
|
||||
initCompleteText(selectData.size());
|
||||
if (mRvGallery.getVisibility() == View.GONE) {
|
||||
mRvGallery.animate().alpha(1).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
|
||||
mRvGallery.setVisibility(View.VISIBLE);
|
||||
bottomLine.animate().alpha(1).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
|
||||
bottomLine.setVisibility(View.VISIBLE);
|
||||
// 重置一片内存区域 不然在其他地方添加也影响这里的数量
|
||||
mGalleryAdapter.setNewData(selectData);
|
||||
}
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureCompleteTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureCompleteTextColor);
|
||||
}
|
||||
if (config.style.pictureCompleteBackgroundStyle != 0) {
|
||||
mPictureSendView.setBackgroundResource(config.style.pictureCompleteBackgroundStyle);
|
||||
}
|
||||
} else {
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
|
||||
}
|
||||
} else {
|
||||
if (config.style != null && !TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
|
||||
mPictureSendView.setText(config.style.pictureUnCompleteText);
|
||||
} else {
|
||||
mPictureSendView.setText(getString(R.string.picture_send));
|
||||
}
|
||||
mRvGallery.animate().alpha(0).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
|
||||
mRvGallery.setVisibility(View.GONE);
|
||||
bottomLine.animate().alpha(0).setDuration(ALPHA_DURATION).setInterpolator(new AccelerateInterpolator());
|
||||
bottomLine.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* initCompleteText
|
||||
*/
|
||||
@Override
|
||||
protected void initCompleteText(int startCount) {
|
||||
boolean isNotEmptyStyle = config.style != null;
|
||||
if (config.isWithVideoImage) {
|
||||
// 混选模式
|
||||
if (config.selectionMode == PictureConfig.SINGLE) {
|
||||
if (startCount <= 0) {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText : getString(R.string.picture_send));
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, selectData.size(), 1));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
|
||||
? config.style.pictureCompleteText : getString(R.string.picture_send));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText,
|
||||
selectData.size(), config.maxSelectNum));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText : getString(R.string.picture_send_num, selectData.size(),
|
||||
config.maxSelectNum));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String mimeType = selectData.get(0).getMimeType();
|
||||
int maxSize = PictureMimeType.isHasVideo(mimeType) && config.maxVideoSelectNum > 0 ? config.maxVideoSelectNum : config.maxSelectNum;
|
||||
if (config.selectionMode == PictureConfig.SINGLE) {
|
||||
if (startCount <= 0) {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText : getString(R.string.picture_send));
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, selectData.size(),
|
||||
1));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
|
||||
? config.style.pictureCompleteText : getString(R.string.picture_send));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, selectData.size(), maxSize));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText
|
||||
: getString(R.string.picture_send_num, selectData.size(), maxSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,286 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.tools.AttrsUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-30 13:27
|
||||
* @describe:PictureSelector WeChatStyle
|
||||
*/
|
||||
public class PictureSelectorWeChatStyleActivity extends PictureSelectorActivity {
|
||||
private TextView mPictureSendView;
|
||||
private RelativeLayout rlAlbum;
|
||||
|
||||
|
||||
@Override
|
||||
public int getResourceId() {
|
||||
return R.layout.picture_wechat_style_selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initWidgets() {
|
||||
super.initWidgets();
|
||||
rlAlbum = findViewById(R.id.rlAlbum);
|
||||
mPictureSendView = findViewById(R.id.picture_send);
|
||||
mPictureSendView.setOnClickListener(this);
|
||||
mPictureSendView.setText(getString(R.string.picture_send));
|
||||
mTvPicturePreview.setTextSize(16);
|
||||
mCbOriginal.setTextSize(16);
|
||||
boolean isChooseMode = config.selectionMode ==
|
||||
PictureConfig.SINGLE && config.isSingleDirectReturn;
|
||||
mPictureSendView.setVisibility(isChooseMode ? View.GONE : View.VISIBLE);
|
||||
if (rlAlbum.getLayoutParams() != null
|
||||
&& rlAlbum.getLayoutParams() instanceof RelativeLayout.LayoutParams) {
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) rlAlbum.getLayoutParams();
|
||||
if (isChooseMode) {
|
||||
lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
|
||||
} else {
|
||||
lp.addRule(RelativeLayout.RIGHT_OF, R.id.pictureLeftBack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initPictureSelectorStyle() {
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureUnCompleteBackgroundStyle != 0) {
|
||||
mPictureSendView.setBackgroundResource(config.style.pictureUnCompleteBackgroundStyle);
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
|
||||
}
|
||||
if (config.style.pictureBottomBgColor != 0) {
|
||||
mBottomLayout.setBackgroundColor(config.style.pictureBottomBgColor);
|
||||
} else {
|
||||
mBottomLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_grey));
|
||||
}
|
||||
if (config.style.pictureUnCompleteTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureUnCompleteTextColor);
|
||||
} else {
|
||||
if (config.style.pictureCancelTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureCancelTextColor);
|
||||
} else {
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
|
||||
}
|
||||
}
|
||||
if (config.style.pictureRightTextSize != 0) {
|
||||
mPictureSendView.setTextSize(config.style.pictureRightTextSize);
|
||||
}
|
||||
if (config.style.pictureOriginalFontColor == 0) {
|
||||
mCbOriginal.setTextColor(ContextCompat
|
||||
.getColor(this, R.color.picture_color_white));
|
||||
}
|
||||
if (config.isOriginalControl) {
|
||||
if (config.style.pictureOriginalControlStyle == 0) {
|
||||
mCbOriginal.setButtonDrawable(ContextCompat
|
||||
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
|
||||
}
|
||||
}
|
||||
if (config.style.pictureContainerBackgroundColor != 0) {
|
||||
container.setBackgroundColor(config.style.pictureContainerBackgroundColor);
|
||||
}
|
||||
|
||||
if (config.style.pictureWeChatTitleBackgroundStyle != 0) {
|
||||
rlAlbum.setBackgroundResource(config.style.pictureWeChatTitleBackgroundStyle);
|
||||
} else {
|
||||
rlAlbum.setBackgroundResource(R.drawable.picture_album_bg);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
|
||||
mPictureSendView.setText(config.style.pictureUnCompleteText);
|
||||
}
|
||||
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
|
||||
rlAlbum.setBackgroundResource(R.drawable.picture_album_bg);
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
|
||||
int pictureBottomBgColor = AttrsUtils.getTypeValueColor(getContext(), R.attr.picture_bottom_bg);
|
||||
mBottomLayout.setBackgroundColor(pictureBottomBgColor != 0
|
||||
? pictureBottomBgColor : ContextCompat.getColor(getContext(), R.color.picture_color_grey));
|
||||
|
||||
mCbOriginal.setTextColor(ContextCompat
|
||||
.getColor(this, R.color.picture_color_white));
|
||||
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.picture_icon_wechat_down);
|
||||
mIvArrow.setImageDrawable(drawable);
|
||||
if (config.isOriginalControl) {
|
||||
mCbOriginal.setButtonDrawable(ContextCompat
|
||||
.getDrawable(this, R.drawable.picture_original_wechat_checkbox));
|
||||
}
|
||||
}
|
||||
super.initPictureSelectorStyle();
|
||||
goneParentView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide views that are not needed by the parent container
|
||||
*/
|
||||
private void goneParentView() {
|
||||
mTvPictureRight.setVisibility(View.GONE);
|
||||
mTvPictureImgNum.setVisibility(View.GONE);
|
||||
mTvPictureOk.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void changeImageNumber(List<LocalMedia> selectData) {
|
||||
if (mPictureSendView == null) {
|
||||
return;
|
||||
}
|
||||
int size = selectData.size();
|
||||
boolean enable = size != 0;
|
||||
if (enable) {
|
||||
mPictureSendView.setEnabled(true);
|
||||
mPictureSendView.setSelected(true);
|
||||
mTvPicturePreview.setEnabled(true);
|
||||
mTvPicturePreview.setSelected(true);
|
||||
initCompleteText(selectData);
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureCompleteBackgroundStyle != 0) {
|
||||
mPictureSendView.setBackgroundResource(config.style.pictureCompleteBackgroundStyle);
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
|
||||
}
|
||||
if (config.style.pictureCompleteTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureCompleteTextColor);
|
||||
} else {
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
}
|
||||
if (config.style.picturePreviewTextColor != 0) {
|
||||
mTvPicturePreview.setTextColor(config.style.picturePreviewTextColor);
|
||||
} else {
|
||||
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
}
|
||||
if (!TextUtils.isEmpty(config.style.picturePreviewText)) {
|
||||
mTvPicturePreview.setText(config.style.picturePreviewText);
|
||||
} else {
|
||||
mTvPicturePreview.setText(getString(R.string.picture_preview_num, size));
|
||||
}
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_bg);
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_white));
|
||||
mTvPicturePreview.setText(getString(R.string.picture_preview_num, size));
|
||||
}
|
||||
} else {
|
||||
mPictureSendView.setEnabled(false);
|
||||
mPictureSendView.setSelected(false);
|
||||
mTvPicturePreview.setEnabled(false);
|
||||
mTvPicturePreview.setSelected(false);
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureUnCompleteBackgroundStyle != 0) {
|
||||
mPictureSendView.setBackgroundResource(config.style.pictureUnCompleteBackgroundStyle);
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
|
||||
}
|
||||
if (config.style.pictureUnCompleteTextColor != 0) {
|
||||
mPictureSendView.setTextColor(config.style.pictureUnCompleteTextColor);
|
||||
} else {
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
|
||||
}
|
||||
if (config.style.pictureUnPreviewTextColor != 0) {
|
||||
mTvPicturePreview.setTextColor(config.style.pictureUnPreviewTextColor);
|
||||
} else {
|
||||
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_9b));
|
||||
}
|
||||
if (!TextUtils.isEmpty(config.style.pictureUnCompleteText)) {
|
||||
mPictureSendView.setText(config.style.pictureUnCompleteText);
|
||||
} else {
|
||||
mPictureSendView.setText(getString(R.string.picture_send));
|
||||
}
|
||||
if (!TextUtils.isEmpty(config.style.pictureUnPreviewText)) {
|
||||
mTvPicturePreview.setText(config.style.pictureUnPreviewText);
|
||||
} else {
|
||||
mTvPicturePreview.setText(getString(R.string.picture_preview));
|
||||
}
|
||||
} else {
|
||||
mPictureSendView.setBackgroundResource(R.drawable.picture_send_button_default_bg);
|
||||
mPictureSendView.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_53575e));
|
||||
mTvPicturePreview.setTextColor(ContextCompat.getColor(getContext(), R.color.picture_color_9b));
|
||||
mTvPicturePreview.setText(getString(R.string.picture_preview));
|
||||
mPictureSendView.setText(getString(R.string.picture_send));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
super.onClick(v);
|
||||
int id = v.getId();
|
||||
if (id == R.id.picture_send) {
|
||||
if (folderWindow != null
|
||||
&& folderWindow.isShowing()) {
|
||||
folderWindow.dismiss();
|
||||
} else {
|
||||
mTvPictureOk.performClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangeData(List<LocalMedia> list) {
|
||||
super.onChangeData(list);
|
||||
initCompleteText(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCompleteText(List<LocalMedia> list) {
|
||||
int size = list.size();
|
||||
boolean isNotEmptyStyle = config.style != null;
|
||||
if (config.isWithVideoImage) {
|
||||
if (config.selectionMode == PictureConfig.SINGLE) {
|
||||
if (size <= 0) {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText : getString(R.string.picture_send));
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, 1));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
|
||||
? config.style.pictureCompleteText : getString(R.string.picture_send));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, config.maxSelectNum));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText : getString(R.string.picture_send_num, size, config.maxSelectNum));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String mimeType = list.get(0).getMimeType();
|
||||
int maxSize = PictureMimeType.isHasVideo(mimeType) && config.maxVideoSelectNum > 0 ? config.maxVideoSelectNum : config.maxSelectNum;
|
||||
if (config.selectionMode == PictureConfig.SINGLE) {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, 1));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureCompleteText)
|
||||
? config.style.pictureCompleteText : getString(R.string.picture_send));
|
||||
}
|
||||
} else {
|
||||
boolean isCompleteReplaceNum = isNotEmptyStyle && config.style.isCompleteReplaceNum;
|
||||
if (isCompleteReplaceNum && !TextUtils.isEmpty(config.style.pictureCompleteText)) {
|
||||
mPictureSendView.setText(String.format(config.style.pictureCompleteText, size, maxSize));
|
||||
} else {
|
||||
mPictureSendView.setText(isNotEmptyStyle && !TextUtils.isEmpty(config.style.pictureUnCompleteText)
|
||||
? config.style.pictureUnCompleteText : getString(R.string.picture_send_num, size, maxSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
package com.luck.picture.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.MediaController;
|
||||
import android.widget.TextView;
|
||||
import android.widget.VideoView;
|
||||
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2017/8/28 下午11:00
|
||||
* @描述: 视频播放类
|
||||
*/
|
||||
public class PictureVideoPlayActivity extends PictureBaseActivity implements
|
||||
MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener,
|
||||
MediaPlayer.OnCompletionListener, View.OnClickListener {
|
||||
private String videoPath;
|
||||
private ImageButton ibLeftBack;
|
||||
private MediaController mMediaController;
|
||||
private VideoView mVideoView;
|
||||
private TextView tvConfirm;
|
||||
private ImageView iv_play;
|
||||
private int mPositionWhenPaused = -1;
|
||||
|
||||
@Override
|
||||
public boolean isImmersive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestedOrientation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResourceId() {
|
||||
return R.layout.picture_activity_video_play;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initPictureSelectorStyle() {
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureLeftBackIcon != 0) {
|
||||
ibLeftBack.setImageResource(config.style.pictureLeftBackIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initWidgets() {
|
||||
super.initWidgets();
|
||||
videoPath = getIntent().getStringExtra(PictureConfig.EXTRA_VIDEO_PATH);
|
||||
boolean isExternalPreview = getIntent().getBooleanExtra
|
||||
(PictureConfig.EXTRA_PREVIEW_VIDEO, false);
|
||||
if (TextUtils.isEmpty(videoPath)) {
|
||||
LocalMedia media = getIntent().getParcelableExtra(PictureConfig.EXTRA_MEDIA_KEY);
|
||||
if (media == null || TextUtils.isEmpty(media.getPath())) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
videoPath = media.getPath();
|
||||
}
|
||||
if (TextUtils.isEmpty(videoPath)) {
|
||||
closeActivity();
|
||||
return;
|
||||
}
|
||||
ibLeftBack = findViewById(R.id.pictureLeftBack);
|
||||
mVideoView = findViewById(R.id.video_view);
|
||||
tvConfirm = findViewById(R.id.tv_confirm);
|
||||
mVideoView.setBackgroundColor(Color.BLACK);
|
||||
iv_play = findViewById(R.id.iv_play);
|
||||
mMediaController = new MediaController(this);
|
||||
mVideoView.setOnCompletionListener(this);
|
||||
mVideoView.setOnPreparedListener(this);
|
||||
mVideoView.setMediaController(mMediaController);
|
||||
ibLeftBack.setOnClickListener(this);
|
||||
iv_play.setOnClickListener(this);
|
||||
tvConfirm.setOnClickListener(this);
|
||||
|
||||
tvConfirm.setVisibility(config.selectionMode
|
||||
== PictureConfig.SINGLE
|
||||
&& config.enPreviewVideo && !isExternalPreview ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
// Play Video
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(videoPath)) {
|
||||
mVideoView.setVideoURI(Uri.parse(videoPath));
|
||||
} else {
|
||||
mVideoView.setVideoPath(videoPath);
|
||||
}
|
||||
mVideoView.start();
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
// Stop video when the activity is pause.
|
||||
mPositionWhenPaused = mVideoView.getCurrentPosition();
|
||||
mVideoView.stopPlayback();
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mMediaController = null;
|
||||
mVideoView = null;
|
||||
iv_play = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
// Resume video player
|
||||
if (mPositionWhenPaused >= 0) {
|
||||
mVideoView.seekTo(mPositionWhenPaused);
|
||||
mPositionWhenPaused = -1;
|
||||
}
|
||||
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onError(MediaPlayer player, int arg1, int arg2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
if (null != iv_play) {
|
||||
iv_play.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
if (id == R.id.pictureLeftBack) {
|
||||
onBackPressed();
|
||||
} else if (id == R.id.iv_play) {
|
||||
mVideoView.start();
|
||||
iv_play.setVisibility(View.INVISIBLE);
|
||||
} else if (id == R.id.tv_confirm) {
|
||||
List<LocalMedia> result = new ArrayList<>();
|
||||
result.add(getIntent().getParcelableExtra(PictureConfig.EXTRA_MEDIA_KEY));
|
||||
setResult(RESULT_OK, new Intent()
|
||||
.putParcelableArrayListExtra(PictureConfig.EXTRA_SELECT_LIST,
|
||||
(ArrayList<? extends Parcelable>) result));
|
||||
onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (config.windowAnimationStyle != null
|
||||
&& config.windowAnimationStyle.activityPreviewExitAnimation != 0) {
|
||||
finish();
|
||||
overridePendingTransition(0, config.windowAnimationStyle != null
|
||||
&& config.windowAnimationStyle.activityPreviewExitAnimation != 0 ?
|
||||
config.windowAnimationStyle.activityPreviewExitAnimation : R.anim.picture_anim_exit);
|
||||
} else {
|
||||
closeActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context newBase) {
|
||||
super.attachBaseContext(new ContextWrapper(newBase) {
|
||||
@Override
|
||||
public Object getSystemService(String name) {
|
||||
if (Context.AUDIO_SERVICE.equals(name)) {
|
||||
return getApplicationContext().getSystemService(name);
|
||||
}
|
||||
return super.getSystemService(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mp.setOnInfoListener((mp1, what, extra) -> {
|
||||
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
|
||||
// video started
|
||||
mVideoView.setBackgroundColor(Color.TRANSPARENT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package com.luck.picture.lib.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.entity.LocalMediaFolder;
|
||||
import com.luck.picture.lib.listener.OnAlbumItemClickListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2016-12-11 17:02
|
||||
* @describe:PictureAlbumDirectoryAdapter
|
||||
*/
|
||||
public class PictureAlbumDirectoryAdapter extends RecyclerView.Adapter<PictureAlbumDirectoryAdapter.ViewHolder> {
|
||||
private List<LocalMediaFolder> folders = new ArrayList<>();
|
||||
private int chooseMode;
|
||||
private PictureSelectionConfig config;
|
||||
|
||||
public PictureAlbumDirectoryAdapter(PictureSelectionConfig config) {
|
||||
super();
|
||||
this.config = config;
|
||||
this.chooseMode = config.chooseMode;
|
||||
}
|
||||
|
||||
public void bindFolderData(List<LocalMediaFolder> folders) {
|
||||
this.folders = folders == null ? new ArrayList<>() : folders;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setChooseMode(int chooseMode) {
|
||||
this.chooseMode = chooseMode;
|
||||
}
|
||||
|
||||
public List<LocalMediaFolder> getFolderData() {
|
||||
return folders == null ? new ArrayList<>() : folders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.picture_album_folder_item, parent, false);
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
final LocalMediaFolder folder = folders.get(position);
|
||||
String name = folder.getName();
|
||||
int imageNum = folder.getImageNum();
|
||||
String imagePath = folder.getFirstImagePath();
|
||||
boolean isChecked = folder.isChecked();
|
||||
int checkedNum = folder.getCheckedNum();
|
||||
holder.tvSign.setVisibility(checkedNum > 0 ? View.VISIBLE : View.INVISIBLE);
|
||||
holder.itemView.setSelected(isChecked);
|
||||
if (config.style != null && config.style.pictureAlbumStyle != 0) {
|
||||
holder.itemView.setBackgroundResource(config.style.pictureAlbumStyle);
|
||||
}
|
||||
if (chooseMode == PictureMimeType.ofAudio()) {
|
||||
holder.ivFirstImage.setImageResource(R.drawable.picture_audio_placeholder);
|
||||
} else {
|
||||
if (PictureSelectionConfig.imageEngine != null) {
|
||||
PictureSelectionConfig.imageEngine.loadFolderImage(holder.itemView.getContext(),
|
||||
imagePath, holder.ivFirstImage);
|
||||
}
|
||||
}
|
||||
Context context = holder.itemView.getContext();
|
||||
String firstTitle = folder.getOfAllType() != -1 ? folder.getOfAllType() == PictureMimeType.ofAudio() ?
|
||||
context.getString(R.string.picture_all_audio)
|
||||
: context.getString(R.string.picture_camera_roll) : name;
|
||||
holder.tvFolderName.setText(context.getString(R.string.picture_camera_roll_num, firstTitle, imageNum));
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (onAlbumItemClickListener != null) {
|
||||
int size = folders.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
LocalMediaFolder mediaFolder = folders.get(i);
|
||||
mediaFolder.setChecked(false);
|
||||
}
|
||||
folder.setChecked(true);
|
||||
notifyDataSetChanged();
|
||||
onAlbumItemClickListener.onItemClick(position, folder.isCameraFolder(), folder.getBucketId(), folder.getName(), folder.getData());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return folders.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView ivFirstImage;
|
||||
TextView tvFolderName, tvSign;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ivFirstImage = itemView.findViewById(R.id.first_image);
|
||||
tvFolderName = itemView.findViewById(R.id.tv_folder_name);
|
||||
tvSign = itemView.findViewById(R.id.tv_sign);
|
||||
if (config.style != null && config.style.pictureFolderCheckedDotStyle != 0) {
|
||||
tvSign.setBackgroundResource(config.style.pictureFolderCheckedDotStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private OnAlbumItemClickListener onAlbumItemClickListener;
|
||||
|
||||
public void setOnAlbumItemClickListener(OnAlbumItemClickListener listener) {
|
||||
this.onAlbumItemClickListener = listener;
|
||||
}
|
||||
}
|
@ -0,0 +1,682 @@
|
||||
package com.luck.picture.lib.adapter;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.dialog.PictureCustomDialog;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.listener.OnPhotoSelectChangedListener;
|
||||
import com.luck.picture.lib.tools.AnimUtils;
|
||||
import com.luck.picture.lib.tools.DateUtils;
|
||||
import com.luck.picture.lib.tools.MediaUtils;
|
||||
import com.luck.picture.lib.tools.PictureFileUtils;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
import com.luck.picture.lib.tools.StringUtils;
|
||||
import com.luck.picture.lib.tools.ToastUtils;
|
||||
import com.luck.picture.lib.tools.VoiceUtils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2016-12-30 12:02
|
||||
* @describe:PictureImageGridAdapter
|
||||
*/
|
||||
public class PictureImageGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private boolean showCamera;
|
||||
private OnPhotoSelectChangedListener imageSelectChangedListener;
|
||||
private List<LocalMedia> data = new ArrayList<>();
|
||||
private List<LocalMedia> selectData = new ArrayList<>();
|
||||
private PictureSelectionConfig config;
|
||||
|
||||
public PictureImageGridAdapter(Context context, PictureSelectionConfig config) {
|
||||
this.context = context;
|
||||
this.config = config;
|
||||
this.showCamera = config.isCamera;
|
||||
}
|
||||
|
||||
public void setShowCamera(boolean showCamera) {
|
||||
this.showCamera = showCamera;
|
||||
}
|
||||
|
||||
public boolean isShowCamera() {
|
||||
return showCamera;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量刷新
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
public void bindData(List<LocalMedia> data) {
|
||||
this.data = data == null ? new ArrayList<>() : data;
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
public void bindSelectData(List<LocalMedia> images) {
|
||||
// 这里重新构构造一个新集合,不然会产生已选集合一变,结果集合也会添加的问题
|
||||
List<LocalMedia> selection = new ArrayList<>();
|
||||
int size = images.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
LocalMedia media = images.get(i);
|
||||
selection.add(media);
|
||||
}
|
||||
this.selectData = selection;
|
||||
if (!config.isSingleDirectReturn) {
|
||||
subSelectPosition();
|
||||
if (imageSelectChangedListener != null) {
|
||||
imageSelectChangedListener.onChange(selectData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<LocalMedia> getSelectedData() {
|
||||
return selectData == null ? new ArrayList<>() : selectData;
|
||||
}
|
||||
|
||||
public int getSelectedSize() {
|
||||
return selectData == null ? 0 : selectData.size();
|
||||
}
|
||||
|
||||
public List<LocalMedia> getData() {
|
||||
return data == null ? new ArrayList<>() : data;
|
||||
}
|
||||
|
||||
public boolean isDataEmpty() {
|
||||
return data == null || data.size() == 0;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (getSize() > 0) {
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return data == null ? 0 : data.size();
|
||||
}
|
||||
|
||||
public LocalMedia getItem(int position) {
|
||||
return getSize() > 0 ? data.get(position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (showCamera && position == 0) {
|
||||
return PictureConfig.TYPE_CAMERA;
|
||||
} else {
|
||||
return PictureConfig.TYPE_PICTURE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (viewType == PictureConfig.TYPE_CAMERA) {
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.picture_item_camera, parent, false);
|
||||
return new CameraViewHolder(view);
|
||||
} else {
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.picture_image_grid_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NotNull final RecyclerView.ViewHolder holder, final int position) {
|
||||
if (getItemViewType(position) == PictureConfig.TYPE_CAMERA) {
|
||||
CameraViewHolder headerHolder = (CameraViewHolder) holder;
|
||||
headerHolder.headerView.setOnClickListener(v -> {
|
||||
if (imageSelectChangedListener != null) {
|
||||
imageSelectChangedListener.onTakePhoto();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final ViewHolder contentHolder = (ViewHolder) holder;
|
||||
final LocalMedia image = data.get(showCamera ? position - 1 : position);
|
||||
image.position = contentHolder.getAdapterPosition();
|
||||
final String path = image.getPath();
|
||||
final String mimeType = image.getMimeType();
|
||||
if (config.checkNumMode) {
|
||||
notifyCheckChanged(contentHolder, image);
|
||||
}
|
||||
if (config.isSingleDirectReturn) {
|
||||
contentHolder.tvCheck.setVisibility(View.GONE);
|
||||
contentHolder.btnCheck.setVisibility(View.GONE);
|
||||
} else {
|
||||
selectImage(contentHolder, isSelected(image));
|
||||
contentHolder.tvCheck.setVisibility(View.VISIBLE);
|
||||
contentHolder.btnCheck.setVisibility(View.VISIBLE);
|
||||
// 启用了蒙层效果
|
||||
if (config.isMaxSelectEnabledMask) {
|
||||
dispatchHandleMask(contentHolder, image);
|
||||
}
|
||||
}
|
||||
contentHolder.tvIsGif.setVisibility(PictureMimeType.isGif(mimeType) ? View.VISIBLE : View.GONE);
|
||||
if (PictureMimeType.isHasImage(image.getMimeType())) {
|
||||
if (image.loadLongImageStatus == PictureConfig.NORMAL) {
|
||||
image.isLongImage = MediaUtils.isLongImg(image);
|
||||
image.loadLongImageStatus = PictureConfig.LOADED;
|
||||
}
|
||||
contentHolder.tvLongChart.setVisibility(image.isLongImage ? View.VISIBLE : View.GONE);
|
||||
} else {
|
||||
image.loadLongImageStatus = PictureConfig.NORMAL;
|
||||
contentHolder.tvLongChart.setVisibility(View.GONE);
|
||||
}
|
||||
boolean isHasVideo = PictureMimeType.isHasVideo(mimeType);
|
||||
if (isHasVideo || PictureMimeType.isHasAudio(mimeType)) {
|
||||
contentHolder.tvDuration.setVisibility(View.VISIBLE);
|
||||
contentHolder.tvDuration.setText(DateUtils.formatDurationTime(image.getDuration()));
|
||||
contentHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds
|
||||
(isHasVideo ? R.drawable.picture_icon_video : R.drawable.picture_icon_audio,
|
||||
0, 0, 0);
|
||||
} else {
|
||||
contentHolder.tvDuration.setVisibility(View.GONE);
|
||||
}
|
||||
if (config.chooseMode == PictureMimeType.ofAudio()) {
|
||||
contentHolder.ivPicture.setImageResource(R.drawable.picture_audio_placeholder);
|
||||
} else {
|
||||
if (PictureSelectionConfig.imageEngine != null) {
|
||||
PictureSelectionConfig.imageEngine.loadGridImage(context, path, contentHolder.ivPicture);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.enablePreview || config.enPreviewVideo || config.enablePreviewAudio) {
|
||||
contentHolder.btnCheck.setOnClickListener(v -> {
|
||||
if (config.isMaxSelectEnabledMask) {
|
||||
if (!contentHolder.tvCheck.isSelected() && getSelectedSize() >= config.maxSelectNum) {
|
||||
String msg = StringUtils.getMsg(context, config.chooseMode == PictureMimeType.ofAll() ? null : image.getMimeType(), config.maxSelectNum);
|
||||
showPromptDialog(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If the original path does not exist or the path does exist but the file does not exist
|
||||
String newPath = image.getRealPath();
|
||||
if (!TextUtils.isEmpty(newPath) && !new File(newPath).exists()) {
|
||||
ToastUtils.s(context, PictureMimeType.s(context, mimeType));
|
||||
return;
|
||||
}
|
||||
// The width and height of the image are reversed if there is rotation information
|
||||
MediaUtils.setOrientationAsynchronous(context, image, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH, null);
|
||||
changeCheckboxState(contentHolder, image);
|
||||
});
|
||||
}
|
||||
contentHolder.contentView.setOnClickListener(v -> {
|
||||
if (config.isMaxSelectEnabledMask) {
|
||||
if (image.isMaxSelectEnabledMask()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If the original path does not exist or the path does exist but the file does not exist
|
||||
String newPath = image.getRealPath();
|
||||
if (!TextUtils.isEmpty(newPath) && !new File(newPath).exists()) {
|
||||
ToastUtils.s(context, PictureMimeType.s(context, mimeType));
|
||||
return;
|
||||
}
|
||||
int index = showCamera ? position - 1 : position;
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
// The width and height of the image are reversed if there is rotation information
|
||||
MediaUtils.setOrientationAsynchronous(context, image, config.isAndroidQChangeWH, config.isAndroidQChangeVideoWH, null);
|
||||
boolean eqResult =
|
||||
PictureMimeType.isHasImage(mimeType) && config.enablePreview
|
||||
|| PictureMimeType.isHasVideo(mimeType) && (config.enPreviewVideo
|
||||
|| config.selectionMode == PictureConfig.SINGLE)
|
||||
|| PictureMimeType.isHasAudio(mimeType) && (config.enablePreviewAudio
|
||||
|| config.selectionMode == PictureConfig.SINGLE);
|
||||
if (eqResult) {
|
||||
if (PictureMimeType.isHasVideo(image.getMimeType())) {
|
||||
if (config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
|
||||
// The video is less than the minimum specified length
|
||||
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
|
||||
return;
|
||||
}
|
||||
if (config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
|
||||
// The length of the video exceeds the specified length
|
||||
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
|
||||
return;
|
||||
}
|
||||
}
|
||||
imageSelectChangedListener.onPictureClick(image, index);
|
||||
} else {
|
||||
changeCheckboxState(contentHolder, image);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mask effects
|
||||
*
|
||||
* @param contentHolder
|
||||
* @param item
|
||||
*/
|
||||
private void dispatchHandleMask(ViewHolder contentHolder, LocalMedia item) {
|
||||
if (config.isWithVideoImage && config.maxVideoSelectNum > 0) {
|
||||
if (getSelectedSize() >= config.maxSelectNum) {
|
||||
boolean isSelected = contentHolder.tvCheck.isSelected();
|
||||
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, isSelected ? R.color.picture_color_80 : R.color.picture_color_half_white), PorterDuff.Mode.SRC_ATOP);
|
||||
item.setMaxSelectEnabledMask(!isSelected);
|
||||
} else {
|
||||
item.setMaxSelectEnabledMask(false);
|
||||
}
|
||||
} else {
|
||||
LocalMedia media = selectData.size() > 0 ? selectData.get(0) : null;
|
||||
if (media != null) {
|
||||
boolean isSelected = contentHolder.tvCheck.isSelected();
|
||||
if (config.chooseMode == PictureMimeType.ofAll()) {
|
||||
if (PictureMimeType.isHasImage(media.getMimeType())) {
|
||||
// All videos are not optional
|
||||
if (!isSelected && !PictureMimeType.isHasImage(item.getMimeType())) {
|
||||
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, PictureMimeType.isHasVideo(item.getMimeType()) ? R.color.picture_color_half_white : R.color.picture_color_20), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
item.setMaxSelectEnabledMask(PictureMimeType.isHasVideo(item.getMimeType()));
|
||||
} else if (PictureMimeType.isHasVideo(media.getMimeType())) {
|
||||
// All images are not optional
|
||||
if (!isSelected && !PictureMimeType.isHasVideo(item.getMimeType())) {
|
||||
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, PictureMimeType.isHasImage(item.getMimeType()) ? R.color.picture_color_half_white : R.color.picture_color_20), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
item.setMaxSelectEnabledMask(PictureMimeType.isHasImage(item.getMimeType()));
|
||||
}
|
||||
} else {
|
||||
if (config.chooseMode == PictureMimeType.ofVideo() && config.maxVideoSelectNum > 0) {
|
||||
if (!isSelected && getSelectedSize() == config.maxVideoSelectNum) {
|
||||
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, R.color.picture_color_half_white), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
item.setMaxSelectEnabledMask(!isSelected && getSelectedSize() == config.maxVideoSelectNum);
|
||||
} else {
|
||||
if (!isSelected && getSelectedSize() == config.maxSelectNum) {
|
||||
contentHolder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, R.color.picture_color_half_white), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
item.setMaxSelectEnabledMask(!isSelected && getSelectedSize() == config.maxSelectNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return showCamera ? data.size() + 1 : data.size();
|
||||
}
|
||||
|
||||
public class CameraViewHolder extends RecyclerView.ViewHolder {
|
||||
View headerView;
|
||||
TextView tvCamera;
|
||||
|
||||
public CameraViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
headerView = itemView;
|
||||
tvCamera = itemView.findViewById(R.id.tvCamera);
|
||||
String title = config.chooseMode == PictureMimeType.ofAudio() ?
|
||||
context.getString(R.string.picture_tape)
|
||||
: context.getString(R.string.picture_take_picture);
|
||||
tvCamera.setText(title);
|
||||
}
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView ivPicture;
|
||||
TextView tvCheck;
|
||||
TextView tvDuration, tvIsGif, tvLongChart;
|
||||
View contentView;
|
||||
View btnCheck;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
contentView = itemView;
|
||||
ivPicture = itemView.findViewById(R.id.ivPicture);
|
||||
tvCheck = itemView.findViewById(R.id.tvCheck);
|
||||
btnCheck = itemView.findViewById(R.id.btnCheck);
|
||||
tvDuration = itemView.findViewById(R.id.tv_duration);
|
||||
tvIsGif = itemView.findViewById(R.id.tv_isGif);
|
||||
tvLongChart = itemView.findViewById(R.id.tv_long_chart);
|
||||
if (config.style != null) {
|
||||
if (config.style.pictureCheckedStyle != 0) {
|
||||
tvCheck.setBackgroundResource(config.style.pictureCheckedStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSelected(LocalMedia image) {
|
||||
int size = selectData.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
LocalMedia media = selectData.get(i);
|
||||
if (media == null || TextUtils.isEmpty(media.getPath())) {
|
||||
continue;
|
||||
}
|
||||
if (media.getPath()
|
||||
.equals(image.getPath())
|
||||
|| media.getId() == image.getId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update button status
|
||||
*/
|
||||
private void notifyCheckChanged(ViewHolder viewHolder, LocalMedia imageBean) {
|
||||
viewHolder.tvCheck.setText("");
|
||||
int size = selectData.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
LocalMedia media = selectData.get(i);
|
||||
if (media.getPath().equals(imageBean.getPath())
|
||||
|| media.getId() == imageBean.getId()) {
|
||||
imageBean.setNum(media.getNum());
|
||||
media.setPosition(imageBean.getPosition());
|
||||
viewHolder.tvCheck.setText(String.valueOf(imageBean.getNum()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the selected status of the image
|
||||
*
|
||||
* @param contentHolder
|
||||
* @param image
|
||||
*/
|
||||
|
||||
@SuppressLint("StringFormatMatches")
|
||||
private void changeCheckboxState(ViewHolder contentHolder, LocalMedia image) {
|
||||
boolean isChecked = contentHolder.tvCheck.isSelected();
|
||||
int count = selectData.size();
|
||||
String mimeType = count > 0 ? selectData.get(0).getMimeType() : "";
|
||||
if (config.isWithVideoImage) {
|
||||
// isWithVideoImage mode
|
||||
int videoSize = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
LocalMedia media = selectData.get(i);
|
||||
if (PictureMimeType.isHasVideo(media.getMimeType())) {
|
||||
videoSize++;
|
||||
}
|
||||
}
|
||||
|
||||
if (PictureMimeType.isHasVideo(image.getMimeType())) {
|
||||
if (config.maxVideoSelectNum <= 0) {
|
||||
showPromptDialog(context.getString(R.string.picture_rule));
|
||||
return;
|
||||
}
|
||||
|
||||
if (getSelectedSize() >= config.maxSelectNum && !isChecked) {
|
||||
showPromptDialog(context.getString(R.string.picture_message_max_num, config.maxSelectNum));
|
||||
return;
|
||||
}
|
||||
|
||||
if (videoSize >= config.maxVideoSelectNum && !isChecked) {
|
||||
showPromptDialog(StringUtils.getMsg(context, image.getMimeType(), config.maxVideoSelectNum));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChecked && config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
|
||||
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChecked && config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
|
||||
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (PictureMimeType.isHasImage(image.getMimeType())) {
|
||||
if (getSelectedSize() >= config.maxSelectNum && !isChecked) {
|
||||
showPromptDialog(context.getString(R.string.picture_message_max_num, config.maxSelectNum));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(mimeType)) {
|
||||
boolean mimeTypeSame = PictureMimeType.isMimeTypeSame(mimeType, image.getMimeType());
|
||||
if (!mimeTypeSame) {
|
||||
showPromptDialog(context.getString(R.string.picture_rule));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (PictureMimeType.isHasVideo(mimeType) && config.maxVideoSelectNum > 0) {
|
||||
if (count >= config.maxVideoSelectNum && !isChecked) {
|
||||
showPromptDialog(StringUtils.getMsg(context, mimeType, config.maxVideoSelectNum));
|
||||
return;
|
||||
}
|
||||
if (!isChecked && config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
|
||||
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChecked && config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
|
||||
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (count >= config.maxSelectNum && !isChecked) {
|
||||
showPromptDialog(StringUtils.getMsg(context, mimeType, config.maxSelectNum));
|
||||
return;
|
||||
}
|
||||
if (PictureMimeType.isHasVideo(image.getMimeType())) {
|
||||
if (!isChecked && config.videoMinSecond > 0 && image.getDuration() < config.videoMinSecond) {
|
||||
showPromptDialog(context.getString(R.string.picture_choose_min_seconds, config.videoMinSecond / 1000));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChecked && config.videoMaxSecond > 0 && image.getDuration() > config.videoMaxSecond) {
|
||||
showPromptDialog(context.getString(R.string.picture_choose_max_seconds, config.videoMaxSecond / 1000));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isChecked) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
LocalMedia media = selectData.get(i);
|
||||
if (media == null || TextUtils.isEmpty(media.getPath())) {
|
||||
continue;
|
||||
}
|
||||
if (media.getPath().equals(image.getPath())
|
||||
|| media.getId() == image.getId()) {
|
||||
selectData.remove(media);
|
||||
subSelectPosition();
|
||||
AnimUtils.disZoom(contentHolder.ivPicture, config.zoomAnim);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The radio
|
||||
if (config.selectionMode == PictureConfig.SINGLE) {
|
||||
singleRadioMediaImage();
|
||||
}
|
||||
|
||||
// If the width and height are 0, regain the width and height
|
||||
if (image.getWidth() == 0 || image.getHeight() == 0) {
|
||||
int width = 0, height = 0;
|
||||
image.setOrientation(-1);
|
||||
if (PictureMimeType.isContent(image.getPath())) {
|
||||
if (PictureMimeType.isHasVideo(image.getMimeType())) {
|
||||
int[] size = MediaUtils.getVideoSizeForUri(context, Uri.parse(image.getPath()));
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
} else if (PictureMimeType.isHasImage(image.getMimeType())) {
|
||||
int[] size = MediaUtils.getImageSizeForUri(context, Uri.parse(image.getPath()));
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
}
|
||||
} else {
|
||||
if (PictureMimeType.isHasVideo(image.getMimeType())) {
|
||||
int[] size = MediaUtils.getVideoSizeForUrl(image.getPath());
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
} else if (PictureMimeType.isHasImage(image.getMimeType())) {
|
||||
int[] size = MediaUtils.getImageSizeForUrl(image.getPath());
|
||||
width = size[0];
|
||||
height = size[1];
|
||||
}
|
||||
}
|
||||
image.setWidth(width);
|
||||
image.setHeight(height);
|
||||
}
|
||||
|
||||
selectData.add(image);
|
||||
image.setNum(selectData.size());
|
||||
VoiceUtils.getInstance().play();
|
||||
AnimUtils.zoom(contentHolder.ivPicture, config.zoomAnim);
|
||||
contentHolder.tvCheck.startAnimation(AnimationUtils.loadAnimation(context, R.anim.picture_anim_modal_in));
|
||||
}
|
||||
|
||||
boolean isRefreshAll = false;
|
||||
if (config.isMaxSelectEnabledMask) {
|
||||
if (config.chooseMode == PictureMimeType.ofAll()) {
|
||||
// ofAll
|
||||
if (config.isWithVideoImage && config.maxVideoSelectNum > 0) {
|
||||
if (getSelectedSize() >= config.maxSelectNum) {
|
||||
isRefreshAll = true;
|
||||
}
|
||||
if (isChecked) {
|
||||
// delete
|
||||
if (getSelectedSize() == config.maxSelectNum - 1) {
|
||||
isRefreshAll = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!isChecked && getSelectedSize() == 1) {
|
||||
// add
|
||||
isRefreshAll = true;
|
||||
}
|
||||
if (isChecked && getSelectedSize() == 0) {
|
||||
// delete
|
||||
isRefreshAll = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ofImage or ofVideo or ofAudio
|
||||
if (config.chooseMode == PictureMimeType.ofVideo() && config.maxVideoSelectNum > 0) {
|
||||
if (!isChecked && getSelectedSize() == config.maxVideoSelectNum) {
|
||||
// add
|
||||
isRefreshAll = true;
|
||||
}
|
||||
if (isChecked && getSelectedSize() == config.maxVideoSelectNum - 1) {
|
||||
// delete
|
||||
isRefreshAll = true;
|
||||
}
|
||||
} else {
|
||||
if (!isChecked && getSelectedSize() == config.maxSelectNum) {
|
||||
// add
|
||||
isRefreshAll = true;
|
||||
}
|
||||
if (isChecked && getSelectedSize() == config.maxSelectNum - 1) {
|
||||
// delete
|
||||
isRefreshAll = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isRefreshAll) {
|
||||
notifyDataSetChanged();
|
||||
} else {
|
||||
notifyItemChanged(contentHolder.getAdapterPosition());
|
||||
}
|
||||
|
||||
selectImage(contentHolder, !isChecked);
|
||||
if (imageSelectChangedListener != null) {
|
||||
imageSelectChangedListener.onChange(selectData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Radio mode
|
||||
*/
|
||||
private void singleRadioMediaImage() {
|
||||
if (selectData != null
|
||||
&& selectData.size() > 0) {
|
||||
LocalMedia media = selectData.get(0);
|
||||
notifyItemChanged(media.position);
|
||||
selectData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the selection order
|
||||
*/
|
||||
private void subSelectPosition() {
|
||||
if (config.checkNumMode) {
|
||||
int size = selectData.size();
|
||||
for (int index = 0; index < size; index++) {
|
||||
LocalMedia media = selectData.get(index);
|
||||
media.setNum(index + 1);
|
||||
notifyItemChanged(media.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the image and animate it
|
||||
*
|
||||
* @param holder
|
||||
* @param isChecked
|
||||
*/
|
||||
public void selectImage(ViewHolder holder, boolean isChecked) {
|
||||
holder.tvCheck.setSelected(isChecked);
|
||||
if (isChecked) {
|
||||
holder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, R.color.picture_color_80), PorterDuff.Mode.SRC_ATOP);
|
||||
} else {
|
||||
holder.ivPicture.setColorFilter(ContextCompat.getColor
|
||||
(context, R.color.picture_color_20), PorterDuff.Mode.SRC_ATOP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tips
|
||||
*/
|
||||
private void showPromptDialog(String content) {
|
||||
PictureCustomDialog dialog = new PictureCustomDialog(context, R.layout.picture_prompt_dialog);
|
||||
TextView btnOk = dialog.findViewById(R.id.btnOk);
|
||||
TextView tvContent = dialog.findViewById(R.id.tv_content);
|
||||
tvContent.setText(content);
|
||||
btnOk.setOnClickListener(v -> dialog.dismiss());
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Binding listener
|
||||
*
|
||||
* @param imageSelectChangedListener
|
||||
*/
|
||||
public void setOnPhotoSelectChangedListener(OnPhotoSelectChangedListener
|
||||
imageSelectChangedListener) {
|
||||
this.imageSelectChangedListener = imageSelectChangedListener;
|
||||
}
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
package com.luck.picture.lib.adapter;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.PointF;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.photoview.PhotoView;
|
||||
import com.luck.picture.lib.tools.JumpUtils;
|
||||
import com.luck.picture.lib.tools.MediaUtils;
|
||||
import com.luck.picture.lib.widget.longimage.ImageSource;
|
||||
import com.luck.picture.lib.widget.longimage.ImageViewState;
|
||||
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2018/1/27 下午7:50
|
||||
* @describe:PictureSimpleFragmentAdapter
|
||||
*/
|
||||
|
||||
public class PictureSimpleFragmentAdapter extends PagerAdapter {
|
||||
private List<LocalMedia> data;
|
||||
private OnCallBackActivity onBackPressed;
|
||||
private PictureSelectionConfig config;
|
||||
/**
|
||||
* Maximum number of cached images
|
||||
*/
|
||||
private static final int MAX_CACHE_SIZE = 20;
|
||||
/**
|
||||
* To cache the view
|
||||
*/
|
||||
private SparseArray<View> mCacheView;
|
||||
|
||||
public void clear() {
|
||||
if (null != mCacheView) {
|
||||
mCacheView.clear();
|
||||
mCacheView = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeCacheView(int position) {
|
||||
if (mCacheView != null && position < mCacheView.size()) {
|
||||
mCacheView.removeAt(position);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnCallBackActivity {
|
||||
/**
|
||||
* Close Activity
|
||||
*/
|
||||
void onActivityBackPressed();
|
||||
}
|
||||
|
||||
public PictureSimpleFragmentAdapter(PictureSelectionConfig config,
|
||||
OnCallBackActivity onBackPressed) {
|
||||
super();
|
||||
this.config = config;
|
||||
this.onBackPressed = onBackPressed;
|
||||
this.mCacheView = new SparseArray<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* bind data
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
public void bindData(List<LocalMedia> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* get data
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<LocalMedia> getData() {
|
||||
return data == null ? new ArrayList<>() : data;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return data == null ? 0 : data.size();
|
||||
}
|
||||
|
||||
public void remove(int currentItem) {
|
||||
if (getSize() > currentItem) {
|
||||
data.remove(currentItem);
|
||||
}
|
||||
}
|
||||
|
||||
public LocalMedia getItem(int position) {
|
||||
return getSize() > 0 && position < getSize() ? data.get(position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return data != null ? data.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
(container).removeView((View) object);
|
||||
if (mCacheView.size() > MAX_CACHE_SIZE) {
|
||||
mCacheView.remove(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(@NonNull Object object) {
|
||||
return POSITION_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(@NotNull View view, @NotNull Object object) {
|
||||
return view == object;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object instantiateItem(@NotNull ViewGroup container, int position) {
|
||||
View contentView = mCacheView.get(position);
|
||||
if (contentView == null) {
|
||||
contentView = LayoutInflater.from(container.getContext())
|
||||
.inflate(R.layout.picture_image_preview, container, false);
|
||||
mCacheView.put(position, contentView);
|
||||
}
|
||||
PhotoView imageView = contentView.findViewById(R.id.preview_image);
|
||||
SubsamplingScaleImageView longImg = contentView.findViewById(R.id.longImg);
|
||||
ImageView ivPlay = contentView.findViewById(R.id.iv_play);
|
||||
LocalMedia media = getItem(position);
|
||||
if (media != null) {
|
||||
final String mimeType = media.getMimeType();
|
||||
final String path;
|
||||
if (media.isCut() && !media.isCompressed()) {
|
||||
path = media.getCutPath();
|
||||
} else if (media.isCompressed() || (media.isCut() && media.isCompressed())) {
|
||||
path = media.getCompressPath();
|
||||
} else {
|
||||
path = media.getPath();
|
||||
}
|
||||
boolean isGif = PictureMimeType.isGif(mimeType);
|
||||
boolean isHasVideo = PictureMimeType.isHasVideo(mimeType);
|
||||
ivPlay.setVisibility(isHasVideo ? View.VISIBLE : View.GONE);
|
||||
ivPlay.setOnClickListener(v -> {
|
||||
if (PictureSelectionConfig.customVideoPlayCallback != null) {
|
||||
PictureSelectionConfig.customVideoPlayCallback.startPlayVideo(media);
|
||||
} else {
|
||||
Intent intent = new Intent();
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(PictureConfig.EXTRA_PREVIEW_VIDEO, true);
|
||||
bundle.putString(PictureConfig.EXTRA_VIDEO_PATH, path);
|
||||
intent.putExtras(bundle);
|
||||
JumpUtils.startPictureVideoPlayActivity(container.getContext(), bundle, PictureConfig.PREVIEW_VIDEO_CODE);
|
||||
}
|
||||
});
|
||||
boolean eqLongImg = MediaUtils.isLongImg(media);
|
||||
imageView.setVisibility(eqLongImg && !isGif ? View.GONE : View.VISIBLE);
|
||||
imageView.setOnViewTapListener((view, x, y) -> {
|
||||
if (onBackPressed != null) {
|
||||
onBackPressed.onActivityBackPressed();
|
||||
}
|
||||
});
|
||||
longImg.setVisibility(eqLongImg && !isGif ? View.VISIBLE : View.GONE);
|
||||
longImg.setOnClickListener(v -> {
|
||||
if (onBackPressed != null) {
|
||||
onBackPressed.onActivityBackPressed();
|
||||
}
|
||||
});
|
||||
|
||||
if (isGif && !media.isCompressed()) {
|
||||
if (config != null && PictureSelectionConfig.imageEngine != null) {
|
||||
PictureSelectionConfig.imageEngine.loadAsGifImage
|
||||
(contentView.getContext(), path, imageView);
|
||||
}
|
||||
} else {
|
||||
if (config != null && PictureSelectionConfig.imageEngine != null) {
|
||||
if (eqLongImg) {
|
||||
displayLongPic(PictureMimeType.isContent(path)
|
||||
? Uri.parse(path) : Uri.fromFile(new File(path)), longImg);
|
||||
} else {
|
||||
PictureSelectionConfig.imageEngine.loadImage
|
||||
(contentView.getContext(), path, imageView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(container).addView(contentView, 0);
|
||||
return contentView;
|
||||
}
|
||||
|
||||
/**
|
||||
* load long image
|
||||
*
|
||||
* @param uri
|
||||
* @param longImg
|
||||
*/
|
||||
private void displayLongPic(Uri uri, SubsamplingScaleImageView longImg) {
|
||||
longImg.setQuickScaleEnabled(true);
|
||||
longImg.setZoomEnabled(true);
|
||||
longImg.setPanEnabled(true);
|
||||
longImg.setDoubleTapZoomDuration(100);
|
||||
longImg.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
|
||||
longImg.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
|
||||
longImg.setImage(ImageSource.uri(uri), new ImageViewState(0, new PointF(0, 0), 0));
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package com.luck.picture.lib.adapter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-30 20:50
|
||||
* @describe:WeChat style selected after image preview
|
||||
*/
|
||||
public class PictureWeChatPreviewGalleryAdapter
|
||||
extends RecyclerView.Adapter<PictureWeChatPreviewGalleryAdapter.ViewHolder> {
|
||||
private List<LocalMedia> list;
|
||||
private PictureSelectionConfig config;
|
||||
|
||||
public PictureWeChatPreviewGalleryAdapter(PictureSelectionConfig config) {
|
||||
super();
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void setNewData(List<LocalMedia> data) {
|
||||
this.list = data == null ? new ArrayList<>() : data;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addSingleMediaToData(LocalMedia media) {
|
||||
if (this.list != null) {
|
||||
list.clear();
|
||||
list.add(media);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMediaToData(LocalMedia media) {
|
||||
if (this.list != null && this.list.size() > 0) {
|
||||
this.list.remove(media);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDataEmpty() {
|
||||
return list == null || list.size() == 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.picture_wechat_preview_gallery, parent, false);
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
LocalMedia item = getItem(position);
|
||||
if (item != null) {
|
||||
holder.viewBorder.setVisibility(item.isChecked() ? View.VISIBLE : View.GONE);
|
||||
if (config != null && PictureSelectionConfig.imageEngine != null) {
|
||||
PictureSelectionConfig.imageEngine.loadImage(holder.itemView.getContext(), item.getPath(), holder.ivImage);
|
||||
}
|
||||
holder.ivPlay.setVisibility(PictureMimeType.isHasVideo(item.getMimeType()) ? View.VISIBLE : View.GONE);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (listener != null && holder.getAdapterPosition() >= 0) {
|
||||
listener.onItemClick(holder.getAdapterPosition(), getItem(position), v);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public LocalMedia getItem(int position) {
|
||||
return list != null && list.size() > 0 ? list.get(position) : null;
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView ivImage;
|
||||
ImageView ivPlay;
|
||||
View viewBorder;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ivImage = itemView.findViewById(R.id.ivImage);
|
||||
ivPlay = itemView.findViewById(R.id.ivPlay);
|
||||
viewBorder = itemView.findViewById(R.id.viewBorder);
|
||||
}
|
||||
}
|
||||
|
||||
private OnItemClickListener listener;
|
||||
|
||||
public void setItemClickListener(OnItemClickListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(int position, LocalMedia media, View v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list != null ? list.size() : 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.luck.picture.lib.animators;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-18 14:11
|
||||
* @describe:AlphaInAnimationAdapter
|
||||
*/
|
||||
public class AlphaInAnimationAdapter extends BaseAnimationAdapter {
|
||||
private static final float DEFAULT_ALPHA_FROM = 0f;
|
||||
private final float mFrom;
|
||||
|
||||
public AlphaInAnimationAdapter(RecyclerView.Adapter adapter) {
|
||||
this(adapter, DEFAULT_ALPHA_FROM);
|
||||
}
|
||||
|
||||
public AlphaInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
|
||||
super(adapter);
|
||||
mFrom = from;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator[] getAnimators(View view) {
|
||||
return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)};
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.luck.picture.lib.animators;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-18 15:21
|
||||
* @describe:AnimationType
|
||||
*/
|
||||
public class AnimationType {
|
||||
|
||||
/**
|
||||
* default animation
|
||||
*/
|
||||
public final static int DEFAULT_ANIMATION = -1;
|
||||
|
||||
/**
|
||||
* alpha animation
|
||||
*/
|
||||
public final static int ALPHA_IN_ANIMATION = 1;
|
||||
/**
|
||||
* slide in bottom animation
|
||||
*/
|
||||
public final static int SLIDE_IN_BOTTOM_ANIMATION = 2;
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package com.luck.picture.lib.animators;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-18 14:12
|
||||
* @describe:BaseAnimationAdapter
|
||||
*/
|
||||
public abstract class BaseAnimationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
private RecyclerView.Adapter<RecyclerView.ViewHolder> mAdapter;
|
||||
private int mDuration = 250;
|
||||
private Interpolator mInterpolator = new LinearInterpolator();
|
||||
private int mLastPosition = -1;
|
||||
|
||||
private boolean isFirstOnly = true;
|
||||
|
||||
public BaseAnimationAdapter(RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return mAdapter.onCreateViewHolder(parent, viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
|
||||
super.registerAdapterDataObserver(observer);
|
||||
mAdapter.registerAdapterDataObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
|
||||
super.unregisterAdapterDataObserver(observer);
|
||||
mAdapter.unregisterAdapterDataObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
mAdapter.onAttachedToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView);
|
||||
mAdapter.onDetachedFromRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
|
||||
super.onViewAttachedToWindow(holder);
|
||||
mAdapter.onViewAttachedToWindow(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
|
||||
super.onViewDetachedFromWindow(holder);
|
||||
mAdapter.onViewDetachedFromWindow(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
mAdapter.onBindViewHolder(holder, position);
|
||||
|
||||
int adapterPosition = holder.getAdapterPosition();
|
||||
if (!isFirstOnly || adapterPosition > mLastPosition) {
|
||||
for (Animator anim : getAnimators(holder.itemView)) {
|
||||
anim.setDuration(mDuration).start();
|
||||
anim.setInterpolator(mInterpolator);
|
||||
}
|
||||
mLastPosition = adapterPosition;
|
||||
} else {
|
||||
ViewHelper.clear(holder.itemView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(RecyclerView.ViewHolder holder) {
|
||||
mAdapter.onViewRecycled(holder);
|
||||
super.onViewRecycled(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mAdapter.getItemCount();
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
mDuration = duration;
|
||||
}
|
||||
|
||||
public void setInterpolator(Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
public void setStartPosition(int start) {
|
||||
mLastPosition = start;
|
||||
}
|
||||
|
||||
protected abstract Animator[] getAnimators(View view);
|
||||
|
||||
public void setFirstOnly(boolean firstOnly) {
|
||||
isFirstOnly = firstOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return mAdapter.getItemViewType(position);
|
||||
}
|
||||
|
||||
public RecyclerView.Adapter<RecyclerView.ViewHolder> getWrappedAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mAdapter.getItemId(position);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.luck.picture.lib.animators;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-18 14:19
|
||||
* @describe:SlideInBottomAnimationAdapter
|
||||
*/
|
||||
public class SlideInBottomAnimationAdapter extends BaseAnimationAdapter {
|
||||
|
||||
public SlideInBottomAnimationAdapter(RecyclerView.Adapter adapter) {
|
||||
super(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Animator[] getAnimators(View view) {
|
||||
return new Animator[]{
|
||||
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.luck.picture.lib.animators;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-18 14:13
|
||||
* @describe:ViewHelper
|
||||
*/
|
||||
public final class ViewHelper {
|
||||
public static void clear(View v) {
|
||||
v.setAlpha(1);
|
||||
v.setScaleY(1);
|
||||
v.setScaleX(1);
|
||||
v.setTranslationY(0);
|
||||
v.setTranslationX(0);
|
||||
v.setRotation(0);
|
||||
v.setRotationY(0);
|
||||
v.setRotationX(0);
|
||||
v.setPivotY(v.getMeasuredHeight() / 2);
|
||||
v.setPivotX(v.getMeasuredWidth() / 2);
|
||||
ViewCompat.animate(v).setInterpolator(null).setStartDelay(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.luck.picture.lib.app;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.luck.picture.lib.engine.PictureSelectorEngine;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-12-03 15:14
|
||||
* @describe:IApp
|
||||
*/
|
||||
public interface IApp {
|
||||
/**
|
||||
* Application
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Context getAppContext();
|
||||
|
||||
/**
|
||||
* PictureSelectorEngine
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
PictureSelectorEngine getPictureSelectorEngine();
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.luck.picture.lib.app;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.luck.picture.lib.engine.PictureSelectorEngine;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-12-03 15:12
|
||||
* @describe:PictureAppMaster
|
||||
*/
|
||||
public class PictureAppMaster implements IApp {
|
||||
|
||||
|
||||
@Override
|
||||
public Context getAppContext() {
|
||||
if (app == null) {
|
||||
return null;
|
||||
}
|
||||
return app.getAppContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PictureSelectorEngine getPictureSelectorEngine() {
|
||||
if (app == null) {
|
||||
return null;
|
||||
}
|
||||
return app.getPictureSelectorEngine();
|
||||
}
|
||||
|
||||
private PictureAppMaster() {
|
||||
}
|
||||
|
||||
private static PictureAppMaster mInstance;
|
||||
|
||||
public static PictureAppMaster getInstance() {
|
||||
if (mInstance == null) {
|
||||
synchronized (PictureAppMaster.class) {
|
||||
if (mInstance == null) {
|
||||
mInstance = new PictureAppMaster();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
private IApp app;
|
||||
|
||||
public void setApp(IApp app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public IApp getApp() {
|
||||
return app;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.luck.picture.lib.broadcast;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-20 14:01
|
||||
* @describe:广播Action
|
||||
*/
|
||||
public class BroadcastAction {
|
||||
|
||||
/**
|
||||
* 外部预览界面删除图片Action
|
||||
*/
|
||||
public static final String ACTION_DELETE_PREVIEW_POSITION = "com.luck.picture.lib.action.delete_preview_position";
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
package com.luck.picture.lib.broadcast;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-20 13:45
|
||||
* @describe:本地广播
|
||||
*/
|
||||
public class BroadcastManager {
|
||||
private static final String TAG = BroadcastManager.class.getSimpleName();
|
||||
private LocalBroadcastManager localBroadcastManager;
|
||||
|
||||
private Intent intent;
|
||||
private String action;
|
||||
|
||||
public static BroadcastManager getInstance(Context ctx) {
|
||||
BroadcastManager broadcastManager = new BroadcastManager();
|
||||
broadcastManager.localBroadcastManager = LocalBroadcastManager.getInstance(ctx.getApplicationContext());
|
||||
return broadcastManager;
|
||||
}
|
||||
|
||||
|
||||
public BroadcastManager intent(Intent intent) {
|
||||
this.intent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public BroadcastManager action(String action) {
|
||||
this.action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager extras(Bundle bundle) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
intent.putExtras(bundle);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public BroadcastManager put(String key, ArrayList<? extends Parcelable> value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager put(String key, Parcelable[] value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public BroadcastManager put(String key, Parcelable value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager put(String key, float value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager put(String key, double value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager put(String key, long value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager put(String key, boolean value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BroadcastManager put(String key, int value) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public BroadcastManager put(String key, String str) {
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
Log.e(TAG, "intent create failed");
|
||||
return this;
|
||||
}
|
||||
|
||||
intent.putExtra(key, str);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void createIntent() {
|
||||
if (intent == null) {
|
||||
Log.d(TAG, "intent is not created");
|
||||
}
|
||||
|
||||
if (intent == null) {
|
||||
if (!TextUtils.isEmpty(action)) {
|
||||
intent = new Intent(action);
|
||||
}
|
||||
Log.d(TAG, "intent created with action");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void broadcast() {
|
||||
|
||||
createIntent();
|
||||
|
||||
if (intent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
intent.setAction(action);
|
||||
|
||||
if (null != localBroadcastManager) {
|
||||
localBroadcastManager.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerReceiver(BroadcastReceiver br, List<String> actions) {
|
||||
if (null == br || null == actions) {
|
||||
return;
|
||||
}
|
||||
IntentFilter iFilter = new IntentFilter();
|
||||
if (actions != null) {
|
||||
for (String action : actions) {
|
||||
iFilter.addAction(action);
|
||||
}
|
||||
}
|
||||
if (null != localBroadcastManager) {
|
||||
localBroadcastManager.registerReceiver(br, iFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void registerReceiver(BroadcastReceiver br, String... actions) {
|
||||
if (actions == null || actions.length <= 0) {
|
||||
return;
|
||||
}
|
||||
registerReceiver(br, Arrays.asList(actions));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param br
|
||||
*/
|
||||
public void unregisterReceiver(BroadcastReceiver br) {
|
||||
if (null == br) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
localBroadcastManager.unregisterReceiver(br);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param br
|
||||
* @param actions 至少传入一个
|
||||
*/
|
||||
public void unregisterReceiver(BroadcastReceiver br, @NonNull String... actions) {
|
||||
unregisterReceiver(br);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.luck.picture.lib.camera;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder;
|
||||
|
||||
/**
|
||||
* =====================================
|
||||
* 作 者: 陈嘉桐
|
||||
* 版 本:1.1.4
|
||||
* 创建日期:2017/6/8
|
||||
* 描 述:
|
||||
* =====================================
|
||||
*/
|
||||
public class CheckPermission {
|
||||
public static final int STATE_RECORDING = -1;
|
||||
public static final int STATE_NO_PERMISSION = -2;
|
||||
public static final int STATE_SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* 用于检测是否具有录音权限
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getRecordState() {
|
||||
int minBuffer = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat
|
||||
.ENCODING_PCM_16BIT);
|
||||
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 44100, AudioFormat
|
||||
.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, (minBuffer * 100));
|
||||
short[] point = new short[minBuffer];
|
||||
int readSize = 0;
|
||||
try {
|
||||
|
||||
audioRecord.startRecording();//检测是否可以进入初始化状态
|
||||
} catch (Exception e) {
|
||||
if (audioRecord != null) {
|
||||
audioRecord.release();
|
||||
audioRecord = null;
|
||||
}
|
||||
return STATE_NO_PERMISSION;
|
||||
}
|
||||
if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
|
||||
//6.0以下机型都会返回此状态,故使用时需要判断bulid版本
|
||||
//检测是否在录音中
|
||||
if (audioRecord != null) {
|
||||
audioRecord.stop();
|
||||
audioRecord.release();
|
||||
audioRecord = null;
|
||||
}
|
||||
return STATE_RECORDING;
|
||||
} else {
|
||||
//检测是否可以获取录音结果
|
||||
|
||||
readSize = audioRecord.read(point, 0, point.length);
|
||||
|
||||
|
||||
if (readSize <= 0) {
|
||||
if (audioRecord != null) {
|
||||
audioRecord.stop();
|
||||
audioRecord.release();
|
||||
audioRecord = null;
|
||||
|
||||
}
|
||||
return STATE_NO_PERMISSION;
|
||||
|
||||
} else {
|
||||
if (audioRecord != null) {
|
||||
audioRecord.stop();
|
||||
audioRecord.release();
|
||||
audioRecord = null;
|
||||
|
||||
}
|
||||
|
||||
return STATE_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,547 @@
|
||||
package com.luck.picture.lib.camera;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.camera.core.ImageCapture;
|
||||
import androidx.camera.core.ImageCaptureException;
|
||||
import androidx.camera.core.VideoCapture;
|
||||
import androidx.camera.view.CameraView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.LifecycleEventObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.luck.picture.lib.PictureMediaScannerConnection;
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.camera.listener.CameraListener;
|
||||
import com.luck.picture.lib.camera.listener.CaptureListener;
|
||||
import com.luck.picture.lib.camera.listener.ClickListener;
|
||||
import com.luck.picture.lib.camera.listener.ImageCallbackListener;
|
||||
import com.luck.picture.lib.camera.listener.TypeListener;
|
||||
import com.luck.picture.lib.camera.view.CaptureLayout;
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.config.PictureSelectionConfig;
|
||||
import com.luck.picture.lib.thread.PictureThreadUtils;
|
||||
import com.luck.picture.lib.tools.AndroidQTransformUtils;
|
||||
import com.luck.picture.lib.tools.DateUtils;
|
||||
import com.luck.picture.lib.tools.MediaUtils;
|
||||
import com.luck.picture.lib.tools.PictureFileUtils;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
import com.luck.picture.lib.tools.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-04 13:41
|
||||
* @describe:自定义相机View
|
||||
*/
|
||||
public class CustomCameraView extends RelativeLayout {
|
||||
/**
|
||||
* 只能拍照
|
||||
*/
|
||||
public static final int BUTTON_STATE_ONLY_CAPTURE = 0x101;
|
||||
/**
|
||||
* 只能录像
|
||||
*/
|
||||
public static final int BUTTON_STATE_ONLY_RECORDER = 0x102;
|
||||
/**
|
||||
* 两者都可以
|
||||
*/
|
||||
public static final int BUTTON_STATE_BOTH = 0x103;
|
||||
/**
|
||||
* 闪关灯状态
|
||||
*/
|
||||
private static final int TYPE_FLASH_AUTO = 0x021;
|
||||
private static final int TYPE_FLASH_ON = 0x022;
|
||||
private static final int TYPE_FLASH_OFF = 0x023;
|
||||
private int type_flash = TYPE_FLASH_OFF;
|
||||
private PictureSelectionConfig mConfig;
|
||||
/**
|
||||
* 回调监听
|
||||
*/
|
||||
private CameraListener mCameraListener;
|
||||
private ClickListener mOnClickListener;
|
||||
private ImageCallbackListener mImageCallbackListener;
|
||||
private androidx.camera.view.CameraView mCameraView;
|
||||
private ImageView mImagePreview;
|
||||
private ImageView mSwitchCamera;
|
||||
private ImageView mFlashLamp;
|
||||
private CaptureLayout mCaptureLayout;
|
||||
private MediaPlayer mMediaPlayer;
|
||||
private TextureView mTextureView;
|
||||
private long recordTime = 0;
|
||||
private File mVideoFile;
|
||||
private File mPhotoFile;
|
||||
|
||||
public CustomCameraView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CustomCameraView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomCameraView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView();
|
||||
}
|
||||
|
||||
public void initView() {
|
||||
setWillNotDraw(false);
|
||||
setBackgroundColor(ContextCompat.getColor(getContext(), R.color.picture_color_black));
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.picture_camera_view, this);
|
||||
mCameraView = view.findViewById(R.id.cameraView);
|
||||
mCameraView.enableTorch(true);
|
||||
mTextureView = view.findViewById(R.id.video_play_preview);
|
||||
mImagePreview = view.findViewById(R.id.image_preview);
|
||||
mSwitchCamera = view.findViewById(R.id.image_switch);
|
||||
mSwitchCamera.setImageResource(R.drawable.picture_ic_camera);
|
||||
mFlashLamp = view.findViewById(R.id.image_flash);
|
||||
setFlashRes();
|
||||
mFlashLamp.setOnClickListener(v -> {
|
||||
type_flash++;
|
||||
if (type_flash > 0x023)
|
||||
type_flash = TYPE_FLASH_AUTO;
|
||||
setFlashRes();
|
||||
});
|
||||
mCaptureLayout = view.findViewById(R.id.capture_layout);
|
||||
mCaptureLayout.setDuration(15 * 1000);
|
||||
//切换摄像头
|
||||
mSwitchCamera.setOnClickListener(v -> mCameraView.toggleCamera());
|
||||
//拍照 录像
|
||||
mCaptureLayout.setCaptureListener(new CaptureListener() {
|
||||
@Override
|
||||
public void takePictures() {
|
||||
mSwitchCamera.setVisibility(INVISIBLE);
|
||||
mFlashLamp.setVisibility(INVISIBLE);
|
||||
mCameraView.setCaptureMode(androidx.camera.view.CameraView.CaptureMode.IMAGE);
|
||||
File imageOutFile = createImageFile();
|
||||
if (imageOutFile == null) {
|
||||
return;
|
||||
}
|
||||
mPhotoFile = imageOutFile;
|
||||
mCameraView.takePicture(imageOutFile, ContextCompat.getMainExecutor(getContext()),
|
||||
new MyImageResultCallback(getContext(), mConfig, imageOutFile,
|
||||
mImagePreview, mCaptureLayout, mImageCallbackListener, mCameraListener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordStart() {
|
||||
mSwitchCamera.setVisibility(INVISIBLE);
|
||||
mFlashLamp.setVisibility(INVISIBLE);
|
||||
mCameraView.setCaptureMode(androidx.camera.view.CameraView.CaptureMode.VIDEO);
|
||||
mCameraView.startRecording(createVideoFile(), ContextCompat.getMainExecutor(getContext()),
|
||||
new VideoCapture.OnVideoSavedCallback() {
|
||||
@Override
|
||||
public void onVideoSaved(@NonNull File file) {
|
||||
mVideoFile = file;
|
||||
if (recordTime < 1500 && mVideoFile.exists() && mVideoFile.delete()) {
|
||||
return;
|
||||
}
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfig.cameraPath)) {
|
||||
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean doInBackground() {
|
||||
return AndroidQTransformUtils.copyPathToDCIM(getContext(),
|
||||
file, Uri.parse(mConfig.cameraPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
PictureThreadUtils.cancel(PictureThreadUtils.getIoPool());
|
||||
}
|
||||
});
|
||||
}
|
||||
mTextureView.setVisibility(View.VISIBLE);
|
||||
mCameraView.setVisibility(View.INVISIBLE);
|
||||
if (mTextureView.isAvailable()) {
|
||||
startVideoPlay(mVideoFile);
|
||||
} else {
|
||||
mTextureView.setSurfaceTextureListener(surfaceTextureListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
|
||||
if (mCameraListener != null) {
|
||||
mCameraListener.onError(videoCaptureError, message, cause);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordShort(final long time) {
|
||||
recordTime = time;
|
||||
mSwitchCamera.setVisibility(VISIBLE);
|
||||
mFlashLamp.setVisibility(VISIBLE);
|
||||
mCaptureLayout.resetCaptureLayout();
|
||||
mCaptureLayout.setTextWithAnimation(getContext().getString(R.string.picture_recording_time_is_short));
|
||||
mCameraView.stopRecording();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordEnd(long time) {
|
||||
recordTime = time;
|
||||
mCameraView.stopRecording();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordZoom(float zoom) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordError() {
|
||||
if (mCameraListener != null) {
|
||||
mCameraListener.onError(0, "An unknown error", null);
|
||||
}
|
||||
}
|
||||
});
|
||||
//确认 取消
|
||||
mCaptureLayout.setTypeListener(new TypeListener() {
|
||||
@Override
|
||||
public void cancel() {
|
||||
stopVideoPlay();
|
||||
resetState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void confirm() {
|
||||
if (mCameraView.getCaptureMode() == androidx.camera.view.CameraView.CaptureMode.VIDEO) {
|
||||
if (mVideoFile == null) {
|
||||
return;
|
||||
}
|
||||
stopVideoPlay();
|
||||
if (mCameraListener != null || !mVideoFile.exists()) {
|
||||
mCameraListener.onRecordSuccess(mVideoFile);
|
||||
}
|
||||
} else {
|
||||
if (mPhotoFile == null || !mPhotoFile.exists()) {
|
||||
return;
|
||||
}
|
||||
mImagePreview.setVisibility(INVISIBLE);
|
||||
if (mCameraListener != null) {
|
||||
mCameraListener.onPictureSuccess(mPhotoFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
mCaptureLayout.setLeftClickListener(() -> {
|
||||
if (mOnClickListener != null) {
|
||||
mOnClickListener.onClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 拍照回调
|
||||
*/
|
||||
private static class MyImageResultCallback implements ImageCapture.OnImageSavedCallback {
|
||||
private WeakReference<Context> mContextReference;
|
||||
private WeakReference<PictureSelectionConfig> mConfigReference;
|
||||
private WeakReference<File> mFileReference;
|
||||
private WeakReference<ImageView> mImagePreviewReference;
|
||||
private WeakReference<CaptureLayout> mCaptureLayoutReference;
|
||||
private WeakReference<ImageCallbackListener> mImageCallbackListenerReference;
|
||||
private WeakReference<CameraListener> mCameraListenerReference;
|
||||
|
||||
public MyImageResultCallback(Context context, PictureSelectionConfig config,
|
||||
File imageOutFile, ImageView imagePreview,
|
||||
CaptureLayout captureLayout, ImageCallbackListener imageCallbackListener,
|
||||
CameraListener cameraListener) {
|
||||
super();
|
||||
this.mContextReference = new WeakReference<>(context);
|
||||
this.mConfigReference = new WeakReference<>(config);
|
||||
this.mFileReference = new WeakReference<>(imageOutFile);
|
||||
this.mImagePreviewReference = new WeakReference<>(imagePreview);
|
||||
this.mCaptureLayoutReference = new WeakReference<>(captureLayout);
|
||||
this.mImageCallbackListenerReference = new WeakReference<>(imageCallbackListener);
|
||||
this.mCameraListenerReference = new WeakReference<>(cameraListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
|
||||
if (mConfigReference.get() != null) {
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfigReference.get().cameraPath)) {
|
||||
PictureThreadUtils.executeByIo(new PictureThreadUtils.SimpleTask<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean doInBackground() {
|
||||
return AndroidQTransformUtils.copyPathToDCIM(mContextReference.get(),
|
||||
mFileReference.get(), Uri.parse(mConfigReference.get().cameraPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
PictureThreadUtils.cancel(PictureThreadUtils.getIoPool());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (mImageCallbackListenerReference.get() != null
|
||||
&& mFileReference.get() != null
|
||||
&& mImagePreviewReference.get() != null) {
|
||||
mImageCallbackListenerReference.get().onLoadImage(mFileReference.get(), mImagePreviewReference.get());
|
||||
}
|
||||
if (mImagePreviewReference.get() != null) {
|
||||
mImagePreviewReference.get().setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mCaptureLayoutReference.get() != null) {
|
||||
mCaptureLayoutReference.get().startTypeBtnAnimator();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull ImageCaptureException exception) {
|
||||
if (mCameraListenerReference.get() != null) {
|
||||
mCameraListenerReference.get().onError(exception.getImageCaptureError(), exception.getMessage(), exception.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||
startVideoPlay(mVideoFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
public File createImageFile() {
|
||||
if (SdkVersionUtils.checkedAndroid_Q()) {
|
||||
String diskCacheDir = PictureFileUtils.getDiskCacheDir(getContext());
|
||||
File rootDir = new File(diskCacheDir);
|
||||
if (!rootDir.exists() && rootDir.mkdirs()) {
|
||||
}
|
||||
boolean isOutFileNameEmpty = TextUtils.isEmpty(mConfig.cameraFileName);
|
||||
String suffix = TextUtils.isEmpty(mConfig.suffixType) ? PictureFileUtils.POSTFIX : mConfig.suffixType;
|
||||
String newFileImageName = isOutFileNameEmpty ? DateUtils.getCreateFileName("IMG_") + suffix : mConfig.cameraFileName;
|
||||
File cameraFile = new File(rootDir, newFileImageName);
|
||||
Uri outUri = getOutUri(PictureMimeType.ofImage());
|
||||
if (outUri != null) {
|
||||
mConfig.cameraPath = outUri.toString();
|
||||
}
|
||||
return cameraFile;
|
||||
} else {
|
||||
String cameraFileName = "";
|
||||
if (!TextUtils.isEmpty(mConfig.cameraFileName)) {
|
||||
boolean isSuffixOfImage = PictureMimeType.isSuffixOfImage(mConfig.cameraFileName);
|
||||
mConfig.cameraFileName = !isSuffixOfImage ? StringUtils.renameSuffix(mConfig.cameraFileName, PictureMimeType.JPEG) : mConfig.cameraFileName;
|
||||
cameraFileName = mConfig.camera ? mConfig.cameraFileName : StringUtils.rename(mConfig.cameraFileName);
|
||||
}
|
||||
File cameraFile = PictureFileUtils.createCameraFile(getContext(),
|
||||
PictureMimeType.ofImage(), cameraFileName, mConfig.suffixType, mConfig.outPutCameraPath);
|
||||
if (cameraFile != null) {
|
||||
mConfig.cameraPath = cameraFile.getAbsolutePath();
|
||||
}
|
||||
return cameraFile;
|
||||
}
|
||||
}
|
||||
|
||||
public File createVideoFile() {
|
||||
if (SdkVersionUtils.checkedAndroid_Q()) {
|
||||
String diskCacheDir = PictureFileUtils.getVideoDiskCacheDir(getContext());
|
||||
File rootDir = new File(diskCacheDir);
|
||||
if (!rootDir.exists() && rootDir.mkdirs()) {
|
||||
}
|
||||
boolean isOutFileNameEmpty = TextUtils.isEmpty(mConfig.cameraFileName);
|
||||
String suffix = TextUtils.isEmpty(mConfig.suffixType) ? PictureMimeType.MP4 : mConfig.suffixType;
|
||||
String newFileImageName = isOutFileNameEmpty ? DateUtils.getCreateFileName("VID_") + suffix : mConfig.cameraFileName;
|
||||
File cameraFile = new File(rootDir, newFileImageName);
|
||||
Uri outUri = getOutUri(PictureMimeType.ofVideo());
|
||||
if (outUri != null) {
|
||||
mConfig.cameraPath = outUri.toString();
|
||||
}
|
||||
return cameraFile;
|
||||
} else {
|
||||
String cameraFileName = "";
|
||||
if (!TextUtils.isEmpty(mConfig.cameraFileName)) {
|
||||
boolean isSuffixOfImage = PictureMimeType.isSuffixOfImage(mConfig.cameraFileName);
|
||||
mConfig.cameraFileName = !isSuffixOfImage ? StringUtils
|
||||
.renameSuffix(mConfig.cameraFileName, PictureMimeType.MP4) : mConfig.cameraFileName;
|
||||
cameraFileName = mConfig.camera ? mConfig.cameraFileName : StringUtils.rename(mConfig.cameraFileName);
|
||||
}
|
||||
File cameraFile = PictureFileUtils.createCameraFile(getContext(),
|
||||
PictureMimeType.ofVideo(), cameraFileName, mConfig.suffixType, mConfig.outPutCameraPath);
|
||||
mConfig.cameraPath = cameraFile.getAbsolutePath();
|
||||
return cameraFile;
|
||||
}
|
||||
}
|
||||
|
||||
private Uri getOutUri(int type) {
|
||||
return type == PictureMimeType.ofVideo()
|
||||
? MediaUtils.createVideoUri(getContext(), mConfig.suffixType) : MediaUtils.createImageUri(getContext(), mConfig.suffixType);
|
||||
}
|
||||
|
||||
public void setCameraListener(CameraListener cameraListener) {
|
||||
this.mCameraListener = cameraListener;
|
||||
}
|
||||
|
||||
public void setPictureSelectionConfig(PictureSelectionConfig config) {
|
||||
this.mConfig = config;
|
||||
}
|
||||
|
||||
public void setBindToLifecycle(LifecycleOwner lifecycleOwner) {
|
||||
mCameraView.bindToLifecycle(lifecycleOwner);
|
||||
lifecycleOwner.getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置录制视频最大时长 秒
|
||||
*/
|
||||
public void setRecordVideoMaxTime(int maxDurationTime) {
|
||||
mCaptureLayout.setDuration(maxDurationTime * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置录制视频最小时长 秒
|
||||
*/
|
||||
public void setRecordVideoMinTime(int minDurationTime) {
|
||||
mCaptureLayout.setMinDuration(minDurationTime * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭相机界面按钮
|
||||
*
|
||||
* @param clickListener
|
||||
*/
|
||||
public void setOnClickListener(ClickListener clickListener) {
|
||||
this.mOnClickListener = clickListener;
|
||||
}
|
||||
|
||||
public void setImageCallbackListener(ImageCallbackListener mImageCallbackListener) {
|
||||
this.mImageCallbackListener = mImageCallbackListener;
|
||||
}
|
||||
|
||||
private void setFlashRes() {
|
||||
switch (type_flash) {
|
||||
case TYPE_FLASH_AUTO:
|
||||
mFlashLamp.setImageResource(R.drawable.picture_ic_flash_auto);
|
||||
mCameraView.setFlash(ImageCapture.FLASH_MODE_AUTO);
|
||||
break;
|
||||
case TYPE_FLASH_ON:
|
||||
mFlashLamp.setImageResource(R.drawable.picture_ic_flash_on);
|
||||
mCameraView.setFlash(ImageCapture.FLASH_MODE_ON);
|
||||
break;
|
||||
case TYPE_FLASH_OFF:
|
||||
mFlashLamp.setImageResource(R.drawable.picture_ic_flash_off);
|
||||
mCameraView.setFlash(ImageCapture.FLASH_MODE_OFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public CameraView getCameraView() {
|
||||
return mCameraView;
|
||||
}
|
||||
|
||||
public CaptureLayout getCaptureLayout() {
|
||||
return mCaptureLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置状态
|
||||
*/
|
||||
private void resetState() {
|
||||
if (mCameraView.getCaptureMode() == androidx.camera.view.CameraView.CaptureMode.VIDEO) {
|
||||
if (mCameraView.isRecording()) {
|
||||
mCameraView.stopRecording();
|
||||
}
|
||||
if (mVideoFile != null && mVideoFile.exists()) {
|
||||
mVideoFile.delete();
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfig.cameraPath)) {
|
||||
getContext().getContentResolver().delete(Uri.parse(mConfig.cameraPath), null, null);
|
||||
} else {
|
||||
new PictureMediaScannerConnection(getContext(), mVideoFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mImagePreview.setVisibility(INVISIBLE);
|
||||
if (mPhotoFile != null && mPhotoFile.exists()) {
|
||||
mPhotoFile.delete();
|
||||
if (SdkVersionUtils.checkedAndroid_Q() && PictureMimeType.isContent(mConfig.cameraPath)) {
|
||||
getContext().getContentResolver().delete(Uri.parse(mConfig.cameraPath), null, null);
|
||||
} else {
|
||||
new PictureMediaScannerConnection(getContext(), mPhotoFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
mSwitchCamera.setVisibility(VISIBLE);
|
||||
mFlashLamp.setVisibility(VISIBLE);
|
||||
mCameraView.setVisibility(View.VISIBLE);
|
||||
mCaptureLayout.resetCaptureLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始循环播放视频
|
||||
*
|
||||
* @param videoFile
|
||||
*/
|
||||
private void startVideoPlay(File videoFile) {
|
||||
try {
|
||||
if (mMediaPlayer == null) {
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
}
|
||||
mMediaPlayer.setDataSource(videoFile.getAbsolutePath());
|
||||
mMediaPlayer.setSurface(new Surface(mTextureView.getSurfaceTexture()));
|
||||
mMediaPlayer.setLooping(true);
|
||||
mMediaPlayer.setOnPreparedListener(mp -> {
|
||||
mp.start();
|
||||
|
||||
float ratio = mp.getVideoWidth() * 1f / mp.getVideoHeight();
|
||||
int width1 = mTextureView.getWidth();
|
||||
ViewGroup.LayoutParams layoutParams = mTextureView.getLayoutParams();
|
||||
layoutParams.height = (int) (width1 / ratio);
|
||||
mTextureView.setLayoutParams(layoutParams);
|
||||
});
|
||||
mMediaPlayer.prepareAsync();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止视频播放
|
||||
*/
|
||||
private void stopVideoPlay() {
|
||||
if (mMediaPlayer != null) {
|
||||
mMediaPlayer.stop();
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer = null;
|
||||
}
|
||||
mTextureView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.luck.picture.lib.camera.listener;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-04 13:38
|
||||
* @describe:相机回调监听
|
||||
*/
|
||||
public interface CameraListener {
|
||||
/**
|
||||
* 拍照成功返回
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
void onPictureSuccess(@NonNull File file);
|
||||
|
||||
/**
|
||||
* 录像成功返回
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
void onRecordSuccess(@NonNull File file);
|
||||
|
||||
/**
|
||||
* 使用相机出错
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
void onError(int videoCaptureError, String message, Throwable cause);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.luck.picture.lib.camera.listener;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-04 13:56
|
||||
*/
|
||||
public interface CaptureListener {
|
||||
void takePictures();
|
||||
|
||||
void recordShort(long time);
|
||||
|
||||
void recordStart();
|
||||
|
||||
void recordEnd(long time);
|
||||
|
||||
void recordZoom(float zoom);
|
||||
|
||||
void recordError();
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.luck.picture.lib.camera.listener;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-04 13:45
|
||||
* @describe:点击事件监听
|
||||
*/
|
||||
public interface ClickListener {
|
||||
void onClick();
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.luck.picture.lib.camera.listener;
|
||||
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-04 15:55
|
||||
* @describe:图片加载
|
||||
*/
|
||||
public interface ImageCallbackListener {
|
||||
/**
|
||||
* 加载图片回调
|
||||
*
|
||||
* @param file
|
||||
* @param imageView
|
||||
*/
|
||||
void onLoadImage(File file, ImageView imageView);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.luck.picture.lib.camera.listener;
|
||||
|
||||
/**
|
||||
* =====================================
|
||||
* 作 者: 陈嘉桐
|
||||
* 版 本:1.1.4
|
||||
* 创建日期:2017/4/25
|
||||
* 描 述:
|
||||
* =====================================
|
||||
*/
|
||||
public interface TypeListener {
|
||||
void cancel();
|
||||
|
||||
void confirm();
|
||||
}
|
@ -0,0 +1,379 @@
|
||||
package com.luck.picture.lib.camera.view;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.os.CountDownTimer;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.luck.picture.lib.camera.CustomCameraView;
|
||||
import com.luck.picture.lib.camera.CheckPermission;
|
||||
import com.luck.picture.lib.camera.listener.CaptureListener;
|
||||
import com.luck.picture.lib.tools.DoubleUtils;
|
||||
|
||||
|
||||
/**
|
||||
* =====================================
|
||||
* 作 者: 陈嘉桐 445263848@qq.com
|
||||
* 版 本:1.1.4
|
||||
* 创建日期:2017/4/25
|
||||
* 描 述:拍照按钮
|
||||
* =====================================
|
||||
*/
|
||||
public class CaptureButton extends View {
|
||||
|
||||
private int state; //当前按钮状态
|
||||
private int button_state; //按钮可执行的功能状态(拍照,录制,两者)
|
||||
|
||||
public static final int STATE_IDLE = 0x001; //空闲状态
|
||||
public static final int STATE_PRESS = 0x002; //按下状态
|
||||
public static final int STATE_LONG_PRESS = 0x003; //长按状态
|
||||
public static final int STATE_RECORDERING = 0x004; //录制状态
|
||||
public static final int STATE_BAN = 0x005; //禁止状态
|
||||
|
||||
private int progress_color = 0xEE16AE16; //进度条颜色
|
||||
private int outside_color = 0xEEDCDCDC; //外圆背景色
|
||||
private int inside_color = 0xFFFFFFFF; //内圆背景色
|
||||
|
||||
|
||||
private float event_Y; //Touch_Event_Down时候记录的Y值
|
||||
|
||||
|
||||
private Paint mPaint;
|
||||
|
||||
private float strokeWidth; //进度条宽度
|
||||
private int outside_add_size; //长按外圆半径变大的Size
|
||||
private int inside_reduce_size; //长安内圆缩小的Size
|
||||
|
||||
//中心坐标
|
||||
private float center_X;
|
||||
private float center_Y;
|
||||
|
||||
private float button_radius; //按钮半径
|
||||
private float button_outside_radius; //外圆半径
|
||||
private float button_inside_radius; //内圆半径
|
||||
private int button_size; //按钮大小
|
||||
|
||||
private float progress; //录制视频的进度
|
||||
private int duration; //录制视频最大时间长度
|
||||
private int min_duration; //最短录制时间限制
|
||||
private int recorded_time; //记录当前录制的时间
|
||||
|
||||
private RectF rectF;
|
||||
|
||||
private LongPressRunnable longPressRunnable; //长按后处理的逻辑Runnable
|
||||
private CaptureListener captureLisenter; //按钮回调接口
|
||||
private RecordCountDownTimer timer; //计时器
|
||||
|
||||
public CaptureButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public CaptureButton(Context context, int size) {
|
||||
super(context);
|
||||
this.button_size = size;
|
||||
button_radius = size / 2.0f;
|
||||
|
||||
button_outside_radius = button_radius;
|
||||
button_inside_radius = button_radius * 0.75f;
|
||||
|
||||
strokeWidth = size / 15;
|
||||
outside_add_size = size / 8;
|
||||
inside_reduce_size = size / 8;
|
||||
|
||||
mPaint = new Paint();
|
||||
mPaint.setAntiAlias(true);
|
||||
|
||||
progress = 0;
|
||||
longPressRunnable = new LongPressRunnable();
|
||||
|
||||
state = STATE_IDLE; //初始化为空闲状态
|
||||
button_state = CustomCameraView.BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照
|
||||
duration = 10 * 1000; //默认最长录制时间为10s
|
||||
min_duration = 1500; //默认最短录制时间为1.5s
|
||||
|
||||
center_X = (button_size + outside_add_size * 2) / 2;
|
||||
center_Y = (button_size + outside_add_size * 2) / 2;
|
||||
|
||||
rectF = new RectF(
|
||||
center_X - (button_radius + outside_add_size - strokeWidth / 2),
|
||||
center_Y - (button_radius + outside_add_size - strokeWidth / 2),
|
||||
center_X + (button_radius + outside_add_size - strokeWidth / 2),
|
||||
center_Y + (button_radius + outside_add_size - strokeWidth / 2));
|
||||
|
||||
timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(button_size + outside_add_size * 2, button_size + outside_add_size * 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
mPaint.setColor(outside_color); //外圆(半透明灰色)
|
||||
canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint);
|
||||
|
||||
mPaint.setColor(inside_color); //内圆(白色)
|
||||
canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint);
|
||||
|
||||
//如果状态为录制状态,则绘制录制进度条
|
||||
if (state == STATE_RECORDERING) {
|
||||
mPaint.setColor(progress_color);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeWidth(strokeWidth);
|
||||
canvas.drawArc(rectF, -90, progress, false, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (event.getPointerCount() > 1 || state != STATE_IDLE)
|
||||
break;
|
||||
event_Y = event.getY(); //记录Y值
|
||||
state = STATE_PRESS; //修改当前状态为点击按下
|
||||
|
||||
//判断按钮状态是否为可录制状态
|
||||
if ((button_state == CustomCameraView.BUTTON_STATE_ONLY_RECORDER || button_state == CustomCameraView.BUTTON_STATE_BOTH))
|
||||
postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (captureLisenter != null
|
||||
&& state == STATE_RECORDERING
|
||||
&& (button_state == CustomCameraView.BUTTON_STATE_ONLY_RECORDER || button_state == CustomCameraView.BUTTON_STATE_BOTH)) {
|
||||
//记录当前Y值与按下时候Y值的差值,调用缩放回调接口
|
||||
captureLisenter.recordZoom(event_Y - event.getY());
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
//根据当前按钮的状态进行相应的处理 ----CodeReview---抬起瞬间应该重置状态 当前状态可能为按下和正在录制
|
||||
//state = STATE_BAN;
|
||||
handlerPressByState();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//当手指松开按钮时候处理的逻辑
|
||||
private void handlerPressByState() {
|
||||
removeCallbacks(longPressRunnable); //移除长按逻辑的Runnable
|
||||
//根据当前状态处理
|
||||
switch (state) {
|
||||
//当前是点击按下
|
||||
case STATE_PRESS:
|
||||
if (captureLisenter != null && (button_state == CustomCameraView.BUTTON_STATE_ONLY_CAPTURE || button_state ==
|
||||
CustomCameraView.BUTTON_STATE_BOTH)) {
|
||||
startCaptureAnimation(button_inside_radius);
|
||||
} else {
|
||||
state = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
// ---CodeReview---当内外圆动画未结束时已经是长按状态 但还没有置为STATE_RECORDERING时 应该也要结束录制 此处是一个bug
|
||||
case STATE_LONG_PRESS:
|
||||
//当前是长按状态
|
||||
case STATE_RECORDERING:
|
||||
timer.cancel(); //停止计时器
|
||||
recordEnd(); //录制结束
|
||||
break;
|
||||
}
|
||||
state = STATE_IDLE;
|
||||
}
|
||||
|
||||
//录制结束
|
||||
public void recordEnd() {
|
||||
if (captureLisenter != null) {
|
||||
if (recorded_time < min_duration)
|
||||
captureLisenter.recordShort(recorded_time);//回调录制时间过短
|
||||
else
|
||||
captureLisenter.recordEnd(recorded_time); //回调录制结束
|
||||
}
|
||||
resetRecordAnim(); //重制按钮状态
|
||||
}
|
||||
|
||||
//重制状态
|
||||
private void resetRecordAnim() {
|
||||
state = STATE_BAN;
|
||||
progress = 0; //重制进度
|
||||
invalidate();
|
||||
//还原按钮初始状态动画
|
||||
startRecordAnimation(
|
||||
button_outside_radius,
|
||||
button_radius,
|
||||
button_inside_radius,
|
||||
button_radius * 0.75f
|
||||
);
|
||||
}
|
||||
|
||||
//内圆动画
|
||||
private void startCaptureAnimation(float inside_start) {
|
||||
ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_start * 0.75f, inside_start);
|
||||
inside_anim.addUpdateListener(animation -> {
|
||||
button_inside_radius = (float) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
});
|
||||
inside_anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
//回调拍照接口
|
||||
// if (captureLisenter != null) {
|
||||
// captureLisenter.takePictures();
|
||||
// }
|
||||
// 为何拍照完成要将状态掷为禁止????此处貌似bug!!!!!!---CodeReview
|
||||
//state = STATE_BAN;
|
||||
//state = STATE_IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
super.onAnimationStart(animation);
|
||||
if (captureLisenter != null) {
|
||||
captureLisenter.takePictures();
|
||||
}
|
||||
// 防止重复点击 状态重置
|
||||
state = STATE_BAN;
|
||||
}
|
||||
});
|
||||
inside_anim.setDuration(50);
|
||||
inside_anim.start();
|
||||
}
|
||||
|
||||
//内外圆动画
|
||||
private void startRecordAnimation(float outside_start, float outside_end, float inside_start, float inside_end) {
|
||||
ValueAnimator outside_anim = ValueAnimator.ofFloat(outside_start, outside_end);
|
||||
ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_end);
|
||||
//外圆动画监听
|
||||
outside_anim.addUpdateListener(animation -> {
|
||||
button_outside_radius = (float) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
});
|
||||
//内圆动画监听
|
||||
inside_anim.addUpdateListener(animation -> {
|
||||
button_inside_radius = (float) animation.getAnimatedValue();
|
||||
invalidate();
|
||||
});
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
//当动画结束后启动录像Runnable并且回调录像开始接口
|
||||
set.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
if (DoubleUtils.isFastDoubleClick()) {
|
||||
return;
|
||||
}
|
||||
//设置为录制状态
|
||||
if (state == STATE_LONG_PRESS) {
|
||||
if (captureLisenter != null)
|
||||
captureLisenter.recordStart();
|
||||
state = STATE_RECORDERING;
|
||||
timer.start();
|
||||
} else {
|
||||
// 此处动画包括长按起始动画和还原动画 若不是长按状态应该还原状态为空闲????---CodeReview
|
||||
state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
});
|
||||
set.playTogether(outside_anim, inside_anim);
|
||||
set.setDuration(100);
|
||||
set.start();
|
||||
}
|
||||
|
||||
|
||||
//更新进度条
|
||||
private void updateProgress(long millisUntilFinished) {
|
||||
recorded_time = (int) (duration - millisUntilFinished);
|
||||
progress = 360f - millisUntilFinished / (float) duration * 360f;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
//录制视频计时器
|
||||
private class RecordCountDownTimer extends CountDownTimer {
|
||||
RecordCountDownTimer(long millisInFuture, long countDownInterval) {
|
||||
super(millisInFuture, countDownInterval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
updateProgress(millisUntilFinished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
//updateProgress(duration);
|
||||
recordEnd();
|
||||
}
|
||||
}
|
||||
|
||||
//长按线程
|
||||
private class LongPressRunnable implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
state = STATE_LONG_PRESS; //如果按下后经过500毫秒则会修改当前状态为长按状态
|
||||
//没有录制权限
|
||||
if (CheckPermission.getRecordState() != CheckPermission.STATE_SUCCESS) {
|
||||
state = STATE_IDLE;
|
||||
if (captureLisenter != null) {
|
||||
captureLisenter.recordError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
//启动按钮动画,外圆变大,内圆缩小
|
||||
startRecordAnimation(
|
||||
button_outside_radius,
|
||||
button_outside_radius + outside_add_size,
|
||||
button_inside_radius,
|
||||
button_inside_radius - inside_reduce_size
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//设置最长录制时间
|
||||
public void setDuration(int duration) {
|
||||
this.duration = duration;
|
||||
timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
|
||||
}
|
||||
|
||||
//设置最短录制时间
|
||||
public void setMinDuration(int duration) {
|
||||
this.min_duration = duration;
|
||||
}
|
||||
|
||||
//设置回调接口
|
||||
public void setCaptureListener(CaptureListener captureListener) {
|
||||
this.captureLisenter = captureListener;
|
||||
}
|
||||
|
||||
//设置按钮功能(拍照和录像)
|
||||
public void setButtonFeatures(int state) {
|
||||
this.button_state = state;
|
||||
}
|
||||
|
||||
//设置按钮功能(拍照和录像)
|
||||
public int getButtonFeatures() {
|
||||
return button_state;
|
||||
}
|
||||
|
||||
//是否空闲状态
|
||||
public boolean isIdle() {
|
||||
return state == STATE_IDLE ? true : false;
|
||||
}
|
||||
|
||||
//设置状态
|
||||
public void resetState() {
|
||||
state = STATE_IDLE;
|
||||
}
|
||||
}
|
@ -0,0 +1,365 @@
|
||||
package com.luck.picture.lib.camera.view;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.camera.listener.CaptureListener;
|
||||
import com.luck.picture.lib.camera.listener.ClickListener;
|
||||
import com.luck.picture.lib.camera.listener.TypeListener;
|
||||
import com.luck.picture.lib.tools.DoubleUtils;
|
||||
|
||||
import static com.luck.picture.lib.camera.CustomCameraView.BUTTON_STATE_ONLY_CAPTURE;
|
||||
import static com.luck.picture.lib.camera.CustomCameraView.BUTTON_STATE_ONLY_RECORDER;
|
||||
|
||||
/**
|
||||
* =====================================
|
||||
* 作 者: 陈嘉桐 445263848@qq.com
|
||||
* 版 本:1.0.4
|
||||
* 创建日期:2017/4/26
|
||||
* 描 述:集成各个控件的布局
|
||||
* =====================================
|
||||
*/
|
||||
|
||||
public class CaptureLayout extends FrameLayout {
|
||||
|
||||
private CaptureListener captureListener; //拍照按钮监听
|
||||
private TypeListener typeListener; //拍照或录制后接结果按钮监听
|
||||
private ClickListener leftClickListener; //左边按钮监听
|
||||
private ClickListener rightClickListener; //右边按钮监听
|
||||
|
||||
public void setTypeListener(TypeListener typeListener) {
|
||||
this.typeListener = typeListener;
|
||||
}
|
||||
|
||||
public void setCaptureListener(CaptureListener captureListener) {
|
||||
this.captureListener = captureListener;
|
||||
}
|
||||
|
||||
private CaptureButton btn_capture; //拍照按钮
|
||||
private TypeButton btn_confirm; //确认按钮
|
||||
private TypeButton btn_cancel; //取消按钮
|
||||
private ReturnButton btn_return; //返回按钮
|
||||
private ImageView iv_custom_left; //左边自定义按钮
|
||||
private ImageView iv_custom_right; //右边自定义按钮
|
||||
private TextView txt_tip; //提示文本
|
||||
|
||||
private int layout_width;
|
||||
private int layout_height;
|
||||
private int button_size;
|
||||
private int iconLeft = 0;
|
||||
private int iconRight = 0;
|
||||
|
||||
public CaptureLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CaptureLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CaptureLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||
manager.getDefaultDisplay().getMetrics(outMetrics);
|
||||
|
||||
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
layout_width = outMetrics.widthPixels;
|
||||
} else {
|
||||
layout_width = outMetrics.widthPixels / 2;
|
||||
}
|
||||
button_size = (int) (layout_width / 4.5f);
|
||||
layout_height = button_size + (button_size / 5) * 2 + 100;
|
||||
|
||||
initView();
|
||||
initEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(layout_width, layout_height);
|
||||
}
|
||||
|
||||
public void initEvent() {
|
||||
//默认TypeButton为隐藏
|
||||
iv_custom_right.setVisibility(GONE);
|
||||
btn_cancel.setVisibility(GONE);
|
||||
btn_confirm.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public void startTypeBtnAnimator() {
|
||||
//拍照录制结果后的动画
|
||||
if (this.iconLeft != 0)
|
||||
iv_custom_left.setVisibility(GONE);
|
||||
else
|
||||
btn_return.setVisibility(GONE);
|
||||
if (this.iconRight != 0)
|
||||
iv_custom_right.setVisibility(GONE);
|
||||
btn_capture.setVisibility(GONE);
|
||||
btn_cancel.setVisibility(VISIBLE);
|
||||
btn_confirm.setVisibility(VISIBLE);
|
||||
btn_cancel.setClickable(false);
|
||||
btn_confirm.setClickable(false);
|
||||
iv_custom_left.setVisibility(GONE);
|
||||
ObjectAnimator animator_cancel = ObjectAnimator.ofFloat(btn_cancel, "translationX", layout_width / 4, 0);
|
||||
ObjectAnimator animator_confirm = ObjectAnimator.ofFloat(btn_confirm, "translationX", -layout_width / 4, 0);
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.playTogether(animator_cancel, animator_confirm);
|
||||
set.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
btn_cancel.setClickable(true);
|
||||
btn_confirm.setClickable(true);
|
||||
}
|
||||
});
|
||||
set.setDuration(500);
|
||||
set.start();
|
||||
}
|
||||
|
||||
|
||||
private void initView() {
|
||||
setWillNotDraw(false);
|
||||
//拍照按钮
|
||||
btn_capture = new CaptureButton(getContext(), button_size);
|
||||
FrameLayout.LayoutParams btn_capture_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
btn_capture_param.gravity = Gravity.CENTER;
|
||||
btn_capture.setLayoutParams(btn_capture_param);
|
||||
btn_capture.setCaptureListener(new CaptureListener() {
|
||||
@Override
|
||||
public void takePictures() {
|
||||
if (captureListener != null) {
|
||||
captureListener.takePictures();
|
||||
}
|
||||
startAlphaAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordShort(long time) {
|
||||
if (captureListener != null) {
|
||||
captureListener.recordShort(time);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordStart() {
|
||||
if (captureListener != null) {
|
||||
captureListener.recordStart();
|
||||
}
|
||||
startAlphaAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordEnd(long time) {
|
||||
if (captureListener != null) {
|
||||
captureListener.recordEnd(time);
|
||||
}
|
||||
startTypeBtnAnimator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordZoom(float zoom) {
|
||||
if (captureListener != null) {
|
||||
captureListener.recordZoom(zoom);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordError() {
|
||||
if (captureListener != null) {
|
||||
captureListener.recordError();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//取消按钮
|
||||
btn_cancel = new TypeButton(getContext(), TypeButton.TYPE_CANCEL, button_size);
|
||||
final LayoutParams btn_cancel_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
btn_cancel_param.gravity = Gravity.CENTER_VERTICAL;
|
||||
btn_cancel_param.setMargins((layout_width / 4) - button_size / 2, 0, 0, 0);
|
||||
btn_cancel.setLayoutParams(btn_cancel_param);
|
||||
btn_cancel.setOnClickListener(view -> {
|
||||
if (typeListener != null) {
|
||||
typeListener.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
//确认按钮
|
||||
btn_confirm = new TypeButton(getContext(), TypeButton.TYPE_CONFIRM, button_size);
|
||||
LayoutParams btn_confirm_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
btn_confirm_param.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
|
||||
btn_confirm_param.setMargins(0, 0, (layout_width / 4) - button_size / 2, 0);
|
||||
btn_confirm.setLayoutParams(btn_confirm_param);
|
||||
btn_confirm.setOnClickListener(view -> {
|
||||
if (typeListener != null) {
|
||||
typeListener.confirm();
|
||||
}
|
||||
});
|
||||
|
||||
//返回按钮
|
||||
btn_return = new ReturnButton(getContext(), (int) (button_size / 2.5f));
|
||||
LayoutParams btn_return_param = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
btn_return_param.gravity = Gravity.CENTER_VERTICAL;
|
||||
btn_return_param.setMargins(layout_width / 6, 0, 0, 0);
|
||||
btn_return.setLayoutParams(btn_return_param);
|
||||
btn_return.setOnClickListener(v -> {
|
||||
if (leftClickListener != null) {
|
||||
leftClickListener.onClick();
|
||||
}
|
||||
});
|
||||
//左边自定义按钮
|
||||
iv_custom_left = new ImageView(getContext());
|
||||
LayoutParams iv_custom_param_left = new LayoutParams((int) (button_size / 2.5f), (int) (button_size / 2.5f));
|
||||
iv_custom_param_left.gravity = Gravity.CENTER_VERTICAL;
|
||||
iv_custom_param_left.setMargins(layout_width / 6, 0, 0, 0);
|
||||
iv_custom_left.setLayoutParams(iv_custom_param_left);
|
||||
iv_custom_left.setOnClickListener(v -> {
|
||||
if (leftClickListener != null) {
|
||||
leftClickListener.onClick();
|
||||
}
|
||||
});
|
||||
|
||||
//右边自定义按钮
|
||||
iv_custom_right = new ImageView(getContext());
|
||||
LayoutParams iv_custom_param_right = new LayoutParams((int) (button_size / 2.5f), (int) (button_size / 2.5f));
|
||||
iv_custom_param_right.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
|
||||
iv_custom_param_right.setMargins(0, 0, layout_width / 6, 0);
|
||||
iv_custom_right.setLayoutParams(iv_custom_param_right);
|
||||
iv_custom_right.setOnClickListener(v -> {
|
||||
if (rightClickListener != null) {
|
||||
rightClickListener.onClick();
|
||||
}
|
||||
});
|
||||
|
||||
txt_tip = new TextView(getContext());
|
||||
LayoutParams txt_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||
txt_param.gravity = Gravity.CENTER_HORIZONTAL;
|
||||
txt_param.setMargins(0, 0, 0, 0);
|
||||
|
||||
txt_tip.setText(getCaptureTip());
|
||||
|
||||
txt_tip.setTextColor(0xFFFFFFFF);
|
||||
txt_tip.setGravity(Gravity.CENTER);
|
||||
txt_tip.setLayoutParams(txt_param);
|
||||
|
||||
this.addView(btn_capture);
|
||||
this.addView(btn_cancel);
|
||||
this.addView(btn_confirm);
|
||||
this.addView(btn_return);
|
||||
this.addView(iv_custom_left);
|
||||
this.addView(iv_custom_right);
|
||||
this.addView(txt_tip);
|
||||
|
||||
}
|
||||
|
||||
private String getCaptureTip() {
|
||||
int buttonFeatures = btn_capture.getButtonFeatures();
|
||||
switch (buttonFeatures) {
|
||||
case BUTTON_STATE_ONLY_CAPTURE:
|
||||
return getContext().getString(R.string.picture_photo_pictures);
|
||||
case BUTTON_STATE_ONLY_RECORDER:
|
||||
return getContext().getString(R.string.picture_photo_recording);
|
||||
default:
|
||||
return getContext().getString(R.string.picture_photo_camera);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetCaptureLayout() {
|
||||
btn_capture.resetState();
|
||||
btn_cancel.setVisibility(GONE);
|
||||
btn_confirm.setVisibility(GONE);
|
||||
btn_capture.setVisibility(VISIBLE);
|
||||
txt_tip.setText(getCaptureTip());
|
||||
txt_tip.setVisibility(View.VISIBLE);
|
||||
if (this.iconLeft != 0)
|
||||
iv_custom_left.setVisibility(VISIBLE);
|
||||
else
|
||||
btn_return.setVisibility(VISIBLE);
|
||||
if (this.iconRight != 0)
|
||||
iv_custom_right.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
public void startAlphaAnimation() {
|
||||
txt_tip.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
public void setTextWithAnimation(String tip) {
|
||||
txt_tip.setText(tip);
|
||||
ObjectAnimator animator_txt_tip = ObjectAnimator.ofFloat(txt_tip, "alpha", 0f, 1f, 1f, 0f);
|
||||
animator_txt_tip.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
txt_tip.setText(getCaptureTip());
|
||||
txt_tip.setAlpha(1f);
|
||||
}
|
||||
});
|
||||
animator_txt_tip.setDuration(2500);
|
||||
animator_txt_tip.start();
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
btn_capture.setDuration(duration);
|
||||
}
|
||||
|
||||
public void setMinDuration(int duration) {
|
||||
btn_capture.setMinDuration(duration);
|
||||
}
|
||||
|
||||
public void setButtonFeatures(int state) {
|
||||
btn_capture.setButtonFeatures(state);
|
||||
txt_tip.setText(getCaptureTip());
|
||||
}
|
||||
|
||||
public void setTip(String tip) {
|
||||
txt_tip.setText(tip);
|
||||
}
|
||||
|
||||
public void showTip() {
|
||||
txt_tip.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void setIconSrc(int iconLeft, int iconRight) {
|
||||
this.iconLeft = iconLeft;
|
||||
this.iconRight = iconRight;
|
||||
if (this.iconLeft != 0) {
|
||||
iv_custom_left.setImageResource(iconLeft);
|
||||
iv_custom_left.setVisibility(VISIBLE);
|
||||
btn_return.setVisibility(GONE);
|
||||
} else {
|
||||
iv_custom_left.setVisibility(GONE);
|
||||
btn_return.setVisibility(VISIBLE);
|
||||
}
|
||||
if (this.iconRight != 0) {
|
||||
iv_custom_right.setImageResource(iconRight);
|
||||
iv_custom_right.setVisibility(VISIBLE);
|
||||
} else {
|
||||
iv_custom_right.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLeftClickListener(ClickListener leftClickListener) {
|
||||
this.leftClickListener = leftClickListener;
|
||||
}
|
||||
|
||||
public void setRightClickListener(ClickListener rightClickListener) {
|
||||
this.rightClickListener = rightClickListener;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.luck.picture.lib.camera.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* =====================================
|
||||
* 作 者: 陈嘉桐 445263848@qq.com
|
||||
* 版 本:1.0.4
|
||||
* 创建日期:2017/4/26
|
||||
* 描 述:向下箭头的退出按钮
|
||||
* =====================================
|
||||
*/
|
||||
public class ReturnButton extends View {
|
||||
|
||||
private int size;
|
||||
|
||||
private int center_X;
|
||||
private int center_Y;
|
||||
private float strokeWidth;
|
||||
|
||||
private Paint paint;
|
||||
Path path;
|
||||
|
||||
public ReturnButton(Context context, int size) {
|
||||
this(context);
|
||||
this.size = size;
|
||||
center_X = size / 2;
|
||||
center_Y = size / 2;
|
||||
|
||||
strokeWidth = size / 15f;
|
||||
|
||||
paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(Color.WHITE);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
|
||||
path = new Path();
|
||||
}
|
||||
|
||||
public ReturnButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(size, size / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
path.moveTo(strokeWidth, strokeWidth / 2);
|
||||
path.lineTo(center_X, center_Y - strokeWidth / 2);
|
||||
path.lineTo(size - strokeWidth, strokeWidth / 2);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.luck.picture.lib.camera.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* =====================================
|
||||
* 作 者: 陈嘉桐 445263848@qq.com
|
||||
* 版 本:1.0.4
|
||||
* 创建日期:2017/4/26
|
||||
* 描 述:拍照或录制完成后弹出的确认和返回按钮
|
||||
* =====================================
|
||||
*/
|
||||
public class TypeButton extends View{
|
||||
public static final int TYPE_CANCEL = 0x001;
|
||||
public static final int TYPE_CONFIRM = 0x002;
|
||||
private int button_type;
|
||||
private int button_size;
|
||||
|
||||
private float center_X;
|
||||
private float center_Y;
|
||||
private float button_radius;
|
||||
|
||||
private Paint mPaint;
|
||||
private Path path;
|
||||
private float strokeWidth;
|
||||
|
||||
private float index;
|
||||
private RectF rectF;
|
||||
|
||||
public TypeButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public TypeButton(Context context, int type, int size) {
|
||||
super(context);
|
||||
this.button_type = type;
|
||||
button_size = size;
|
||||
button_radius = size / 2.0f;
|
||||
center_X = size / 2.0f;
|
||||
center_Y = size / 2.0f;
|
||||
|
||||
mPaint = new Paint();
|
||||
path = new Path();
|
||||
strokeWidth = size / 50f;
|
||||
index = button_size / 12f;
|
||||
rectF = new RectF(center_X, center_Y - index, center_X + index * 2, center_Y + index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(button_size, button_size);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
//如果类型为取消,则绘制内部为返回箭头
|
||||
if (button_type == TYPE_CANCEL) {
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setColor(0xEEDCDCDC);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawCircle(center_X, center_Y, button_radius, mPaint);
|
||||
|
||||
mPaint.setColor(Color.BLACK);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeWidth(strokeWidth);
|
||||
|
||||
path.moveTo(center_X - index / 7, center_Y + index);
|
||||
path.lineTo(center_X + index, center_Y + index);
|
||||
|
||||
path.arcTo(rectF, 90, -180);
|
||||
path.lineTo(center_X - index, center_Y - index);
|
||||
canvas.drawPath(path, mPaint);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
path.reset();
|
||||
path.moveTo(center_X - index, (float) (center_Y - index * 1.5));
|
||||
path.lineTo(center_X - index, (float) (center_Y - index / 2.3));
|
||||
path.lineTo((float) (center_X - index * 1.6), center_Y - index);
|
||||
path.close();
|
||||
canvas.drawPath(path, mPaint);
|
||||
|
||||
}
|
||||
//如果类型为确认,则绘制绿色勾
|
||||
if (button_type == TYPE_CONFIRM) {
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setColor(0xFFFFFFFF);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawCircle(center_X, center_Y, button_radius, mPaint);
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setColor(0xFF00CC00);
|
||||
mPaint.setStrokeWidth(strokeWidth);
|
||||
|
||||
path.moveTo(center_X - button_size / 6f, center_Y);
|
||||
path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 7.7f);
|
||||
path.lineTo(center_X + button_size / 4.0f, center_Y - button_size / 8.5f);
|
||||
path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 9.4f);
|
||||
path.close();
|
||||
canvas.drawPath(path, mPaint);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,237 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
enum Checker {
|
||||
SINGLE;
|
||||
|
||||
public final static String MIME_TYPE_JPEG = "image/jpeg";
|
||||
|
||||
public final static String MIME_TYPE_JPG = "image/jpg";
|
||||
|
||||
private static final String TAG = "Luban";
|
||||
|
||||
private static final String JPG = ".jpg";
|
||||
|
||||
private final byte[] JPEG_SIGNATURE = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
|
||||
|
||||
/**
|
||||
* Determine if it is JPG.
|
||||
*
|
||||
* @param is image file input stream
|
||||
*/
|
||||
boolean isJPG(InputStream is) {
|
||||
return isJPG(toByteArray(is));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if it is JPG.
|
||||
*
|
||||
* @param is image file mimeType
|
||||
*/
|
||||
boolean isJPG(String mimeType) {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return false;
|
||||
}
|
||||
return mimeType.startsWith(MIME_TYPE_JPEG) || mimeType.startsWith(MIME_TYPE_JPG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
|
||||
*/
|
||||
int getOrientation(InputStream is) {
|
||||
return getOrientation(toByteArray(is));
|
||||
}
|
||||
|
||||
private boolean isJPG(byte[] data) {
|
||||
if (data == null || data.length < 3) {
|
||||
return false;
|
||||
}
|
||||
byte[] signatureB = new byte[]{data[0], data[1], data[2]};
|
||||
return Arrays.equals(JPEG_SIGNATURE, signatureB);
|
||||
}
|
||||
|
||||
private int getOrientation(byte[] jpeg) {
|
||||
if (jpeg == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
int length = 0;
|
||||
|
||||
// ISO/IEC 10918-1:1993(E)
|
||||
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
|
||||
int marker = jpeg[offset] & 0xFF;
|
||||
|
||||
// Check if the marker is a padding.
|
||||
if (marker == 0xFF) {
|
||||
continue;
|
||||
}
|
||||
offset++;
|
||||
|
||||
// Check if the marker is SOI or TEM.
|
||||
if (marker == 0xD8 || marker == 0x01) {
|
||||
continue;
|
||||
}
|
||||
// Check if the marker is EOI or SOS.
|
||||
if (marker == 0xD9 || marker == 0xDA) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the length and check if it is reasonable.
|
||||
length = pack(jpeg, offset, 2, false);
|
||||
if (length < 2 || offset + length > jpeg.length) {
|
||||
Log.e(TAG, "Invalid length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Break if the marker is EXIF in APP1.
|
||||
if (marker == 0xE1 && length >= 8
|
||||
&& pack(jpeg, offset + 2, 4, false) == 0x45786966
|
||||
&& pack(jpeg, offset + 6, 2, false) == 0) {
|
||||
offset += 8;
|
||||
length -= 8;
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip other markers.
|
||||
offset += length;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
// JEITA CP-3451 Exif Version 2.2
|
||||
if (length > 8) {
|
||||
// Identify the byte order.
|
||||
int tag = pack(jpeg, offset, 4, false);
|
||||
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
|
||||
Log.e(TAG, "Invalid byte order");
|
||||
return 0;
|
||||
}
|
||||
boolean littleEndian = (tag == 0x49492A00);
|
||||
|
||||
// Get the offset and check if it is reasonable.
|
||||
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
|
||||
if (count < 10 || count > length) {
|
||||
Log.e(TAG, "Invalid offset");
|
||||
return 0;
|
||||
}
|
||||
offset += count;
|
||||
length -= count;
|
||||
|
||||
// Get the count and go through all the elements.
|
||||
count = pack(jpeg, offset - 2, 2, littleEndian);
|
||||
while (count-- > 0 && length >= 12) {
|
||||
// Get the tag and check if it is orientation.
|
||||
tag = pack(jpeg, offset, 2, littleEndian);
|
||||
if (tag == 0x0112) {
|
||||
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
|
||||
switch (orientation) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 3:
|
||||
return 180;
|
||||
case 6:
|
||||
return 90;
|
||||
case 8:
|
||||
return 270;
|
||||
}
|
||||
Log.e(TAG, "Unsupported orientation");
|
||||
return 0;
|
||||
}
|
||||
offset += 12;
|
||||
length -= 12;
|
||||
}
|
||||
}
|
||||
|
||||
Log.e(TAG, "Orientation not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
String extSuffix(InputStreamProvider input) {
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(input.open(), null, options);
|
||||
return options.outMimeType.replace("image/", ".");
|
||||
} catch (Exception e) {
|
||||
return JPG;
|
||||
}
|
||||
}
|
||||
|
||||
String extSuffix(String mimeType) {
|
||||
try {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return JPG;
|
||||
}
|
||||
return mimeType.startsWith("video") ? mimeType.replace("video/", ".")
|
||||
: mimeType.replace("image/", ".");
|
||||
} catch (Exception e) {
|
||||
return JPG;
|
||||
}
|
||||
}
|
||||
|
||||
boolean needCompress(int leastCompressSize, String path) {
|
||||
if (leastCompressSize > 0) {
|
||||
File source = new File(path);
|
||||
return source.exists() && source.length() > (leastCompressSize << 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean needCompressToLocalMedia(int leastCompressSize, String path) {
|
||||
if (leastCompressSize > 0 && !TextUtils.isEmpty(path)) {
|
||||
File source = new File(path);
|
||||
return source.exists() && source.length() > (leastCompressSize << 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int pack(byte[] bytes, int offset, int length, boolean littleEndian) {
|
||||
int step = 1;
|
||||
if (littleEndian) {
|
||||
offset += length - 1;
|
||||
step = -1;
|
||||
}
|
||||
|
||||
int value = 0;
|
||||
while (length-- > 0) {
|
||||
value = (value << 8) | (bytes[offset] & 0xFF);
|
||||
offset += step;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private byte[] toByteArray(InputStream is) {
|
||||
if (is == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int read;
|
||||
byte[] data = new byte[4096];
|
||||
|
||||
try {
|
||||
while ((read = is.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, read);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
return new byte[0];
|
||||
} finally {
|
||||
try {
|
||||
buffer.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
/**
|
||||
* Created on 2018/1/3 19:43
|
||||
*
|
||||
* @author andy
|
||||
*
|
||||
* A functional interface (callback) that returns true or false for the given input path should be compressed.
|
||||
*/
|
||||
|
||||
public interface CompressionPredicate {
|
||||
|
||||
/**
|
||||
* Determine the given input path should be compressed and return a boolean.
|
||||
* @param path input path
|
||||
* @return the boolean result
|
||||
*/
|
||||
boolean apply(String path);
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.media.ExifInterface;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Responsible for starting compress and managing active and cached resources.
|
||||
*/
|
||||
class Engine {
|
||||
private InputStreamProvider srcImg;
|
||||
private File tagImg;
|
||||
private int srcWidth;
|
||||
private int srcHeight;
|
||||
private boolean focusAlpha;
|
||||
private static final int DEFAULT_QUALITY = 80;
|
||||
private int compressQuality;
|
||||
|
||||
Engine(InputStreamProvider srcImg, File tagImg, boolean focusAlpha, int compressQuality) throws IOException {
|
||||
this.tagImg = tagImg;
|
||||
this.srcImg = srcImg;
|
||||
this.focusAlpha = focusAlpha;
|
||||
this.compressQuality = compressQuality <= 0 ? DEFAULT_QUALITY : compressQuality;
|
||||
|
||||
if (srcImg.getMedia() != null
|
||||
&& srcImg.getMedia().getWidth() > 0
|
||||
&& srcImg.getMedia().getHeight() > 0) {
|
||||
this.srcWidth = srcImg.getMedia().getWidth();
|
||||
this.srcHeight = srcImg.getMedia().getHeight();
|
||||
} else {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
options.inSampleSize = 1;
|
||||
BitmapFactory.decodeStream(srcImg.open(), null, options);
|
||||
this.srcWidth = options.outWidth;
|
||||
this.srcHeight = options.outHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private int computeSize() {
|
||||
srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
|
||||
srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;
|
||||
|
||||
int longSide = Math.max(srcWidth, srcHeight);
|
||||
int shortSide = Math.min(srcWidth, srcHeight);
|
||||
|
||||
float scale = ((float) shortSide / longSide);
|
||||
if (scale <= 1 && scale > 0.5625) {
|
||||
if (longSide < 1664) {
|
||||
return 1;
|
||||
} else if (longSide < 4990) {
|
||||
return 2;
|
||||
} else if (longSide > 4990 && longSide < 10240) {
|
||||
return 4;
|
||||
} else {
|
||||
return longSide / 1280;
|
||||
}
|
||||
} else if (scale <= 0.5625 && scale > 0.5) {
|
||||
return longSide / 1280 == 0 ? 1 : longSide / 1280;
|
||||
} else {
|
||||
return (int) Math.ceil(longSide / (1280.0 / scale));
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap rotatingImage(Bitmap bitmap, int angle) {
|
||||
Matrix matrix = new Matrix();
|
||||
|
||||
matrix.postRotate(angle);
|
||||
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
File compress() throws IOException {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = computeSize();
|
||||
Bitmap tagBitmap = BitmapFactory.decodeStream(srcImg.open(), null, options);
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
if (srcImg.getMedia() != null && !srcImg.getMedia().isCut()) {
|
||||
if (Checker.SINGLE.isJPG(srcImg.getMedia().getMimeType())) {
|
||||
int orientation = srcImg.getMedia().getOrientation();
|
||||
if (orientation > 0) {
|
||||
switch (orientation) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
orientation = 90;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
orientation = 180;
|
||||
break;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
orientation = 270;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tagBitmap = rotatingImage(tagBitmap, orientation);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tagBitmap != null) {
|
||||
compressQuality = compressQuality <= 0 || compressQuality > 100 ? DEFAULT_QUALITY : compressQuality;
|
||||
tagBitmap.compress(focusAlpha ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, compressQuality, stream);
|
||||
tagBitmap.recycle();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(tagImg);
|
||||
fos.write(stream.toByteArray());
|
||||
fos.flush();
|
||||
fos.close();
|
||||
stream.close();
|
||||
return tagImg;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Automatically close the previous InputStream when opening a new InputStream,
|
||||
* and finally need to manually call {@link #close()} to release the resource.
|
||||
*/
|
||||
public abstract class InputStreamAdapter implements InputStreamProvider {
|
||||
|
||||
private InputStream inputStream;
|
||||
|
||||
@Override
|
||||
public InputStream open() throws IOException {
|
||||
close();
|
||||
inputStream = openInternal();
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public abstract InputStream openInternal() throws IOException;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException ignore) {
|
||||
}finally {
|
||||
inputStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 通过此接口获取输入流,以兼容文件、FileProvider方式获取到的图片
|
||||
* <p>
|
||||
* Get the input stream through this interface, and obtain the picture using compatible files and FileProvider
|
||||
*/
|
||||
public interface InputStreamProvider {
|
||||
|
||||
InputStream open() throws IOException;
|
||||
|
||||
void close();
|
||||
|
||||
String getPath();
|
||||
|
||||
LocalMedia getMedia();
|
||||
|
||||
}
|
@ -0,0 +1,638 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.luck.picture.lib.config.PictureMimeType;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.tools.AndroidQTransformUtils;
|
||||
import com.luck.picture.lib.tools.DateUtils;
|
||||
import com.luck.picture.lib.tools.SdkVersionUtils;
|
||||
import com.luck.picture.lib.tools.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Luban implements Handler.Callback {
|
||||
private static final String TAG = "Luban";
|
||||
|
||||
private static final int MSG_COMPRESS_SUCCESS = 0;
|
||||
private static final int MSG_COMPRESS_START = 1;
|
||||
private static final int MSG_COMPRESS_ERROR = 2;
|
||||
|
||||
private String mTargetDir;
|
||||
private String mNewFileName;
|
||||
private boolean focusAlpha;
|
||||
private boolean isCamera;
|
||||
private int mLeastCompressSize;
|
||||
private OnRenameListener mRenameListener;
|
||||
private OnCompressListener mCompressListener;
|
||||
private CompressionPredicate mCompressionPredicate;
|
||||
private List<InputStreamProvider> mStreamProviders;
|
||||
private List<String> mPaths;
|
||||
private List<LocalMedia> mediaList;
|
||||
private int index = -1;
|
||||
private int compressQuality;
|
||||
private Handler mHandler;
|
||||
private int dataCount;
|
||||
|
||||
private Luban(Builder builder) {
|
||||
this.mPaths = builder.mPaths;
|
||||
this.mediaList = builder.mediaList;
|
||||
this.dataCount = builder.dataCount;
|
||||
this.mTargetDir = builder.mTargetDir;
|
||||
this.mNewFileName = builder.mNewFileName;
|
||||
this.mRenameListener = builder.mRenameListener;
|
||||
this.mStreamProviders = builder.mStreamProviders;
|
||||
this.mCompressListener = builder.mCompressListener;
|
||||
this.mLeastCompressSize = builder.mLeastCompressSize;
|
||||
this.mCompressionPredicate = builder.mCompressionPredicate;
|
||||
this.compressQuality = builder.compressQuality;
|
||||
this.focusAlpha = builder.focusAlpha;
|
||||
this.isCamera = builder.isCamera;
|
||||
this.mHandler = new Handler(Looper.getMainLooper(), this);
|
||||
}
|
||||
|
||||
public static Builder with(Context context) {
|
||||
return new Builder(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file with a cache image name in the private cache directory.
|
||||
*
|
||||
* @param context A context.
|
||||
*/
|
||||
private File getImageCacheFile(Context context, InputStreamProvider provider, String suffix) {
|
||||
if (TextUtils.isEmpty(mTargetDir)) {
|
||||
File imageCacheDir = getImageCacheDir(context);
|
||||
if (imageCacheDir != null) {
|
||||
mTargetDir = imageCacheDir.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
String cacheBuilder = "";
|
||||
try {
|
||||
LocalMedia media = provider.getMedia();
|
||||
String encryptionValue = StringUtils.getEncryptionValue(media.getPath(), media.getWidth(), media.getHeight());
|
||||
if (!TextUtils.isEmpty(encryptionValue) && !media.isCut()) {
|
||||
cacheBuilder = mTargetDir + "/" +
|
||||
"IMG_CMP_" +
|
||||
encryptionValue +
|
||||
(TextUtils.isEmpty(suffix) ? ".jpg" : suffix);
|
||||
} else {
|
||||
cacheBuilder = mTargetDir +
|
||||
"/" +
|
||||
DateUtils.getCreateFileName("IMG_CMP_") +
|
||||
(TextUtils.isEmpty(suffix) ? ".jpg" : suffix);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new File(cacheBuilder);
|
||||
}
|
||||
|
||||
private File getImageCustomFile(Context context, String filename) {
|
||||
if (TextUtils.isEmpty(mTargetDir)) {
|
||||
mTargetDir = getImageCacheDir(context).getAbsolutePath();
|
||||
}
|
||||
|
||||
String cacheBuilder = mTargetDir + "/" + filename;
|
||||
|
||||
return new File(cacheBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a directory with the given name in the private cache directory of the application to
|
||||
* use to store retrieved media and thumbnails.
|
||||
*
|
||||
* @param context A context.
|
||||
* @see #getImageCacheDir(Context)
|
||||
*/
|
||||
private static File getImageCacheDir(Context context) {
|
||||
File cacheDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
if (cacheDir != null) {
|
||||
if (!cacheDir.mkdirs() && (!cacheDir.exists() || !cacheDir.isDirectory())) {
|
||||
// File wasn't able to create a directory, or the result exists but not a directory
|
||||
return null;
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.ERROR)) {
|
||||
Log.e(TAG, "default disk cache dir is null");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* start asynchronous compress thread
|
||||
*/
|
||||
private void launch(final Context context) {
|
||||
if (mStreamProviders == null || mPaths == null || mStreamProviders.size() == 0 && mCompressListener != null) {
|
||||
mCompressListener.onError(new NullPointerException("image file cannot be null"));
|
||||
}
|
||||
Iterator<InputStreamProvider> iterator = mStreamProviders.iterator();
|
||||
// 当前压缩下标
|
||||
index = -1;
|
||||
while (iterator.hasNext()) {
|
||||
final InputStreamProvider path = iterator.next();
|
||||
AsyncTask.SERIAL_EXECUTOR.execute(() -> {
|
||||
try {
|
||||
index++;
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_START));
|
||||
String newPath;
|
||||
if (path.open() != null) {
|
||||
if (path.getMedia().isCompressed()
|
||||
&& !TextUtils.isEmpty(path.getMedia().getCompressPath())) {
|
||||
// 压缩过的图片不重复压缩 注意:如果是开启了裁剪 就算压缩过也要重新压缩
|
||||
boolean exists = !path.getMedia().isCut() && new File(path.getMedia().getCompressPath()).exists();
|
||||
|
||||
File result = exists ? new File(path.getMedia().getCompressPath())
|
||||
: compress(context, path);
|
||||
newPath = result.getAbsolutePath();
|
||||
} else {
|
||||
File result = PictureMimeType.isHasVideo(path.getMedia().getMimeType())
|
||||
? new File(path.getPath()) : compress(context, path);
|
||||
newPath = result.getAbsolutePath();
|
||||
}
|
||||
} else {
|
||||
// error
|
||||
newPath = path.getPath();
|
||||
}
|
||||
if (mediaList != null && mediaList.size() > 0) {
|
||||
LocalMedia media = mediaList.get(index);
|
||||
boolean isHasHttp = PictureMimeType.isHasHttp(newPath);
|
||||
boolean isHasVideo = PictureMimeType.isHasVideo(media.getMimeType());
|
||||
media.setCompressed(!isHasHttp && !isHasVideo);
|
||||
media.setCompressPath(isHasHttp || isHasVideo ? null : newPath);
|
||||
media.setAndroidQToPath(SdkVersionUtils.checkedAndroid_Q() ? media.getCompressPath() : null);
|
||||
boolean isLast = index == mediaList.size() - 1;
|
||||
if (isLast) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_SUCCESS, mediaList));
|
||||
}
|
||||
} else {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_ERROR, new IOException()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_COMPRESS_ERROR, e));
|
||||
}
|
||||
});
|
||||
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start compress and return the file
|
||||
*/
|
||||
private File get(InputStreamProvider input, Context context) throws IOException {
|
||||
try {
|
||||
return new Engine(input, getImageCacheFile(context, input, Checker.SINGLE.extSuffix(input)), focusAlpha, compressQuality).compress();
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
}
|
||||
|
||||
private List<File> get(Context context) throws IOException {
|
||||
List<File> results = new ArrayList<>();
|
||||
Iterator<InputStreamProvider> iterator = mStreamProviders.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
InputStreamProvider provider = iterator.next();
|
||||
InputStream inputStream = provider.open();
|
||||
if (inputStream != null) {
|
||||
if (provider.getMedia().isCompressed()
|
||||
&& !TextUtils.isEmpty(provider.getMedia().getCompressPath())) {
|
||||
// 压缩过的图片不重复压缩 注意:如果是开启了裁剪 就算压缩过也要重新压缩
|
||||
boolean exists = !provider.getMedia().isCut() && new File(provider.getMedia().getCompressPath()).exists();
|
||||
File oldFile = exists ? new File(provider.getMedia().getCompressPath())
|
||||
: compress(context, provider);
|
||||
results.add(oldFile);
|
||||
} else {
|
||||
boolean hasVideo = PictureMimeType.isHasVideo(provider.getMedia().getMimeType());
|
||||
results.add(hasVideo ? new File(provider.getMedia().getPath()) : compress(context, provider));
|
||||
}
|
||||
} else {
|
||||
// error
|
||||
results.add(new File(provider.getMedia().getPath()));
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private File compress(Context context, InputStreamProvider path) throws IOException {
|
||||
try {
|
||||
return compressRealLocalMedia(context, path);
|
||||
} finally {
|
||||
path.close();
|
||||
}
|
||||
}
|
||||
|
||||
private File compressReal(Context context, InputStreamProvider path) throws IOException {
|
||||
File result;
|
||||
String suffix = Checker.SINGLE.extSuffix(path.getMedia() != null ? path.getMedia().getMimeType() : "");
|
||||
File outFile = getImageCacheFile(context, path, TextUtils.isEmpty(suffix) ? Checker.SINGLE.extSuffix(path) : suffix);
|
||||
if (mRenameListener != null) {
|
||||
String filename = mRenameListener.rename(path.getPath());
|
||||
outFile = getImageCustomFile(context, filename);
|
||||
}
|
||||
|
||||
if (mCompressionPredicate != null) {
|
||||
if (mCompressionPredicate.apply(path.getPath())
|
||||
&& Checker.SINGLE.needCompress(mLeastCompressSize, path.getPath())) {
|
||||
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
|
||||
} else {
|
||||
result = new File(path.getPath());
|
||||
}
|
||||
} else {
|
||||
if (Checker.SINGLE.extSuffix(path).startsWith(".gif")) {
|
||||
// GIF without compression
|
||||
result = new File(path.getPath());
|
||||
} else {
|
||||
result = Checker.SINGLE.needCompress(mLeastCompressSize, path.getPath()) ?
|
||||
new Engine(path, outFile, focusAlpha, compressQuality).compress() :
|
||||
new File(path.getPath());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private File compressRealLocalMedia(Context context, InputStreamProvider path) throws IOException {
|
||||
File result = null;
|
||||
LocalMedia media = path.getMedia();
|
||||
if (media == null) {
|
||||
throw new NullPointerException("Luban Compress LocalMedia Can't be empty");
|
||||
}
|
||||
String newPath = media.isCut() && !TextUtils.isEmpty(media.getCutPath()) ? media.getCutPath() : media.getRealPath();
|
||||
String suffix = Checker.SINGLE.extSuffix(media.getMimeType());
|
||||
File outFile = getImageCacheFile(context, path, TextUtils.isEmpty(suffix) ? Checker.SINGLE.extSuffix(path) : suffix);
|
||||
String filename = "";
|
||||
if (!TextUtils.isEmpty(mNewFileName)) {
|
||||
filename = isCamera || dataCount == 1 ? mNewFileName : StringUtils.rename(mNewFileName);
|
||||
outFile = getImageCustomFile(context, filename);
|
||||
}
|
||||
// 如果文件存在直接返回不处理
|
||||
if (outFile.exists()) {
|
||||
return outFile;
|
||||
}
|
||||
|
||||
if (mCompressionPredicate != null) {
|
||||
if (Checker.SINGLE.extSuffix(path).startsWith(".gif")) {
|
||||
// GIF without compression
|
||||
if (SdkVersionUtils.checkedAndroid_Q()) {
|
||||
if (media.isCut() && !TextUtils.isEmpty(media.getCutPath())) {
|
||||
result = new File(media.getCutPath());
|
||||
} else {
|
||||
String androidQToPath = AndroidQTransformUtils.copyPathToAndroidQ(context, path.getPath(),
|
||||
media.getWidth(), media.getHeight(), media.getMimeType(), filename);
|
||||
if (!TextUtils.isEmpty(androidQToPath)) {
|
||||
result = new File(androidQToPath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = new File(newPath);
|
||||
}
|
||||
} else {
|
||||
boolean isCompress = Checker.SINGLE.needCompressToLocalMedia(mLeastCompressSize, newPath);
|
||||
if (mCompressionPredicate.apply(newPath) && isCompress) {
|
||||
// 压缩
|
||||
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
|
||||
} else {
|
||||
if (isCompress) {
|
||||
// 压缩
|
||||
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Checker.SINGLE.extSuffix(path).startsWith(".gif")) {
|
||||
// GIF without compression
|
||||
if (SdkVersionUtils.checkedAndroid_Q()) {
|
||||
String newFilePath = media.isCut() ? media.getCutPath() :
|
||||
AndroidQTransformUtils.copyPathToAndroidQ(context,
|
||||
path.getPath(), media.getWidth(), media.getHeight(), media.getMimeType(), filename);
|
||||
if (!TextUtils.isEmpty(newFilePath)) {
|
||||
result = new File(newFilePath);
|
||||
}
|
||||
} else {
|
||||
result = new File(newPath);
|
||||
}
|
||||
} else {
|
||||
boolean isCompress = Checker.SINGLE.needCompressToLocalMedia(mLeastCompressSize, newPath);
|
||||
if (isCompress) {
|
||||
// 压缩
|
||||
result = new Engine(path, outFile, focusAlpha, compressQuality).compress();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
if (mCompressListener == null) return false;
|
||||
|
||||
switch (msg.what) {
|
||||
case MSG_COMPRESS_START:
|
||||
mCompressListener.onStart();
|
||||
break;
|
||||
case MSG_COMPRESS_SUCCESS:
|
||||
mCompressListener.onSuccess((List<LocalMedia>) msg.obj);
|
||||
break;
|
||||
case MSG_COMPRESS_ERROR:
|
||||
mCompressListener.onError((Throwable) msg.obj);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Context context;
|
||||
private String mTargetDir;
|
||||
private String mNewFileName;
|
||||
private boolean focusAlpha;
|
||||
private boolean isCamera;
|
||||
private int compressQuality;
|
||||
private int mLeastCompressSize = 100;
|
||||
private OnRenameListener mRenameListener;
|
||||
private OnCompressListener mCompressListener;
|
||||
private CompressionPredicate mCompressionPredicate;
|
||||
private List<InputStreamProvider> mStreamProviders;
|
||||
private List<String> mPaths;
|
||||
private List<LocalMedia> mediaList;
|
||||
private int dataCount;
|
||||
private boolean isAndroidQ;
|
||||
|
||||
Builder(Context context) {
|
||||
this.context = context;
|
||||
this.mPaths = new ArrayList<>();
|
||||
this.mediaList = new ArrayList<>();
|
||||
this.mStreamProviders = new ArrayList<>();
|
||||
this.isAndroidQ = SdkVersionUtils.checkedAndroid_Q();
|
||||
}
|
||||
|
||||
private Luban build() {
|
||||
return new Luban(this);
|
||||
}
|
||||
|
||||
public Builder load(InputStreamProvider inputStreamProvider) {
|
||||
mStreamProviders.add(inputStreamProvider);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展符合PictureSelector的压缩策略
|
||||
*
|
||||
* @param list LocalMedia集合
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public <T> Builder loadMediaData(List<LocalMedia> list) {
|
||||
this.mediaList = list;
|
||||
this.dataCount = list.size();
|
||||
for (LocalMedia src : list) {
|
||||
load(src);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 扩展符合PictureSelector的压缩策略
|
||||
*
|
||||
* @param media LocalMedia对象
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
private Builder load(final LocalMedia media) {
|
||||
mStreamProviders.add(new InputStreamAdapter() {
|
||||
@Override
|
||||
public InputStream openInternal() throws IOException {
|
||||
if (PictureMimeType.isContent(media.getPath()) && !media.isCut()) {
|
||||
if (!TextUtils.isEmpty(media.getAndroidQToPath())) {
|
||||
return new FileInputStream(media.getAndroidQToPath());
|
||||
}
|
||||
return context.getContentResolver().openInputStream(Uri.parse(media.getPath()));
|
||||
} else {
|
||||
return PictureMimeType.isHasHttp(media.getPath()) ? null : new FileInputStream(media.isCut() ? media.getCutPath() : media.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
if (media.isCut()) {
|
||||
return media.getCutPath();
|
||||
} else {
|
||||
return TextUtils.isEmpty(media.getAndroidQToPath()) ? media.getPath() : media.getAndroidQToPath();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMedia getMedia() {
|
||||
return media;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder load(final Uri uri) {
|
||||
mStreamProviders.add(new InputStreamAdapter() {
|
||||
@Override
|
||||
public InputStream openInternal() throws IOException {
|
||||
return context.getContentResolver().openInputStream(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMedia getMedia() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder load(final File file) {
|
||||
mStreamProviders.add(new InputStreamAdapter() {
|
||||
@Override
|
||||
public InputStream openInternal() throws IOException {
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMedia getMedia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder load(final String string) {
|
||||
mStreamProviders.add(new InputStreamAdapter() {
|
||||
@Override
|
||||
public InputStream openInternal() throws IOException {
|
||||
return new FileInputStream(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMedia getMedia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder load(List<T> list) {
|
||||
for (T src : list) {
|
||||
if (src instanceof String) {
|
||||
load((String) src);
|
||||
} else if (src instanceof File) {
|
||||
load((File) src);
|
||||
} else if (src instanceof Uri) {
|
||||
load((Uri) src);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Incoming data type exception, it must be String, File, Uri or Bitmap");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder putGear(int gear) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Builder setRenameListener(OnRenameListener listener) {
|
||||
this.mRenameListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCompressListener(OnCompressListener listener) {
|
||||
this.mCompressListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTargetDir(String targetDir) {
|
||||
this.mTargetDir = targetDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNewCompressFileName(String newFileName) {
|
||||
this.mNewFileName = newFileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder isCamera(boolean isCamera) {
|
||||
this.isCamera = isCamera;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do I need to keep the image's alpha channel
|
||||
*
|
||||
* @param focusAlpha <p> true - to keep alpha channel, the compress speed will be slow. </p>
|
||||
* <p> false - don't keep alpha channel, it might have a black background.</p>
|
||||
*/
|
||||
public Builder setFocusAlpha(boolean focusAlpha) {
|
||||
this.focusAlpha = focusAlpha;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image compressed output quality
|
||||
*
|
||||
* @param compressQuality The quality is better than
|
||||
*/
|
||||
public Builder setCompressQuality(int compressQuality) {
|
||||
this.compressQuality = compressQuality;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* do not compress when the origin image file size less than one value
|
||||
*
|
||||
* @param size the value of file size, unit KB, default 100K
|
||||
*/
|
||||
public Builder ignoreBy(int size) {
|
||||
this.mLeastCompressSize = size;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* do compress image when return value was true, otherwise, do not compress the image file
|
||||
*
|
||||
* @param compressionPredicate A predicate callback that returns true or false for the given input path should be compressed.
|
||||
*/
|
||||
public Builder filter(CompressionPredicate compressionPredicate) {
|
||||
this.mCompressionPredicate = compressionPredicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* begin compress image with asynchronous
|
||||
*/
|
||||
public void launch() {
|
||||
build().launch(context);
|
||||
}
|
||||
|
||||
public File get(final String path) throws IOException {
|
||||
return build().get(new InputStreamAdapter() {
|
||||
@Override
|
||||
public InputStream openInternal() throws IOException {
|
||||
return new FileInputStream(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMedia getMedia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* begin compress image with synchronize
|
||||
*
|
||||
* @return the thumb image file list
|
||||
*/
|
||||
public List<File> get() throws IOException {
|
||||
return build().get(context);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OnCompressListener {
|
||||
|
||||
/**
|
||||
* Fired when the compression is started, override to handle in your own code
|
||||
*/
|
||||
void onStart();
|
||||
|
||||
/**
|
||||
* Fired when a compression returns successfully, override to handle in your own code
|
||||
*/
|
||||
void onSuccess(List<LocalMedia> list);
|
||||
|
||||
/**
|
||||
* Fired when a compression fails to complete, override to handle in your own code
|
||||
*/
|
||||
void onError(Throwable e);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.luck.picture.lib.compress;
|
||||
|
||||
/**
|
||||
* Author: zibin
|
||||
* Datetime: 2018/5/18
|
||||
* <p>
|
||||
* 提供修改压缩图片命名接口
|
||||
* <p>
|
||||
* A functional interface (callback) that used to rename the file after compress.
|
||||
*/
|
||||
public interface OnRenameListener {
|
||||
|
||||
/**
|
||||
* 压缩前调用该方法用于修改压缩后文件名
|
||||
* <p>
|
||||
* Call before compression begins.
|
||||
*
|
||||
* @param filePath 传入文件路径/ file path
|
||||
* @return 返回重命名后的字符串/ file name
|
||||
*/
|
||||
String rename(String filePath);
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.luck.picture.lib.config;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2017/5/24 1:00
|
||||
* @describe : constant
|
||||
*/
|
||||
public final class PictureConfig {
|
||||
public final static int APPLY_STORAGE_PERMISSIONS_CODE = 1;
|
||||
public final static int APPLY_CAMERA_PERMISSIONS_CODE = 2;
|
||||
public final static int APPLY_AUDIO_PERMISSIONS_CODE = 3;
|
||||
public final static int APPLY_RECORD_AUDIO_PERMISSIONS_CODE = 4;
|
||||
public final static int APPLY_CAMERA_STORAGE_PERMISSIONS_CODE = 5;
|
||||
|
||||
public final static String EXTRA_MEDIA_KEY = "mediaKey";
|
||||
public final static String EXTRA_MEDIA_PATH = "mediaPath";
|
||||
public final static String EXTRA_AUDIO_PATH = "audioPath";
|
||||
public final static String EXTRA_VIDEO_PATH = "videoPath";
|
||||
public final static String EXTRA_PREVIEW_VIDEO = "isExternalPreviewVideo";
|
||||
public final static String EXTRA_PREVIEW_DELETE_POSITION = "position";
|
||||
public final static String EXTRA_FC_TAG = "picture";
|
||||
public final static String EXTRA_RESULT_SELECTION = "extra_result_media";
|
||||
public final static String EXTRA_PREVIEW_SELECT_LIST = "previewSelectList";
|
||||
public final static String EXTRA_SELECT_LIST = "selectList";
|
||||
public final static String EXTRA_COMPLETE_SELECTED = "isCompleteOrSelected";
|
||||
public final static String EXTRA_CHANGE_SELECTED_DATA = "isChangeSelectedData";
|
||||
public final static String EXTRA_CHANGE_ORIGINAL = "isOriginal";
|
||||
public final static String EXTRA_POSITION = "position";
|
||||
public final static String EXTRA_OLD_CURRENT_LIST_SIZE = "oldCurrentListSize";
|
||||
public final static String EXTRA_DIRECTORY_PATH = "directory_path";
|
||||
public final static String EXTRA_BOTTOM_PREVIEW = "bottom_preview";
|
||||
public final static String EXTRA_CONFIG = "PictureSelectorConfig";
|
||||
public final static String EXTRA_SHOW_CAMERA = "isShowCamera";
|
||||
public final static String EXTRA_IS_CURRENT_DIRECTORY = "currentDirectory";
|
||||
public final static String EXTRA_BUCKET_ID = "bucket_id";
|
||||
public final static String EXTRA_PAGE = "page";
|
||||
public final static String EXTRA_DATA_COUNT = "count";
|
||||
public final static String CAMERA_FACING = "android.intent.extras.CAMERA_FACING";
|
||||
|
||||
public final static String EXTRA_ALL_FOLDER_SIZE = "all_folder_size";
|
||||
public final static String EXTRA_QUICK_CAPTURE = "android.intent.extra.quickCapture";
|
||||
|
||||
public final static int MAX_PAGE_SIZE = 60;
|
||||
|
||||
public final static int MIN_PAGE_SIZE = 10;
|
||||
|
||||
public final static int LOADED = 0;
|
||||
|
||||
public final static int NORMAL = -1;
|
||||
|
||||
public final static int CAMERA_BEFORE = 1;
|
||||
|
||||
public final static int TYPE_ALL = 0;
|
||||
public final static int TYPE_IMAGE = 1;
|
||||
public final static int TYPE_VIDEO = 2;
|
||||
|
||||
@Deprecated
|
||||
public final static int TYPE_AUDIO = 3;
|
||||
|
||||
public final static int MAX_COMPRESS_SIZE = 100;
|
||||
|
||||
public final static int TYPE_CAMERA = 1;
|
||||
public final static int TYPE_PICTURE = 2;
|
||||
|
||||
public final static int SINGLE = 1;
|
||||
public final static int MULTIPLE = 2;
|
||||
|
||||
public final static int PREVIEW_VIDEO_CODE = 166;
|
||||
public final static int CHOOSE_REQUEST = 188;
|
||||
public final static int REQUEST_CAMERA = 909;
|
||||
}
|
@ -0,0 +1,345 @@
|
||||
package com.luck.picture.lib.config;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2017-5-24 17:02
|
||||
* @describe:PictureMimeType
|
||||
*/
|
||||
|
||||
public final class PictureMimeType {
|
||||
public static int ofAll() {
|
||||
return PictureConfig.TYPE_ALL;
|
||||
}
|
||||
|
||||
public static int ofImage() {
|
||||
return PictureConfig.TYPE_IMAGE;
|
||||
}
|
||||
|
||||
public static int ofVideo() {
|
||||
return PictureConfig.TYPE_VIDEO;
|
||||
}
|
||||
|
||||
/**
|
||||
* # No longer maintain audio related functions,
|
||||
* but can continue to use but there will be phone compatibility issues
|
||||
* <p>
|
||||
* 不再维护音频相关功能,但可以继续使用但会有机型兼容性问题
|
||||
*/
|
||||
@Deprecated
|
||||
public static int ofAudio() {
|
||||
return PictureConfig.TYPE_AUDIO;
|
||||
}
|
||||
|
||||
|
||||
public static String ofPNG() {
|
||||
return MIME_TYPE_PNG;
|
||||
}
|
||||
|
||||
public static String ofJPEG() {
|
||||
return MIME_TYPE_JPEG;
|
||||
}
|
||||
|
||||
public static String ofBMP() {
|
||||
return MIME_TYPE_BMP;
|
||||
}
|
||||
|
||||
public static String ofGIF() {
|
||||
return MIME_TYPE_GIF;
|
||||
}
|
||||
|
||||
public static String ofWEBP() {
|
||||
return MIME_TYPE_WEBP;
|
||||
}
|
||||
|
||||
public static String of3GP() {
|
||||
return MIME_TYPE_3GP;
|
||||
}
|
||||
|
||||
public static String ofMP4() {
|
||||
return MIME_TYPE_MP4;
|
||||
}
|
||||
|
||||
public static String ofMPEG() {
|
||||
return MIME_TYPE_MPEG;
|
||||
}
|
||||
|
||||
public static String ofAVI() {
|
||||
return MIME_TYPE_AVI;
|
||||
}
|
||||
|
||||
private final static String MIME_TYPE_PNG = "image/png";
|
||||
public final static String MIME_TYPE_JPEG = "image/jpeg";
|
||||
private final static String MIME_TYPE_JPG = "image/jpg";
|
||||
private final static String MIME_TYPE_BMP = "image/bmp";
|
||||
private final static String MIME_TYPE_GIF = "image/gif";
|
||||
private final static String MIME_TYPE_WEBP = "image/webp";
|
||||
|
||||
private final static String MIME_TYPE_3GP = "video/3gp";
|
||||
private final static String MIME_TYPE_MP4 = "video/mp4";
|
||||
private final static String MIME_TYPE_MPEG = "video/mpeg";
|
||||
private final static String MIME_TYPE_AVI = "video/avi";
|
||||
|
||||
|
||||
/**
|
||||
* isGif
|
||||
*
|
||||
* @param mimeType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isGif(String mimeType) {
|
||||
return mimeType != null && (mimeType.equals("image/gif") || mimeType.equals("image/GIF"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* isVideo
|
||||
*
|
||||
* @param mimeType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isHasVideo(String mimeType) {
|
||||
return mimeType != null && mimeType.startsWith(MIME_TYPE_PREFIX_VIDEO);
|
||||
}
|
||||
|
||||
/**
|
||||
* isVideo
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static boolean isUrlHasVideo(String url) {
|
||||
return url.endsWith(".mp4");
|
||||
}
|
||||
|
||||
/**
|
||||
* isAudio
|
||||
*
|
||||
* @param mimeType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isHasAudio(String mimeType) {
|
||||
return mimeType != null && mimeType.startsWith(MIME_TYPE_PREFIX_AUDIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* isImage
|
||||
*
|
||||
* @param mimeType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isHasImage(String mimeType) {
|
||||
return mimeType != null && mimeType.startsWith(MIME_TYPE_PREFIX_IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if it is JPG.
|
||||
*
|
||||
* @param is image file mimeType
|
||||
*/
|
||||
public static boolean isJPEG(String mimeType) {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return false;
|
||||
}
|
||||
return mimeType.startsWith(MIME_TYPE_JPEG) || mimeType.startsWith(MIME_TYPE_JPG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if it is JPG.
|
||||
*
|
||||
* @param is image file mimeType
|
||||
*/
|
||||
public static boolean isJPG(String mimeType) {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return false;
|
||||
}
|
||||
return mimeType.startsWith(MIME_TYPE_JPG);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* is Network image
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static boolean isHasHttp(String path) {
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
return false;
|
||||
}
|
||||
return path.startsWith("http")
|
||||
|| path.startsWith("https")
|
||||
|| path.startsWith("/http")
|
||||
|| path.startsWith("/https");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the file type is an image or a video
|
||||
*
|
||||
* @param cameraMimeType
|
||||
* @return
|
||||
*/
|
||||
public static String getMimeType(int cameraMimeType) {
|
||||
switch (cameraMimeType) {
|
||||
case PictureConfig.TYPE_VIDEO:
|
||||
return MIME_TYPE_VIDEO;
|
||||
case PictureConfig.TYPE_AUDIO:
|
||||
return MIME_TYPE_AUDIO;
|
||||
default:
|
||||
return MIME_TYPE_IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the file name is a picture
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSuffixOfImage(String name) {
|
||||
return !TextUtils.isEmpty(name) && name.endsWith(".PNG") || name.endsWith(".png") || name.endsWith(".jpeg")
|
||||
|| name.endsWith(".gif") || name.endsWith(".GIF") || name.endsWith(".jpg")
|
||||
|| name.endsWith(".webp") || name.endsWith(".WEBP") || name.endsWith(".JPEG")
|
||||
|| name.endsWith(".bmp");
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it the same type
|
||||
*
|
||||
* @param oldMimeType
|
||||
* @param newMimeType
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMimeTypeSame(String oldMimeType, String newMimeType) {
|
||||
|
||||
return getMimeType(oldMimeType) == getMimeType(newMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Image mimeType
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public static String getImageMimeType(String path) {
|
||||
try {
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
File file = new File(path);
|
||||
String fileName = file.getName();
|
||||
int last = fileName.lastIndexOf(".") + 1;
|
||||
String temp = fileName.substring(last);
|
||||
return "image/" + temp;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return MIME_TYPE_IMAGE;
|
||||
}
|
||||
return MIME_TYPE_IMAGE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Picture or video
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getMimeType(String mimeType) {
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return PictureConfig.TYPE_IMAGE;
|
||||
}
|
||||
if (mimeType.startsWith(MIME_TYPE_PREFIX_VIDEO)) {
|
||||
return PictureConfig.TYPE_VIDEO;
|
||||
} else if (mimeType.startsWith(MIME_TYPE_PREFIX_AUDIO)) {
|
||||
return PictureConfig.TYPE_AUDIO;
|
||||
} else {
|
||||
return PictureConfig.TYPE_IMAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image suffix
|
||||
*
|
||||
* @param mineType
|
||||
* @return
|
||||
*/
|
||||
public static String getLastImgSuffix(String mineType) {
|
||||
String defaultSuffix = PNG;
|
||||
try {
|
||||
int index = mineType.lastIndexOf("/") + 1;
|
||||
if (index > 0) {
|
||||
return "." + mineType.substring(index);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return defaultSuffix;
|
||||
}
|
||||
return defaultSuffix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* is content://
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static boolean isContent(String url) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return false;
|
||||
}
|
||||
return url.startsWith("content://");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an error message by type
|
||||
*
|
||||
* @param context
|
||||
* @param mimeType
|
||||
* @return
|
||||
*/
|
||||
public static String s(Context context, String mimeType) {
|
||||
Context ctx = context.getApplicationContext();
|
||||
if (isHasVideo(mimeType)) {
|
||||
return ctx.getString(R.string.picture_video_error);
|
||||
} else if (isHasAudio(mimeType)) {
|
||||
return ctx.getString(R.string.picture_audio_error);
|
||||
} else {
|
||||
return ctx.getString(R.string.picture_error);
|
||||
}
|
||||
}
|
||||
|
||||
public final static String JPEG = ".jpg";
|
||||
|
||||
private final static String PNG = ".png";
|
||||
|
||||
public final static String MP4 = ".mp4";
|
||||
|
||||
public final static String JPEG_Q = "image/jpeg";
|
||||
|
||||
public final static String PNG_Q = "image/png";
|
||||
|
||||
public final static String MP4_Q = "video/mp4";
|
||||
|
||||
public final static String AVI_Q = "video/avi";
|
||||
|
||||
public final static String DCIM = "DCIM/Camera";
|
||||
|
||||
public final static String CAMERA = "Camera";
|
||||
|
||||
public final static String MIME_TYPE_IMAGE = "image/jpeg";
|
||||
public final static String MIME_TYPE_VIDEO = "video/mp4";
|
||||
public final static String MIME_TYPE_AUDIO = "audio/mpeg";
|
||||
|
||||
|
||||
private final static String MIME_TYPE_PREFIX_IMAGE = "image";
|
||||
private final static String MIME_TYPE_PREFIX_VIDEO = "video";
|
||||
private final static String MIME_TYPE_PREFIX_AUDIO = "audio";
|
||||
|
||||
}
|
@ -0,0 +1,521 @@
|
||||
package com.luck.picture.lib.config;
|
||||
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.StyleRes;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.camera.CustomCameraView;
|
||||
import com.luck.picture.lib.engine.CacheResourcesEngine;
|
||||
import com.luck.picture.lib.engine.ImageEngine;
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.listener.OnCustomCameraInterfaceListener;
|
||||
import com.luck.picture.lib.listener.OnResultCallbackListener;
|
||||
import com.luck.picture.lib.listener.OnVideoSelectedPlayCallback;
|
||||
import com.luck.picture.lib.style.PictureCropParameterStyle;
|
||||
import com.luck.picture.lib.style.PictureParameterStyle;
|
||||
import com.luck.picture.lib.style.PictureWindowAnimationStyle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2017-05-24 17:02
|
||||
* @describe:PictureSelector Config
|
||||
*/
|
||||
|
||||
public final class PictureSelectionConfig implements Parcelable {
|
||||
public int chooseMode;
|
||||
public boolean camera;
|
||||
public boolean isSingleDirectReturn;
|
||||
public PictureParameterStyle style;
|
||||
public PictureCropParameterStyle cropStyle;
|
||||
public PictureWindowAnimationStyle windowAnimationStyle;
|
||||
public String compressSavePath;
|
||||
public String suffixType;
|
||||
public boolean focusAlpha;
|
||||
public String renameCompressFileName;
|
||||
public String renameCropFileName;
|
||||
public String specifiedFormat;
|
||||
public int requestedOrientation;
|
||||
public int buttonFeatures;
|
||||
public boolean isCameraAroundState;
|
||||
public boolean isAndroidQTransform;
|
||||
@StyleRes
|
||||
public int themeStyleId;
|
||||
public int selectionMode;
|
||||
public int maxSelectNum;
|
||||
public int minSelectNum;
|
||||
public int maxVideoSelectNum;
|
||||
public int minVideoSelectNum;
|
||||
public int videoQuality;
|
||||
public int cropCompressQuality;
|
||||
public int videoMaxSecond;
|
||||
public int videoMinSecond;
|
||||
public int recordVideoSecond;
|
||||
public int recordVideoMinSecond;
|
||||
public int minimumCompressSize;
|
||||
public int imageSpanCount;
|
||||
public int aspect_ratio_x;
|
||||
public int aspect_ratio_y;
|
||||
public int cropWidth;
|
||||
public int cropHeight;
|
||||
public int compressQuality;
|
||||
public float filterFileSize;
|
||||
public int language;
|
||||
public boolean isMultipleRecyclerAnimation;
|
||||
public boolean isMultipleSkipCrop;
|
||||
public boolean isWeChatStyle;
|
||||
public boolean isUseCustomCamera;
|
||||
public boolean zoomAnim;
|
||||
public boolean isCompress;
|
||||
public boolean isOriginalControl;
|
||||
public boolean isCamera;
|
||||
public boolean isGif;
|
||||
public boolean enablePreview;
|
||||
public boolean enPreviewVideo;
|
||||
public boolean enablePreviewAudio;
|
||||
public boolean checkNumMode;
|
||||
public boolean openClickSound;
|
||||
public boolean enableCrop;
|
||||
public boolean freeStyleCropEnabled;
|
||||
public boolean circleDimmedLayer;
|
||||
@ColorInt
|
||||
public int circleDimmedColor;
|
||||
@ColorInt
|
||||
public int circleDimmedBorderColor;
|
||||
public int circleStrokeWidth;
|
||||
public boolean showCropFrame;
|
||||
public boolean showCropGrid;
|
||||
public boolean hideBottomControls;
|
||||
public boolean rotateEnabled;
|
||||
public boolean scaleEnabled;
|
||||
public boolean previewEggs;
|
||||
public boolean synOrAsy;
|
||||
public boolean returnEmpty;
|
||||
public boolean isDragFrame;
|
||||
public boolean isNotPreviewDownload;
|
||||
public boolean isWithVideoImage;
|
||||
public UCropOptions uCropOptions;
|
||||
public static ImageEngine imageEngine;
|
||||
public static CacheResourcesEngine cacheResourcesEngine;
|
||||
public static OnResultCallbackListener listener;
|
||||
public static OnVideoSelectedPlayCallback customVideoPlayCallback;
|
||||
public static OnCustomCameraInterfaceListener onCustomCameraInterfaceListener;
|
||||
public List<LocalMedia> selectionMedias;
|
||||
public String cameraFileName;
|
||||
public boolean isCheckOriginalImage;
|
||||
@Deprecated
|
||||
public int overrideWidth;
|
||||
@Deprecated
|
||||
public int overrideHeight;
|
||||
@Deprecated
|
||||
public float sizeMultiplier;
|
||||
@Deprecated
|
||||
public boolean isChangeStatusBarFontColor;
|
||||
@Deprecated
|
||||
public boolean isOpenStyleNumComplete;
|
||||
@Deprecated
|
||||
public boolean isOpenStyleCheckNumMode;
|
||||
@Deprecated
|
||||
public int titleBarBackgroundColor;
|
||||
@Deprecated
|
||||
public int pictureStatusBarColor;
|
||||
@Deprecated
|
||||
public int cropTitleBarBackgroundColor;
|
||||
@Deprecated
|
||||
public int cropStatusBarColorPrimaryDark;
|
||||
@Deprecated
|
||||
public int cropTitleColor;
|
||||
@Deprecated
|
||||
public int upResId;
|
||||
@Deprecated
|
||||
public int downResId;
|
||||
public String outPutCameraPath;
|
||||
|
||||
public String originalPath;
|
||||
public String cameraPath;
|
||||
public int cameraMimeType;
|
||||
public int pageSize;
|
||||
public boolean isPageStrategy;
|
||||
public boolean isFilterInvalidFile;
|
||||
public boolean isMaxSelectEnabledMask;
|
||||
public int animationMode;
|
||||
public boolean isAutomaticTitleRecyclerTop;
|
||||
public boolean isCallbackMode;
|
||||
public boolean isAndroidQChangeWH;
|
||||
public boolean isAndroidQChangeVideoWH;
|
||||
public boolean isQuickCapture;
|
||||
/**
|
||||
* 内测专用###########
|
||||
*/
|
||||
public boolean isFallbackVersion;
|
||||
public boolean isFallbackVersion2;
|
||||
public boolean isFallbackVersion3;
|
||||
|
||||
protected void initDefaultValue() {
|
||||
chooseMode = PictureMimeType.ofImage();
|
||||
camera = false;
|
||||
themeStyleId = R.style.picture_default_style;
|
||||
selectionMode = PictureConfig.MULTIPLE;
|
||||
maxSelectNum = 9;
|
||||
minSelectNum = 0;
|
||||
maxVideoSelectNum = 0;
|
||||
minVideoSelectNum = 0;
|
||||
videoQuality = 1;
|
||||
language = -1;
|
||||
cropCompressQuality = 90;
|
||||
videoMaxSecond = 0;
|
||||
videoMinSecond = 0;
|
||||
filterFileSize = -1;
|
||||
recordVideoSecond = 60;
|
||||
recordVideoMinSecond = 0;
|
||||
compressQuality = 80;
|
||||
minimumCompressSize = PictureConfig.MAX_COMPRESS_SIZE;
|
||||
imageSpanCount = 4;
|
||||
isCompress = false;
|
||||
isOriginalControl = false;
|
||||
aspect_ratio_x = 0;
|
||||
aspect_ratio_y = 0;
|
||||
cropWidth = 0;
|
||||
cropHeight = 0;
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
|
||||
buttonFeatures = CustomCameraView.BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照
|
||||
isCameraAroundState = false;
|
||||
isWithVideoImage = false;
|
||||
isAndroidQTransform = true;
|
||||
isCamera = true;
|
||||
isGif = false;
|
||||
focusAlpha = false;
|
||||
isCheckOriginalImage = false;
|
||||
isSingleDirectReturn = false;
|
||||
enablePreview = true;
|
||||
enPreviewVideo = true;
|
||||
enablePreviewAudio = true;
|
||||
checkNumMode = false;
|
||||
isNotPreviewDownload = false;
|
||||
openClickSound = false;
|
||||
isFallbackVersion = false;
|
||||
isFallbackVersion2 = true;
|
||||
isFallbackVersion3 = true;
|
||||
enableCrop = false;
|
||||
isWeChatStyle = false;
|
||||
isUseCustomCamera = false;
|
||||
isMultipleSkipCrop = true;
|
||||
isMultipleRecyclerAnimation = true;
|
||||
freeStyleCropEnabled = false;
|
||||
circleDimmedLayer = false;
|
||||
showCropFrame = true;
|
||||
showCropGrid = true;
|
||||
hideBottomControls = true;
|
||||
rotateEnabled = true;
|
||||
scaleEnabled = true;
|
||||
previewEggs = false;
|
||||
returnEmpty = false;
|
||||
synOrAsy = true;
|
||||
zoomAnim = true;
|
||||
circleDimmedColor = 0;
|
||||
circleDimmedBorderColor = 0;
|
||||
circleStrokeWidth = 1;
|
||||
isDragFrame = true;
|
||||
compressSavePath = "";
|
||||
suffixType = "";
|
||||
cameraFileName = "";
|
||||
specifiedFormat = "";
|
||||
renameCompressFileName = "";
|
||||
renameCropFileName = "";
|
||||
selectionMedias = new ArrayList<>();
|
||||
uCropOptions = null;
|
||||
style = null;
|
||||
cropStyle = null;
|
||||
windowAnimationStyle = null;
|
||||
titleBarBackgroundColor = 0;
|
||||
pictureStatusBarColor = 0;
|
||||
cropTitleBarBackgroundColor = 0;
|
||||
cropStatusBarColorPrimaryDark = 0;
|
||||
cropTitleColor = 0;
|
||||
upResId = 0;
|
||||
downResId = 0;
|
||||
isChangeStatusBarFontColor = false;
|
||||
isOpenStyleNumComplete = false;
|
||||
isOpenStyleCheckNumMode = false;
|
||||
outPutCameraPath = "";
|
||||
sizeMultiplier = 0.5f;
|
||||
overrideWidth = 0;
|
||||
overrideHeight = 0;
|
||||
originalPath = "";
|
||||
cameraPath = "";
|
||||
cameraMimeType = -1;
|
||||
pageSize = PictureConfig.MAX_PAGE_SIZE;
|
||||
isPageStrategy = true;
|
||||
isFilterInvalidFile = false;
|
||||
isMaxSelectEnabledMask = false;
|
||||
animationMode = -1;
|
||||
isAutomaticTitleRecyclerTop = true;
|
||||
isCallbackMode = false;
|
||||
isAndroidQChangeWH = true;
|
||||
isAndroidQChangeVideoWH = false;
|
||||
isQuickCapture = true;
|
||||
}
|
||||
|
||||
public static PictureSelectionConfig getInstance() {
|
||||
return InstanceHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public static PictureSelectionConfig getCleanInstance() {
|
||||
PictureSelectionConfig selectionSpec = getInstance();
|
||||
selectionSpec.initDefaultValue();
|
||||
return selectionSpec;
|
||||
}
|
||||
|
||||
private static final class InstanceHolder {
|
||||
private static final PictureSelectionConfig INSTANCE = new PictureSelectionConfig();
|
||||
}
|
||||
|
||||
public PictureSelectionConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放监听器
|
||||
*/
|
||||
public static void destroy() {
|
||||
PictureSelectionConfig.listener = null;
|
||||
PictureSelectionConfig.customVideoPlayCallback = null;
|
||||
PictureSelectionConfig.onCustomCameraInterfaceListener = null;
|
||||
PictureSelectionConfig.onCustomCameraInterfaceListener = null;
|
||||
PictureSelectionConfig.cacheResourcesEngine = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(this.chooseMode);
|
||||
dest.writeByte(this.camera ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isSingleDirectReturn ? (byte) 1 : (byte) 0);
|
||||
dest.writeParcelable(this.style, flags);
|
||||
dest.writeParcelable(this.cropStyle, flags);
|
||||
dest.writeParcelable(this.windowAnimationStyle, flags);
|
||||
dest.writeString(this.compressSavePath);
|
||||
dest.writeString(this.suffixType);
|
||||
dest.writeByte(this.focusAlpha ? (byte) 1 : (byte) 0);
|
||||
dest.writeString(this.renameCompressFileName);
|
||||
dest.writeString(this.renameCropFileName);
|
||||
dest.writeString(this.specifiedFormat);
|
||||
dest.writeInt(this.requestedOrientation);
|
||||
dest.writeInt(this.buttonFeatures);
|
||||
dest.writeByte(this.isCameraAroundState ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isAndroidQTransform ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.themeStyleId);
|
||||
dest.writeInt(this.selectionMode);
|
||||
dest.writeInt(this.maxSelectNum);
|
||||
dest.writeInt(this.minSelectNum);
|
||||
dest.writeInt(this.maxVideoSelectNum);
|
||||
dest.writeInt(this.minVideoSelectNum);
|
||||
dest.writeInt(this.videoQuality);
|
||||
dest.writeInt(this.cropCompressQuality);
|
||||
dest.writeInt(this.videoMaxSecond);
|
||||
dest.writeInt(this.videoMinSecond);
|
||||
dest.writeInt(this.recordVideoSecond);
|
||||
dest.writeInt(this.recordVideoMinSecond);
|
||||
dest.writeInt(this.minimumCompressSize);
|
||||
dest.writeInt(this.imageSpanCount);
|
||||
dest.writeInt(this.aspect_ratio_x);
|
||||
dest.writeInt(this.aspect_ratio_y);
|
||||
dest.writeInt(this.cropWidth);
|
||||
dest.writeInt(this.cropHeight);
|
||||
dest.writeInt(this.compressQuality);
|
||||
dest.writeFloat(this.filterFileSize);
|
||||
dest.writeInt(this.language);
|
||||
dest.writeByte(this.isMultipleRecyclerAnimation ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isMultipleSkipCrop ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isWeChatStyle ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isUseCustomCamera ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.zoomAnim ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isCompress ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isOriginalControl ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isCamera ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isGif ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.enablePreview ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.enPreviewVideo ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.enablePreviewAudio ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.checkNumMode ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.openClickSound ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.enableCrop ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.freeStyleCropEnabled ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.circleDimmedLayer ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.circleDimmedColor);
|
||||
dest.writeInt(this.circleDimmedBorderColor);
|
||||
dest.writeInt(this.circleStrokeWidth);
|
||||
dest.writeByte(this.showCropFrame ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.showCropGrid ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.hideBottomControls ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.rotateEnabled ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.scaleEnabled ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.previewEggs ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.synOrAsy ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.returnEmpty ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isDragFrame ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isNotPreviewDownload ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isWithVideoImage ? (byte) 1 : (byte) 0);
|
||||
dest.writeParcelable(this.uCropOptions, flags);
|
||||
dest.writeTypedList(this.selectionMedias);
|
||||
dest.writeString(this.cameraFileName);
|
||||
dest.writeByte(this.isCheckOriginalImage ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.overrideWidth);
|
||||
dest.writeInt(this.overrideHeight);
|
||||
dest.writeFloat(this.sizeMultiplier);
|
||||
dest.writeByte(this.isChangeStatusBarFontColor ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isOpenStyleNumComplete ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isOpenStyleCheckNumMode ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.titleBarBackgroundColor);
|
||||
dest.writeInt(this.pictureStatusBarColor);
|
||||
dest.writeInt(this.cropTitleBarBackgroundColor);
|
||||
dest.writeInt(this.cropStatusBarColorPrimaryDark);
|
||||
dest.writeInt(this.cropTitleColor);
|
||||
dest.writeInt(this.upResId);
|
||||
dest.writeInt(this.downResId);
|
||||
dest.writeString(this.outPutCameraPath);
|
||||
dest.writeString(this.originalPath);
|
||||
dest.writeString(this.cameraPath);
|
||||
dest.writeInt(this.cameraMimeType);
|
||||
dest.writeInt(this.pageSize);
|
||||
dest.writeByte(this.isPageStrategy ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isFilterInvalidFile ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isMaxSelectEnabledMask ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.animationMode);
|
||||
dest.writeByte(this.isAutomaticTitleRecyclerTop ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isCallbackMode ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isAndroidQChangeWH ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isAndroidQChangeVideoWH ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isQuickCapture ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isFallbackVersion ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isFallbackVersion2 ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isFallbackVersion3 ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
|
||||
protected PictureSelectionConfig(Parcel in) {
|
||||
this.chooseMode = in.readInt();
|
||||
this.camera = in.readByte() != 0;
|
||||
this.isSingleDirectReturn = in.readByte() != 0;
|
||||
this.style = in.readParcelable(PictureParameterStyle.class.getClassLoader());
|
||||
this.cropStyle = in.readParcelable(PictureCropParameterStyle.class.getClassLoader());
|
||||
this.windowAnimationStyle = in.readParcelable(PictureWindowAnimationStyle.class.getClassLoader());
|
||||
this.compressSavePath = in.readString();
|
||||
this.suffixType = in.readString();
|
||||
this.focusAlpha = in.readByte() != 0;
|
||||
this.renameCompressFileName = in.readString();
|
||||
this.renameCropFileName = in.readString();
|
||||
this.specifiedFormat = in.readString();
|
||||
this.requestedOrientation = in.readInt();
|
||||
this.buttonFeatures = in.readInt();
|
||||
this.isCameraAroundState = in.readByte() != 0;
|
||||
this.isAndroidQTransform = in.readByte() != 0;
|
||||
this.themeStyleId = in.readInt();
|
||||
this.selectionMode = in.readInt();
|
||||
this.maxSelectNum = in.readInt();
|
||||
this.minSelectNum = in.readInt();
|
||||
this.maxVideoSelectNum = in.readInt();
|
||||
this.minVideoSelectNum = in.readInt();
|
||||
this.videoQuality = in.readInt();
|
||||
this.cropCompressQuality = in.readInt();
|
||||
this.videoMaxSecond = in.readInt();
|
||||
this.videoMinSecond = in.readInt();
|
||||
this.recordVideoSecond = in.readInt();
|
||||
this.recordVideoMinSecond = in.readInt();
|
||||
this.minimumCompressSize = in.readInt();
|
||||
this.imageSpanCount = in.readInt();
|
||||
this.aspect_ratio_x = in.readInt();
|
||||
this.aspect_ratio_y = in.readInt();
|
||||
this.cropWidth = in.readInt();
|
||||
this.cropHeight = in.readInt();
|
||||
this.compressQuality = in.readInt();
|
||||
this.filterFileSize = in.readFloat();
|
||||
this.language = in.readInt();
|
||||
this.isMultipleRecyclerAnimation = in.readByte() != 0;
|
||||
this.isMultipleSkipCrop = in.readByte() != 0;
|
||||
this.isWeChatStyle = in.readByte() != 0;
|
||||
this.isUseCustomCamera = in.readByte() != 0;
|
||||
this.zoomAnim = in.readByte() != 0;
|
||||
this.isCompress = in.readByte() != 0;
|
||||
this.isOriginalControl = in.readByte() != 0;
|
||||
this.isCamera = in.readByte() != 0;
|
||||
this.isGif = in.readByte() != 0;
|
||||
this.enablePreview = in.readByte() != 0;
|
||||
this.enPreviewVideo = in.readByte() != 0;
|
||||
this.enablePreviewAudio = in.readByte() != 0;
|
||||
this.checkNumMode = in.readByte() != 0;
|
||||
this.openClickSound = in.readByte() != 0;
|
||||
this.enableCrop = in.readByte() != 0;
|
||||
this.freeStyleCropEnabled = in.readByte() != 0;
|
||||
this.circleDimmedLayer = in.readByte() != 0;
|
||||
this.circleDimmedColor = in.readInt();
|
||||
this.circleDimmedBorderColor = in.readInt();
|
||||
this.circleStrokeWidth = in.readInt();
|
||||
this.showCropFrame = in.readByte() != 0;
|
||||
this.showCropGrid = in.readByte() != 0;
|
||||
this.hideBottomControls = in.readByte() != 0;
|
||||
this.rotateEnabled = in.readByte() != 0;
|
||||
this.scaleEnabled = in.readByte() != 0;
|
||||
this.previewEggs = in.readByte() != 0;
|
||||
this.synOrAsy = in.readByte() != 0;
|
||||
this.returnEmpty = in.readByte() != 0;
|
||||
this.isDragFrame = in.readByte() != 0;
|
||||
this.isNotPreviewDownload = in.readByte() != 0;
|
||||
this.isWithVideoImage = in.readByte() != 0;
|
||||
this.uCropOptions = in.readParcelable(UCropOptions.class.getClassLoader());
|
||||
this.selectionMedias = in.createTypedArrayList(LocalMedia.CREATOR);
|
||||
this.cameraFileName = in.readString();
|
||||
this.isCheckOriginalImage = in.readByte() != 0;
|
||||
this.overrideWidth = in.readInt();
|
||||
this.overrideHeight = in.readInt();
|
||||
this.sizeMultiplier = in.readFloat();
|
||||
this.isChangeStatusBarFontColor = in.readByte() != 0;
|
||||
this.isOpenStyleNumComplete = in.readByte() != 0;
|
||||
this.isOpenStyleCheckNumMode = in.readByte() != 0;
|
||||
this.titleBarBackgroundColor = in.readInt();
|
||||
this.pictureStatusBarColor = in.readInt();
|
||||
this.cropTitleBarBackgroundColor = in.readInt();
|
||||
this.cropStatusBarColorPrimaryDark = in.readInt();
|
||||
this.cropTitleColor = in.readInt();
|
||||
this.upResId = in.readInt();
|
||||
this.downResId = in.readInt();
|
||||
this.outPutCameraPath = in.readString();
|
||||
this.originalPath = in.readString();
|
||||
this.cameraPath = in.readString();
|
||||
this.cameraMimeType = in.readInt();
|
||||
this.pageSize = in.readInt();
|
||||
this.isPageStrategy = in.readByte() != 0;
|
||||
this.isFilterInvalidFile = in.readByte() != 0;
|
||||
this.isMaxSelectEnabledMask = in.readByte() != 0;
|
||||
this.animationMode = in.readInt();
|
||||
this.isAutomaticTitleRecyclerTop = in.readByte() != 0;
|
||||
this.isCallbackMode = in.readByte() != 0;
|
||||
this.isAndroidQChangeWH = in.readByte() != 0;
|
||||
this.isAndroidQChangeVideoWH = in.readByte() != 0;
|
||||
this.isQuickCapture = in.readByte() != 0;
|
||||
this.isFallbackVersion = in.readByte() != 0;
|
||||
this.isFallbackVersion2 = in.readByte() != 0;
|
||||
this.isFallbackVersion3 = in.readByte() != 0;
|
||||
}
|
||||
|
||||
public static final Creator<PictureSelectionConfig> CREATOR = new Creator<PictureSelectionConfig>() {
|
||||
@Override
|
||||
public PictureSelectionConfig createFromParcel(Parcel source) {
|
||||
return new PictureSelectionConfig(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PictureSelectionConfig[] newArray(int size) {
|
||||
return new PictureSelectionConfig[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.luck.picture.lib.config;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.yalantis.ucrop.UCrop;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-01-09 13:33
|
||||
* @describe: UCrop Configuration items
|
||||
*/
|
||||
public class UCropOptions extends UCrop.Options implements Parcelable {
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
}
|
||||
|
||||
public UCropOptions() {
|
||||
}
|
||||
|
||||
protected UCropOptions(Parcel in) {
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<UCropOptions> CREATOR = new Parcelable.Creator<UCropOptions>() {
|
||||
@Override
|
||||
public UCropOptions createFromParcel(Parcel source) {
|
||||
return new UCropOptions(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UCropOptions[] newArray(int size) {
|
||||
return new UCropOptions[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,207 @@
|
||||
package com.luck.picture.lib.crash;
|
||||
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.luck.picture.lib.app.PictureAppMaster;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-12-03 14:53
|
||||
* @describe:PictureSelector Crash Log collection class
|
||||
*/
|
||||
public class PictureSelectorCrashUtils {
|
||||
private static boolean mInitialized;
|
||||
private static String defaultDir;
|
||||
private static String dir;
|
||||
private static String versionName;
|
||||
private static int versionCode;
|
||||
|
||||
private static final String FILE_SEP = System.getProperty("file.separator");
|
||||
private static final Format FORMAT = new SimpleDateFormat("MM-dd HH-mm-ss", Locale.getDefault());
|
||||
|
||||
private static final String CRASH_HEAD;
|
||||
|
||||
private static final Thread.UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
PackageInfo pi = PictureAppMaster.getInstance().getAppContext()
|
||||
.getPackageManager()
|
||||
.getPackageInfo(PictureAppMaster.getInstance().getAppContext().getPackageName(), 0);
|
||||
if (pi != null) {
|
||||
versionName = pi.versionName;
|
||||
versionCode = pi.versionCode;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
CRASH_HEAD = "\n************* Crash Log Head ****************" +
|
||||
"\nDevice Manufacturer: " + Build.MANUFACTURER + // 设备厂商
|
||||
"\nDevice Model : " + Build.MODEL + // 设备型号
|
||||
"\nAndroid Version : " + Build.VERSION.RELEASE + // 系统版本
|
||||
"\nAndroid SDK : " + Build.VERSION.SDK_INT + // SDK版本
|
||||
"\nApp VersionName : " + versionName +
|
||||
"\nApp VersionCode : " + versionCode +
|
||||
"\n************* Crash Log Head ****************\n\n";
|
||||
|
||||
|
||||
UNCAUGHT_EXCEPTION_HANDLER = new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(final Thread t, final Throwable e) {
|
||||
|
||||
if (mFinishAppListener != null) {
|
||||
mFinishAppListener.onFinishApp(t, e);
|
||||
}
|
||||
|
||||
Date now = new Date(System.currentTimeMillis());
|
||||
String fileName = FORMAT.format(now) + ".txt";
|
||||
final String fullPath = (dir == null ? defaultDir : dir) + fileName;
|
||||
if (createOrExistsFile(fullPath)) {
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
pw = new PrintWriter(new FileWriter(fullPath, false));
|
||||
pw.write(CRASH_HEAD);
|
||||
e.printStackTrace(pw);
|
||||
Throwable cause = e.getCause();
|
||||
while (cause != null) {
|
||||
cause.printStackTrace(pw);
|
||||
cause = cause.getCause();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} finally {
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private PictureSelectorCrashUtils() {
|
||||
throw new UnsupportedOperationException("u can't instantiate me...");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
|
||||
*
|
||||
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
|
||||
*/
|
||||
public static boolean init() {
|
||||
return init("", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
|
||||
*
|
||||
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
|
||||
*/
|
||||
public static boolean init(CrashAppListener listener) {
|
||||
return init("", listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
|
||||
*
|
||||
* @param crashDir 崩溃文件存储目录
|
||||
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
|
||||
*/
|
||||
public static boolean init(@NonNull final File crashDir) {
|
||||
return init(crashDir.getAbsolutePath() + FILE_SEP, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>}</p>
|
||||
*
|
||||
* @param crashDir 崩溃文件存储目录
|
||||
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
|
||||
*/
|
||||
public static boolean init(final String crashDir, CrashAppListener listener) {
|
||||
mFinishAppListener = listener;
|
||||
if (isSpace(crashDir)) {
|
||||
dir = null;
|
||||
} else {
|
||||
dir = crashDir.endsWith(FILE_SEP) ? dir : dir + FILE_SEP;
|
||||
}
|
||||
if (mInitialized) {
|
||||
return true;
|
||||
}
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
||||
&& PictureAppMaster.getInstance().getAppContext().getExternalCacheDir() != null) {
|
||||
defaultDir = PictureAppMaster.getInstance().getAppContext().getExternalCacheDir() + FILE_SEP + "crash" + FILE_SEP;
|
||||
} else {
|
||||
defaultDir = PictureAppMaster.getInstance().getAppContext().getCacheDir() + FILE_SEP + "crash" + FILE_SEP;
|
||||
}
|
||||
Thread.setDefaultUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
|
||||
return mInitialized = true;
|
||||
}
|
||||
|
||||
private static boolean createOrExistsFile(String filePath) {
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
return file.isFile();
|
||||
}
|
||||
if (!createOrExistsDir(file.getParentFile())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean createOrExistsDir(File file) {
|
||||
return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
|
||||
}
|
||||
|
||||
private static boolean isSpace(String s) {
|
||||
if (s == null) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0, len = s.length(); i < len; ++i) {
|
||||
if (!Character.isWhitespace(s.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static CrashAppListener mFinishAppListener = null;
|
||||
|
||||
public static void setCrashListener(CrashAppListener crashListener) {
|
||||
mFinishAppListener = crashListener;
|
||||
}
|
||||
|
||||
public interface CrashAppListener {
|
||||
void onFinishApp(final Thread t, final Throwable e);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.luck.picture.lib.decoration;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2016/12/27 下午23:50
|
||||
* @describe:GridSpacingItemDecoration
|
||||
*/
|
||||
|
||||
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
|
||||
|
||||
private int spanCount;
|
||||
private int spacing;
|
||||
private boolean includeEdge;
|
||||
|
||||
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
|
||||
this.spanCount = spanCount;
|
||||
this.spacing = spacing;
|
||||
this.includeEdge = includeEdge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int column = position % spanCount;
|
||||
if (includeEdge) {
|
||||
outRect.left = spacing - column * spacing / spanCount;
|
||||
outRect.right = (column + 1) * spacing / spanCount;
|
||||
if (position < spanCount) {
|
||||
outRect.top = spacing;
|
||||
}
|
||||
outRect.bottom = spacing;
|
||||
} else {
|
||||
outRect.left = column * spacing / spanCount;
|
||||
outRect.right = spacing - (column + 1) * spacing / spanCount;
|
||||
if (position < spanCount) {
|
||||
outRect.top = spacing;
|
||||
}
|
||||
outRect.bottom = spacing;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2018.
|
||||
* Author:Zhao
|
||||
* Email:joeyzhao1005@gmail.com
|
||||
*/
|
||||
|
||||
package com.luck.picture.lib.decoration;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Created by luck on 2017/12/4.
|
||||
* <p>
|
||||
* RecyclerView Bug:IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter的解决方案
|
||||
*/
|
||||
|
||||
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
|
||||
public WrapContentLinearLayoutManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
||||
super(context, orientation, reverseLayout);
|
||||
}
|
||||
|
||||
public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
|
||||
try {
|
||||
super.onLayoutChildren(recycler, state);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.luck.picture.lib.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
import com.luck.picture.lib.listener.OnItemClickListener;
|
||||
import com.luck.picture.lib.tools.ScreenUtils;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-12-12 16:39
|
||||
* @describe:PhotoSelectedDialog
|
||||
*/
|
||||
public class PhotoItemSelectedDialog extends DialogFragment implements View.OnClickListener {
|
||||
public static final int IMAGE_CAMERA = 0;
|
||||
public static final int VIDEO_CAMERA = 1;
|
||||
private TextView tvPicturePhoto, tvPictureVideo, tvPictureCancel;
|
||||
|
||||
public static PhotoItemSelectedDialog newInstance() {
|
||||
PhotoItemSelectedDialog selectedDialog = new PhotoItemSelectedDialog();
|
||||
return selectedDialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
if (getDialog() != null) {
|
||||
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
if (getDialog().getWindow() != null) {
|
||||
getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||
}
|
||||
}
|
||||
return inflater.inflate(R.layout.picture_dialog_camera_selected, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
tvPicturePhoto = view.findViewById(R.id.picture_tv_photo);
|
||||
tvPictureVideo = view.findViewById(R.id.picture_tv_video);
|
||||
tvPictureCancel = view.findViewById(R.id.picture_tv_cancel);
|
||||
tvPictureVideo.setOnClickListener(this);
|
||||
tvPicturePhoto.setOnClickListener(this);
|
||||
tvPictureCancel.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
initDialogStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* DialogFragment Style
|
||||
*/
|
||||
private void initDialogStyle() {
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog != null) {
|
||||
Window window = dialog.getWindow();
|
||||
if (window != null) {
|
||||
window.setLayout(ScreenUtils.getScreenWidth(getContext()), RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
window.setGravity(Gravity.BOTTOM);
|
||||
window.setWindowAnimations(R.style.PictureThemeDialogFragmentAnim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private OnItemClickListener onItemClickListener;
|
||||
|
||||
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int id = v.getId();
|
||||
if (onItemClickListener != null) {
|
||||
if (id == R.id.picture_tv_photo) {
|
||||
onItemClickListener.onItemClick(v, IMAGE_CAMERA);
|
||||
}
|
||||
if (id == R.id.picture_tv_video) {
|
||||
onItemClickListener.onItemClick(v, VIDEO_CAMERA);
|
||||
}
|
||||
}
|
||||
|
||||
dismissAllowingStateLoss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(FragmentManager manager, String tag) {
|
||||
FragmentTransaction ft = manager.beginTransaction();
|
||||
ft.add(this, tag);
|
||||
ft.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.luck.picture.lib.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
|
||||
public class PictureCustomDialog extends Dialog {
|
||||
|
||||
public PictureCustomDialog(Context context, int layout) {
|
||||
super(context, R.style.Picture_Theme_Dialog);
|
||||
setContentView(layout);
|
||||
Window window = getWindow();
|
||||
WindowManager.LayoutParams params = window.getAttributes();
|
||||
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
params.gravity = Gravity.CENTER;
|
||||
window.setAttributes(params);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.luck.picture.lib.dialog;
|
||||
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.Window;
|
||||
|
||||
import com.luck.picture.lib.R;
|
||||
|
||||
public class PictureLoadingDialog extends Dialog {
|
||||
|
||||
public PictureLoadingDialog(Context context) {
|
||||
super(context, R.style.Picture_Theme_AlertDialog);
|
||||
setCancelable(true);
|
||||
setCanceledOnTouchOutside(false);
|
||||
Window window = getWindow();
|
||||
window.setWindowAnimations(R.style.PictureThemeDialogWindowStyle);
|
||||
}
|
||||
|
||||
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.picture_alert_dialog);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.luck.picture.lib.engine;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-03-24 09:36
|
||||
* @describe:CacheResourcesEngine
|
||||
*/
|
||||
public interface CacheResourcesEngine {
|
||||
/**
|
||||
* Get the cache path
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
*/
|
||||
String onCachePath(Context context, String url);
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.luck.picture.lib.engine;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.luck.picture.lib.listener.OnImageCompleteCallback;
|
||||
import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2019-11-13 16:59
|
||||
* @describe:ImageEngine
|
||||
*/
|
||||
public interface ImageEngine {
|
||||
/**
|
||||
* Loading image
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
|
||||
|
||||
/**
|
||||
* Loading image
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView, SubsamplingScaleImageView longImageView, OnImageCompleteCallback callback);
|
||||
|
||||
/**
|
||||
* Load network long graph adaption
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
@Deprecated
|
||||
void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView, SubsamplingScaleImageView longImageView);
|
||||
|
||||
|
||||
/**
|
||||
* Load album catalog pictures
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
void loadFolderImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
|
||||
|
||||
/**
|
||||
* Load GIF image
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
void loadAsGifImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
|
||||
|
||||
/**
|
||||
* Load picture list picture
|
||||
*
|
||||
* @param context
|
||||
* @param url
|
||||
* @param imageView
|
||||
*/
|
||||
void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.luck.picture.lib.engine;
|
||||
|
||||
import com.luck.picture.lib.entity.LocalMedia;
|
||||
import com.luck.picture.lib.listener.OnResultCallbackListener;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020/4/22 11:36 AM
|
||||
* @describe:PictureSelectorEngine
|
||||
*/
|
||||
public interface PictureSelectorEngine {
|
||||
|
||||
/**
|
||||
* Create ImageLoad Engine
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ImageEngine createEngine();
|
||||
|
||||
/**
|
||||
* Create Result Listener
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
OnResultCallbackListener<LocalMedia> getResultCallbackListener();
|
||||
}
|
@ -0,0 +1,471 @@
|
||||
package com.luck.picture.lib.entity;
|
||||
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.luck.picture.lib.config.PictureConfig;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2017-5-24 16:21
|
||||
* @describe:Media Entity
|
||||
*/
|
||||
|
||||
public class LocalMedia implements Parcelable {
|
||||
/**
|
||||
* file to ID
|
||||
*/
|
||||
private long id;
|
||||
/**
|
||||
* original path
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* The real path,But you can't get access from AndroidQ
|
||||
* <p>
|
||||
* It could be empty
|
||||
* <p/>
|
||||
*/
|
||||
private String realPath;
|
||||
|
||||
/**
|
||||
* # Check the original button to get the return value
|
||||
* original path
|
||||
*/
|
||||
private String originalPath;
|
||||
/**
|
||||
* compress path
|
||||
*/
|
||||
private String compressPath;
|
||||
/**
|
||||
* cut path
|
||||
*/
|
||||
private String cutPath;
|
||||
|
||||
/**
|
||||
* Note: this field is only returned in Android Q version
|
||||
* <p>
|
||||
* Android Q image or video path
|
||||
*/
|
||||
private String androidQToPath;
|
||||
/**
|
||||
* video duration
|
||||
*/
|
||||
private long duration;
|
||||
/**
|
||||
* If the selected
|
||||
* # Internal use
|
||||
*/
|
||||
private boolean isChecked;
|
||||
/**
|
||||
* If the cut
|
||||
*/
|
||||
private boolean isCut;
|
||||
/**
|
||||
* media position of list
|
||||
*/
|
||||
public int position;
|
||||
/**
|
||||
* The media number of qq choose styles
|
||||
*/
|
||||
private int num;
|
||||
/**
|
||||
* The media resource type
|
||||
*/
|
||||
private String mimeType;
|
||||
|
||||
/**
|
||||
* Gallery selection mode
|
||||
*/
|
||||
private int chooseModel;
|
||||
|
||||
/**
|
||||
* If the compressed
|
||||
*/
|
||||
private boolean compressed;
|
||||
/**
|
||||
* image or video width
|
||||
* <p>
|
||||
* # If zero occurs, the developer needs to handle it extra
|
||||
*/
|
||||
private int width;
|
||||
/**
|
||||
* image or video height
|
||||
* <p>
|
||||
* # If zero occurs, the developer needs to handle it extra
|
||||
*/
|
||||
private int height;
|
||||
|
||||
/**
|
||||
* file size
|
||||
*/
|
||||
private long size;
|
||||
|
||||
/**
|
||||
* Whether the original image is displayed
|
||||
*/
|
||||
private boolean isOriginal;
|
||||
|
||||
/**
|
||||
* file name
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* Parent Folder Name
|
||||
*/
|
||||
private String parentFolderName;
|
||||
|
||||
/**
|
||||
* orientation info
|
||||
* # For internal use only
|
||||
*/
|
||||
private int orientation = -1;
|
||||
|
||||
/**
|
||||
* loadLongImageStatus
|
||||
* # For internal use only
|
||||
*/
|
||||
public int loadLongImageStatus = PictureConfig.NORMAL;
|
||||
|
||||
/**
|
||||
* isLongImage
|
||||
* # For internal use only
|
||||
*/
|
||||
public boolean isLongImage;
|
||||
|
||||
/**
|
||||
* bucketId
|
||||
*/
|
||||
private long bucketId = -1;
|
||||
|
||||
/**
|
||||
* isMaxSelectEnabledMask
|
||||
* # For internal use only
|
||||
*/
|
||||
private boolean isMaxSelectEnabledMask;
|
||||
|
||||
public LocalMedia() {
|
||||
|
||||
}
|
||||
|
||||
public LocalMedia(String path, long duration, int chooseModel, String mimeType) {
|
||||
this.path = path;
|
||||
this.duration = duration;
|
||||
this.chooseModel = chooseModel;
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public LocalMedia(long id, String path, String fileName, String parentFolderName, long duration, int chooseModel,
|
||||
String mimeType, int width, int height, long size) {
|
||||
this.id = id;
|
||||
this.path = path;
|
||||
this.fileName = fileName;
|
||||
this.parentFolderName = parentFolderName;
|
||||
this.duration = duration;
|
||||
this.chooseModel = chooseModel;
|
||||
this.mimeType = mimeType;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public LocalMedia(long id, String path, String absolutePath, String fileName, String parentFolderName, long duration, int chooseModel,
|
||||
String mimeType, int width, int height, long size, long bucketId) {
|
||||
this.id = id;
|
||||
this.path = path;
|
||||
this.realPath = absolutePath;
|
||||
this.fileName = fileName;
|
||||
this.parentFolderName = parentFolderName;
|
||||
this.duration = duration;
|
||||
this.chooseModel = chooseModel;
|
||||
this.mimeType = mimeType;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.size = size;
|
||||
this.bucketId = bucketId;
|
||||
}
|
||||
|
||||
public LocalMedia(String path, long duration,
|
||||
boolean isChecked, int position, int num, int chooseModel) {
|
||||
this.path = path;
|
||||
this.duration = duration;
|
||||
this.isChecked = isChecked;
|
||||
this.position = position;
|
||||
this.num = num;
|
||||
this.chooseModel = chooseModel;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getCompressPath() {
|
||||
return compressPath;
|
||||
}
|
||||
|
||||
public void setCompressPath(String compressPath) {
|
||||
this.compressPath = compressPath;
|
||||
}
|
||||
|
||||
public String getCutPath() {
|
||||
return cutPath;
|
||||
}
|
||||
|
||||
public void setCutPath(String cutPath) {
|
||||
this.cutPath = cutPath;
|
||||
}
|
||||
|
||||
public String getAndroidQToPath() {
|
||||
return androidQToPath;
|
||||
}
|
||||
|
||||
public void setAndroidQToPath(String androidQToPath) {
|
||||
this.androidQToPath = androidQToPath;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getRealPath() {
|
||||
return realPath;
|
||||
}
|
||||
|
||||
public void setRealPath(String realPath) {
|
||||
this.realPath = realPath;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return isChecked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
isChecked = checked;
|
||||
}
|
||||
|
||||
public boolean isCut() {
|
||||
return isCut;
|
||||
}
|
||||
|
||||
public void setCut(boolean cut) {
|
||||
isCut = cut;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public int getNum() {
|
||||
return num;
|
||||
}
|
||||
|
||||
public void setNum(int num) {
|
||||
this.num = num;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return TextUtils.isEmpty(mimeType) ? "image/jpeg" : mimeType;
|
||||
}
|
||||
|
||||
public void setMimeType(String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public boolean isCompressed() {
|
||||
return compressed;
|
||||
}
|
||||
|
||||
public void setCompressed(boolean compressed) {
|
||||
this.compressed = compressed;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getChooseModel() {
|
||||
return chooseModel;
|
||||
}
|
||||
|
||||
public void setChooseModel(int chooseModel) {
|
||||
this.chooseModel = chooseModel;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public boolean isOriginal() {
|
||||
return isOriginal;
|
||||
}
|
||||
|
||||
public void setOriginal(boolean original) {
|
||||
isOriginal = original;
|
||||
}
|
||||
|
||||
public String getOriginalPath() {
|
||||
return originalPath;
|
||||
}
|
||||
|
||||
public void setOriginalPath(String originalPath) {
|
||||
this.originalPath = originalPath;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getParentFolderName() {
|
||||
return parentFolderName;
|
||||
}
|
||||
|
||||
public void setParentFolderName(String parentFolderName) {
|
||||
this.parentFolderName = parentFolderName;
|
||||
}
|
||||
|
||||
public int getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
public void setOrientation(int orientation) {
|
||||
this.orientation = orientation;
|
||||
}
|
||||
|
||||
public long getBucketId() {
|
||||
return bucketId;
|
||||
}
|
||||
|
||||
public void setBucketId(long bucketId) {
|
||||
this.bucketId = bucketId;
|
||||
}
|
||||
|
||||
public boolean isMaxSelectEnabledMask() {
|
||||
return isMaxSelectEnabledMask;
|
||||
}
|
||||
|
||||
public void setMaxSelectEnabledMask(boolean maxSelectEnabledMask) {
|
||||
isMaxSelectEnabledMask = maxSelectEnabledMask;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(this.id);
|
||||
dest.writeString(this.path);
|
||||
dest.writeString(this.realPath);
|
||||
dest.writeString(this.originalPath);
|
||||
dest.writeString(this.compressPath);
|
||||
dest.writeString(this.cutPath);
|
||||
dest.writeString(this.androidQToPath);
|
||||
dest.writeLong(this.duration);
|
||||
dest.writeByte(this.isChecked ? (byte) 1 : (byte) 0);
|
||||
dest.writeByte(this.isCut ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.position);
|
||||
dest.writeInt(this.num);
|
||||
dest.writeString(this.mimeType);
|
||||
dest.writeInt(this.chooseModel);
|
||||
dest.writeByte(this.compressed ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.width);
|
||||
dest.writeInt(this.height);
|
||||
dest.writeLong(this.size);
|
||||
dest.writeByte(this.isOriginal ? (byte) 1 : (byte) 0);
|
||||
dest.writeString(this.fileName);
|
||||
dest.writeString(this.parentFolderName);
|
||||
dest.writeInt(this.orientation);
|
||||
dest.writeInt(this.loadLongImageStatus);
|
||||
dest.writeByte(this.isLongImage ? (byte) 1 : (byte) 0);
|
||||
dest.writeLong(this.bucketId);
|
||||
dest.writeByte(this.isMaxSelectEnabledMask ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
|
||||
protected LocalMedia(Parcel in) {
|
||||
this.id = in.readLong();
|
||||
this.path = in.readString();
|
||||
this.realPath = in.readString();
|
||||
this.originalPath = in.readString();
|
||||
this.compressPath = in.readString();
|
||||
this.cutPath = in.readString();
|
||||
this.androidQToPath = in.readString();
|
||||
this.duration = in.readLong();
|
||||
this.isChecked = in.readByte() != 0;
|
||||
this.isCut = in.readByte() != 0;
|
||||
this.position = in.readInt();
|
||||
this.num = in.readInt();
|
||||
this.mimeType = in.readString();
|
||||
this.chooseModel = in.readInt();
|
||||
this.compressed = in.readByte() != 0;
|
||||
this.width = in.readInt();
|
||||
this.height = in.readInt();
|
||||
this.size = in.readLong();
|
||||
this.isOriginal = in.readByte() != 0;
|
||||
this.fileName = in.readString();
|
||||
this.parentFolderName = in.readString();
|
||||
this.orientation = in.readInt();
|
||||
this.loadLongImageStatus = in.readInt();
|
||||
this.isLongImage = in.readByte() != 0;
|
||||
this.bucketId = in.readLong();
|
||||
this.isMaxSelectEnabledMask = in.readByte() != 0;
|
||||
}
|
||||
|
||||
public static final Creator<LocalMedia> CREATOR = new Creator<LocalMedia>() {
|
||||
@Override
|
||||
public LocalMedia createFromParcel(Parcel source) {
|
||||
return new LocalMedia(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMedia[] newArray(int size) {
|
||||
return new LocalMedia[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
package com.luck.picture.lib.entity;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2016-12-31 15:21
|
||||
* @describe:MediaFolder Entity
|
||||
*/
|
||||
|
||||
public class LocalMediaFolder implements Parcelable {
|
||||
/**
|
||||
* bucketId
|
||||
*/
|
||||
private long bucketId = -1;
|
||||
/**
|
||||
* Folder name
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* Folder first path
|
||||
*/
|
||||
private String firstImagePath;
|
||||
/**
|
||||
* Folder media num
|
||||
*/
|
||||
private int imageNum;
|
||||
/**
|
||||
* If the selected num
|
||||
*/
|
||||
private int checkedNum;
|
||||
/**
|
||||
* If the selected
|
||||
*/
|
||||
private boolean isChecked;
|
||||
|
||||
/**
|
||||
* type
|
||||
*/
|
||||
private int ofAllType = -1;
|
||||
/**
|
||||
* Whether or not the camera
|
||||
*/
|
||||
private boolean isCameraFolder;
|
||||
|
||||
/**
|
||||
* data
|
||||
*/
|
||||
private List<LocalMedia> data = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* # Internal use
|
||||
* setCurrentDataPage
|
||||
*/
|
||||
private int currentDataPage;
|
||||
|
||||
/**
|
||||
* # Internal use
|
||||
* is load more
|
||||
*/
|
||||
private boolean isHasMore;
|
||||
|
||||
public long getBucketId() {
|
||||
return bucketId;
|
||||
}
|
||||
|
||||
public void setBucketId(long bucketId) {
|
||||
this.bucketId = bucketId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getFirstImagePath() {
|
||||
return firstImagePath;
|
||||
}
|
||||
|
||||
public void setFirstImagePath(String firstImagePath) {
|
||||
this.firstImagePath = firstImagePath;
|
||||
}
|
||||
|
||||
public int getImageNum() {
|
||||
return imageNum;
|
||||
}
|
||||
|
||||
public void setImageNum(int imageNum) {
|
||||
this.imageNum = imageNum;
|
||||
}
|
||||
|
||||
public int getCheckedNum() {
|
||||
return checkedNum;
|
||||
}
|
||||
|
||||
public void setCheckedNum(int checkedNum) {
|
||||
this.checkedNum = checkedNum;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return isChecked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
isChecked = checked;
|
||||
}
|
||||
|
||||
public int getOfAllType() {
|
||||
return ofAllType;
|
||||
}
|
||||
|
||||
public void setOfAllType(int ofAllType) {
|
||||
this.ofAllType = ofAllType;
|
||||
}
|
||||
|
||||
public boolean isCameraFolder() {
|
||||
return isCameraFolder;
|
||||
}
|
||||
|
||||
public void setCameraFolder(boolean cameraFolder) {
|
||||
isCameraFolder = cameraFolder;
|
||||
}
|
||||
|
||||
public List<LocalMedia> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<LocalMedia> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getCurrentDataPage() {
|
||||
return currentDataPage;
|
||||
}
|
||||
|
||||
public void setCurrentDataPage(int currentDataPage) {
|
||||
this.currentDataPage = currentDataPage;
|
||||
}
|
||||
|
||||
public boolean isHasMore() {
|
||||
return isHasMore;
|
||||
}
|
||||
|
||||
public void setHasMore(boolean hasMore) {
|
||||
isHasMore = hasMore;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(this.bucketId);
|
||||
dest.writeString(this.name);
|
||||
dest.writeString(this.firstImagePath);
|
||||
dest.writeInt(this.imageNum);
|
||||
dest.writeInt(this.checkedNum);
|
||||
dest.writeByte(this.isChecked ? (byte) 1 : (byte) 0);
|
||||
dest.writeInt(this.ofAllType);
|
||||
dest.writeByte(this.isCameraFolder ? (byte) 1 : (byte) 0);
|
||||
dest.writeTypedList(this.data);
|
||||
dest.writeInt(this.currentDataPage);
|
||||
dest.writeByte(this.isHasMore ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
|
||||
public LocalMediaFolder() {
|
||||
}
|
||||
|
||||
protected LocalMediaFolder(Parcel in) {
|
||||
this.bucketId = in.readLong();
|
||||
this.name = in.readString();
|
||||
this.firstImagePath = in.readString();
|
||||
this.imageNum = in.readInt();
|
||||
this.checkedNum = in.readInt();
|
||||
this.isChecked = in.readByte() != 0;
|
||||
this.ofAllType = in.readInt();
|
||||
this.isCameraFolder = in.readByte() != 0;
|
||||
this.data = in.createTypedArrayList(LocalMedia.CREATOR);
|
||||
this.currentDataPage = in.readInt();
|
||||
this.isHasMore = in.readByte() != 0;
|
||||
}
|
||||
|
||||
public static final Creator<LocalMediaFolder> CREATOR = new Creator<LocalMediaFolder>() {
|
||||
@Override
|
||||
public LocalMediaFolder createFromParcel(Parcel source) {
|
||||
return new LocalMediaFolder(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMediaFolder[] newArray(int size) {
|
||||
return new LocalMediaFolder[size];
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.luck.picture.lib.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @date:2020-04-17 13:52
|
||||
* @describe:MediaData
|
||||
*/
|
||||
public class MediaData {
|
||||
|
||||
/**
|
||||
* Is there more
|
||||
*/
|
||||
public boolean isHasNextMore;
|
||||
|
||||
/**
|
||||
* data
|
||||
*/
|
||||
public List<LocalMedia> data;
|
||||
|
||||
|
||||
public MediaData() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MediaData(boolean isHasNextMore, List<LocalMedia> data) {
|
||||
super();
|
||||
this.isHasNextMore = isHasNextMore;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.luck.picture.lib.immersive;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2018/3/28 下午1:00
|
||||
* @描述: 沉浸式相关
|
||||
*/
|
||||
|
||||
public class ImmersiveManage {
|
||||
|
||||
/**
|
||||
* 注意:使用最好将布局xml 跟布局加入 android:fitsSystemWindows="true" ,这样可以避免有些手机上布局顶边的问题
|
||||
*
|
||||
* @param baseActivity 这个会留出来状态栏和底栏的空白
|
||||
* @param statusBarColor 状态栏的颜色
|
||||
* @param navigationBarColor 导航栏的颜色
|
||||
* @param isDarkStatusBarIcon 状态栏图标颜色是否是深(黑)色 false状态栏图标颜色为白色
|
||||
*/
|
||||
public static void immersiveAboveAPI23(AppCompatActivity baseActivity, int statusBarColor, int navigationBarColor, boolean isDarkStatusBarIcon) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
immersiveAboveAPI23(baseActivity, false, false, statusBarColor, navigationBarColor, isDarkStatusBarIcon);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param baseActivity
|
||||
* @param statusBarColor 状态栏的颜色
|
||||
* @param navigationBarColor 导航栏的颜色
|
||||
*/
|
||||
public static void immersiveAboveAPI23(AppCompatActivity baseActivity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar, int statusBarColor, int navigationBarColor, boolean isDarkStatusBarIcon) {
|
||||
try {
|
||||
Window window = baseActivity.getWindow();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
//4.4版本及以上 5.0版本及以下
|
||||
window.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
|
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (isMarginStatusBar && isMarginNavigationBar) {
|
||||
//5.0版本及以上
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
|
||||
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
LightStatusBarUtils.setLightStatusBar(baseActivity, isMarginStatusBar
|
||||
, isMarginNavigationBar
|
||||
, statusBarColor == Color.TRANSPARENT
|
||||
, isDarkStatusBarIcon);
|
||||
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
} else if (!isMarginStatusBar && !isMarginNavigationBar) {
|
||||
window.requestFeature(Window.FEATURE_NO_TITLE);
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
|
||||
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
|
||||
LightStatusBarUtils.setLightStatusBar(baseActivity, isMarginStatusBar
|
||||
, isMarginNavigationBar
|
||||
, statusBarColor == Color.TRANSPARENT
|
||||
, isDarkStatusBarIcon);
|
||||
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
|
||||
|
||||
} else if (!isMarginStatusBar && isMarginNavigationBar) {
|
||||
window.requestFeature(Window.FEATURE_NO_TITLE);
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
|
||||
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
|
||||
LightStatusBarUtils.setLightStatusBar(baseActivity, isMarginStatusBar
|
||||
, isMarginNavigationBar
|
||||
, statusBarColor == Color.TRANSPARENT
|
||||
, isDarkStatusBarIcon);
|
||||
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
|
||||
|
||||
} else {
|
||||
//留出来状态栏 不留出来导航栏 没找到办法。。
|
||||
return;
|
||||
}
|
||||
|
||||
window.setStatusBarColor(statusBarColor);
|
||||
window.setNavigationBarColor(navigationBarColor);
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
package com.luck.picture.lib.immersive;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author:luck
|
||||
* @data:2018/3/28 下午1:01
|
||||
* @描述: 沉浸式
|
||||
*/
|
||||
|
||||
public class LightStatusBarUtils {
|
||||
public static void setLightStatusBarAboveAPI23(Activity activity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean dark) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLightStatusBar(Activity activity, boolean dark) {
|
||||
setLightStatusBar(activity, false, false, false, dark);
|
||||
}
|
||||
|
||||
public static void setLightStatusBar(Activity activity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean dark) {
|
||||
switch (RomUtils.getLightStatausBarAvailableRomType()) {
|
||||
case RomUtils.AvailableRomType.MIUI:
|
||||
if (RomUtils.getMIUIVersionCode() >= 7) {
|
||||
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
} else {
|
||||
setMIUILightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
}
|
||||
break;
|
||||
|
||||
case RomUtils.AvailableRomType.FLYME:
|
||||
setFlymeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
break;
|
||||
|
||||
case RomUtils.AvailableRomType.ANDROID_NATIVE:
|
||||
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
break;
|
||||
|
||||
case RomUtils.AvailableRomType.NA:
|
||||
// N/A do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean setMIUILightStatusBar(Activity activity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean darkmode) {
|
||||
initStatusBarStyle(activity, isMarginStatusBar, isMarginNavigationBar);
|
||||
|
||||
Class<? extends Window> clazz = activity.getWindow().getClass();
|
||||
try {
|
||||
int darkModeFlag = 0;
|
||||
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
|
||||
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
|
||||
darkModeFlag = field.getInt(layoutParams);
|
||||
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
|
||||
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, darkmode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean setFlymeLightStatusBar(Activity activity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean dark) {
|
||||
boolean result = false;
|
||||
if (activity != null) {
|
||||
initStatusBarStyle(activity, isMarginStatusBar, isMarginNavigationBar);
|
||||
try {
|
||||
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
||||
Field darkFlag = WindowManager.LayoutParams.class
|
||||
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
|
||||
Field meizuFlags = WindowManager.LayoutParams.class
|
||||
.getDeclaredField("meizuFlags");
|
||||
darkFlag.setAccessible(true);
|
||||
meizuFlags.setAccessible(true);
|
||||
int bit = darkFlag.getInt(null);
|
||||
int value = meizuFlags.getInt(lp);
|
||||
if (dark) {
|
||||
value |= bit;
|
||||
} else {
|
||||
value &= ~bit;
|
||||
}
|
||||
meizuFlags.setInt(lp, value);
|
||||
activity.getWindow().setAttributes(lp);
|
||||
result = true;
|
||||
|
||||
if (RomUtils.getFlymeVersion() >= 7) {
|
||||
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setAndroidNativeLightStatusBar(activity, isMarginStatusBar, isMarginNavigationBar, isTransStatusBar, dark);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@TargetApi(11)
|
||||
private static void setAndroidNativeLightStatusBar(Activity activity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar, boolean isTransStatusBar, boolean isDarkStatusBarIcon) {
|
||||
|
||||
try {
|
||||
if (isTransStatusBar) {
|
||||
Window window = activity.getWindow();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (isMarginStatusBar && isMarginNavigationBar) {
|
||||
//5.0版本及以上
|
||||
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
} else {
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
} else if (!isMarginStatusBar && !isMarginNavigationBar) {
|
||||
|
||||
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
} else {
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
|
||||
|
||||
} else if (!isMarginStatusBar && isMarginNavigationBar) {
|
||||
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
} else {
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
//留出来状态栏 不留出来导航栏 没找到办法。。
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
View decor = activity.getWindow().getDecorView();
|
||||
if (isDarkStatusBarIcon && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
} else {
|
||||
// We want to change tint color to white again.
|
||||
// You can also record the flags in advance so that you can turn UI back completely if
|
||||
// you have set other flags before, such as translucent or full screen.
|
||||
decor.setSystemUiVisibility(0);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void initStatusBarStyle(Activity activity, boolean isMarginStatusBar
|
||||
, boolean isMarginNavigationBar) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
if (isMarginStatusBar && isMarginNavigationBar) {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
} else if (!isMarginStatusBar && !isMarginNavigationBar) {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
} else if (!isMarginStatusBar && isMarginNavigationBar) {
|
||||
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
} else {
|
||||
//留出来状态栏 不留出来导航栏 没找到办法。。
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|