update:修复圆角显示,封面缩略图拉伸
fix bug:
This commit is contained in:
2021-03-08 14:24:34 +08:00
parent 527587b926
commit a92df28f33
91 changed files with 557 additions and 68 deletions

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 625 B

View File

Before

Width:  |  Height:  |  Size: 378 B

After

Width:  |  Height:  |  Size: 378 B

View File

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 531 B

View File

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 486 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 176 B

After

Width:  |  Height:  |  Size: 176 B

View File

Before

Width:  |  Height:  |  Size: 169 B

After

Width:  |  Height:  |  Size: 169 B

View File

Before

Width:  |  Height:  |  Size: 169 B

After

Width:  |  Height:  |  Size: 169 B

View File

Before

Width:  |  Height:  |  Size: 168 B

After

Width:  |  Height:  |  Size: 168 B

View File

Before

Width:  |  Height:  |  Size: 169 B

After

Width:  |  Height:  |  Size: 169 B

View File

Before

Width:  |  Height:  |  Size: 168 B

After

Width:  |  Height:  |  Size: 168 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 469 B

After

Width:  |  Height:  |  Size: 469 B

View File

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 717 B

View File

Before

Width:  |  Height:  |  Size: 164 B

After

Width:  |  Height:  |  Size: 164 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 958 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 224 B

After

Width:  |  Height:  |  Size: 224 B

View File

Before

Width:  |  Height:  |  Size: 922 B

After

Width:  |  Height:  |  Size: 922 B

View File

Before

Width:  |  Height:  |  Size: 946 B

After

Width:  |  Height:  |  Size: 946 B

View File

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 470 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -94,6 +94,7 @@ dependencies {
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
implementation 'com.github.SheHuan:NiceImageView:1.0.5'
implementation project(path: ':library')
// implementation 'com.github.SheHuan:NiceImageView:1.0.5'
implementation project(path: ':JZVideo')
implementation project(path: ':niceimageview')
}

View File

@@ -48,9 +48,10 @@ public class MainActivity extends AppCompatActivity {
String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
private RecyclerView recyclerView;
private TextView tips;
private TextView tips, tv_scan;
private SwipeRefreshLayout refreshLayout;
private VideoAdapter adapter;
private List<String> paths = new ArrayList<>();
private RecycleGridLayoutManager mManager;
@@ -62,6 +63,7 @@ public class MainActivity extends AppCompatActivity {
initView();
// String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator;
// traverseFolder(rootPath);
ScanTask scanTask = new ScanTask();
scanTask.execute();
}
@@ -89,6 +91,7 @@ public class MainActivity extends AppCompatActivity {
private void initView() {
initActionBar();
tips = findViewById(R.id.tips);
tv_scan = findViewById(R.id.tv_scan);
refreshLayout = findViewById(R.id.swipeRefreshLayout);
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
@@ -111,6 +114,8 @@ public class MainActivity extends AppCompatActivity {
recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x),
getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x)));
((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
adapter = new VideoAdapter(MainActivity.this);
recyclerView.setAdapter(adapter);
}
private void initActionBar() {
@@ -198,6 +203,8 @@ public class MainActivity extends AppCompatActivity {
@Override
protected List<String> doInBackground(Void... voids) {
long s1 = System.currentTimeMillis();
paths.clear();
List<String> fileList = new ArrayList<>();
String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator;
File file = new File(rootPath);
@@ -232,6 +239,7 @@ public class MainActivity extends AppCompatActivity {
} else {
Log.e("traverseFolder1", "文件不存在!");
}
Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms");
return fileList;
}
@@ -239,22 +247,26 @@ public class MainActivity extends AppCompatActivity {
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// Log.e("ScanTask", "onProgressUpdate: " + values[0]);
paths.add(values[0]);
tv_scan.setVisibility(View.VISIBLE);
tv_scan.setText("正在扫描:" + values[0]);
adapter.setData(paths);
}
@Override
protected void onPostExecute(List<String> strings) {
super.onPostExecute(strings);
Log.e("ScanTask", "onPostExecute: " + strings);
Log.e("ScanTask", "onPostExecute: " + strings.size());
if (strings.size() == 0) {
tips.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
tips.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
adapter = new VideoAdapter(MainActivity.this, strings);
adapter.setData(strings);
// recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
recyclerView.setAdapter(adapter);
}
tv_scan.setVisibility(View.GONE);
refreshLayout.setRefreshing(false);
}
}

View File

@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.media.Image;
import android.media.MediaMetadataRetriever;
import android.os.AsyncTask;
@@ -17,10 +18,13 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.shehuan.niv.NiceImageView;
import com.uiui.videoplayer.R;
import com.uiui.videoplayer.activity.ActivityTikTok;
@@ -65,6 +69,11 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
Bitmap frame;
}
public void setData(List<String> paths) {
this.videoPath = paths;
notifyDataSetChanged();
}
@NonNull
@Override
public VideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@@ -76,7 +85,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
public void onBindViewHolder(@NonNull final VideoHolder holder, final int position) {
final String path = videoPath.get(position);
File file = new File(path);
if (file.exists() && file.isFile()) {
// if (file.exists() && file.isFile()) {
// BitmapRetultListener bitmapRetultListener = new BitmapRetultListener() {
// @Override
// public void onScanCompleted(Bitmap bitmap) {
@@ -109,7 +118,12 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
@Override
public void onNext(VideoResult result) {
try {
Glide.with(holder.video_image).load(result.frame).into(holder.video_image);
Glide.with(holder.video_image).load(result.frame).skipMemoryCache(false).into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
holder.video_image.setImageDrawable(resource);
}
});
holder.duration.setText(Utils.TimeFormat(result.time));
} catch (Exception e) {
@@ -130,7 +144,7 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
// this.listener = bitmapRetultListener;
holder.title.setText(getFileName(path));
Log.e("title:", holder.title.getText().toString());
}
// }
holder.root.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

View File

@@ -1,23 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_scan">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
android:background="@color/white">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</androidx.recyclerview.widget.RecyclerView>
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/tips"
@@ -27,7 +36,21 @@
android:text="没有找到视频文件"
android:textColor="@color/defaultColor"
android:visibility="gone" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_scan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLines="1"
android:text=""
android:singleLine="true"
android:textColor="@color/defaultColor"
android:textSize="18sp"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,24 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_scan">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
>
android:background="@color/white">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</androidx.recyclerview.widget.RecyclerView>
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/tips"
@@ -28,7 +36,21 @@
android:text="没有找到视频文件"
android:textColor="@color/defaultColor"
android:visibility="gone" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_scan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLines="1"
android:text=""
android:singleLine="true"
android:textColor="@color/defaultColor"
android:textSize="18sp"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -12,12 +12,11 @@
android:layout_height="162dp"
android:layout_marginTop="4dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:scaleType="centerCrop"
app:is_cover_src="true"
app:corner_radius="5dp"
android:background="@color/black"
app:corner_radius="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintHorizontal_bias="0.500"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

1
niceimageview/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,26 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
}

21
niceimageview/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# 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

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shehuan.niv" />

View File

@@ -0,0 +1,337 @@
package com.shehuan.niv;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.os.Build;
import android.util.AttributeSet;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
public class NiceImageView extends AppCompatImageView {
private Context context;
private boolean isCircle; // 是否显示为圆形如果为圆形则设置的corner无效
private boolean isCoverSrc; // border、inner_border是否覆盖图片
private int borderWidth; // 边框宽度
private int borderColor = Color.WHITE; // 边框颜色
private int innerBorderWidth; // 内层边框宽度
private int innerBorderColor = Color.WHITE; // 内层边框充色
private int cornerRadius; // 统一设置圆角半径,优先级高于单独设置每个角的半径
private int cornerTopLeftRadius; // 左上角圆角半径
private int cornerTopRightRadius; // 右上角圆角半径
private int cornerBottomLeftRadius; // 左下角圆角半径
private int cornerBottomRightRadius; // 右下角圆角半径
private int maskColor; // 遮罩颜色
private Xfermode xfermode;
private int width;
private int height;
private float radius;
private float[] borderRadii;
private float[] srcRadii;
private RectF srcRectF; // 图片占的矩形区域
private RectF borderRectF; // 边框的矩形区域
private Paint paint;
private Path path; // 用来裁剪图片的ptah
private Path srcPath; // 图片区域大小的path
public NiceImageView(Context context) {
this(context, null);
}
public NiceImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NiceImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.NiceImageView, 0, 0);
for (int i = 0; i < ta.getIndexCount(); i++) {
int attr = ta.getIndex(i);
if (attr == R.styleable.NiceImageView_is_cover_src) {
isCoverSrc = ta.getBoolean(attr, isCoverSrc);
} else if (attr == R.styleable.NiceImageView_is_circle) {
isCircle = ta.getBoolean(attr, isCircle);
} else if (attr == R.styleable.NiceImageView_border_width) {
borderWidth = ta.getDimensionPixelSize(attr, borderWidth);
} else if (attr == R.styleable.NiceImageView_border_color) {
borderColor = ta.getColor(attr, borderColor);
} else if (attr == R.styleable.NiceImageView_inner_border_width) {
innerBorderWidth = ta.getDimensionPixelSize(attr, innerBorderWidth);
} else if (attr == R.styleable.NiceImageView_inner_border_color) {
innerBorderColor = ta.getColor(attr, innerBorderColor);
} else if (attr == R.styleable.NiceImageView_corner_radius) {
cornerRadius = ta.getDimensionPixelSize(attr, cornerRadius);
} else if (attr == R.styleable.NiceImageView_corner_top_left_radius) {
cornerTopLeftRadius = ta.getDimensionPixelSize(attr, cornerTopLeftRadius);
} else if (attr == R.styleable.NiceImageView_corner_top_right_radius) {
cornerTopRightRadius = ta.getDimensionPixelSize(attr, cornerTopRightRadius);
} else if (attr == R.styleable.NiceImageView_corner_bottom_left_radius) {
cornerBottomLeftRadius = ta.getDimensionPixelSize(attr, cornerBottomLeftRadius);
} else if (attr == R.styleable.NiceImageView_corner_bottom_right_radius) {
cornerBottomRightRadius = ta.getDimensionPixelSize(attr, cornerBottomRightRadius);
} else if (attr == R.styleable.NiceImageView_mask_color) {
maskColor = ta.getColor(attr, maskColor);
}
}
ta.recycle();
borderRadii = new float[8];
srcRadii = new float[8];
borderRectF = new RectF();
srcRectF = new RectF();
paint = new Paint();
path = new Path();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
} else {
xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
srcPath = new Path();
}
calculateRadii();
clearInnerBorderWidth();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
initBorderRectF();
initSrcRectF();
}
@Override
protected void onDraw(Canvas canvas) {
// 使用图形混合模式来显示指定区域的图片
canvas.saveLayer(srcRectF, null, Canvas.ALL_SAVE_FLAG);
if (!isCoverSrc) {
float sx = 1.0f * (width - 2 * borderWidth - 2 * innerBorderWidth) / width;
float sy = 1.0f * (height - 2 * borderWidth - 2 * innerBorderWidth) / height;
// 缩小画布使图片内容不被borders覆盖
canvas.scale(sx, sy, width / 2.0f, height / 2.0f);
}
super.onDraw(canvas);
paint.reset();
path.reset();
if (isCircle) {
path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
} else {
path.addRoundRect(srcRectF, srcRadii, Path.Direction.CCW);
}
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setXfermode(xfermode);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
canvas.drawPath(path, paint);
} else {
srcPath.addRect(srcRectF, Path.Direction.CCW);
// 计算tempPath和path的差集
srcPath.op(path, Path.Op.DIFFERENCE);
canvas.drawPath(srcPath, paint);
srcPath.reset();//1
}
paint.setXfermode(null);
// 绘制遮罩
if (maskColor != 0) {
paint.setColor(maskColor);
canvas.drawPath(path, paint);
}
// 恢复画布
canvas.restore();
// 绘制边框
drawBorders(canvas);
}
private void drawBorders(Canvas canvas) {
if (isCircle) {
if (borderWidth > 0) {
drawCircleBorder(canvas, borderWidth, borderColor, radius - borderWidth / 2.0f);
}
if (innerBorderWidth > 0) {
drawCircleBorder(canvas, innerBorderWidth, innerBorderColor, radius - borderWidth - innerBorderWidth / 2.0f);
}
} else {
if (borderWidth > 0) {
drawRectFBorder(canvas, borderWidth, borderColor, borderRectF, borderRadii);
}
}
}
private void drawCircleBorder(Canvas canvas, int borderWidth, int borderColor, float radius) {
initBorderPaint(borderWidth, borderColor);
path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
canvas.drawPath(path, paint);
}
private void drawRectFBorder(Canvas canvas, int borderWidth, int borderColor, RectF rectF, float[] radii) {
initBorderPaint(borderWidth, borderColor);
path.addRoundRect(rectF, radii, Path.Direction.CCW);
canvas.drawPath(path, paint);
}
private void initBorderPaint(int borderWidth, int borderColor) {
path.reset();
paint.setStrokeWidth(borderWidth);
paint.setColor(borderColor);
paint.setStyle(Paint.Style.STROKE);
}
/**
* 计算外边框的RectF
*/
private void initBorderRectF() {
if (!isCircle) {
borderRectF.set(borderWidth / 2.0f, borderWidth / 2.0f, width - borderWidth / 2.0f, height - borderWidth / 2.0f);
}
}
/**
* 计算图片原始区域的RectF
*/
private void initSrcRectF() {
if (isCircle) {
radius = Math.min(width, height) / 2.0f;
srcRectF.set(width / 2.0f - radius, height / 2.0f - radius, width / 2.0f + radius, height / 2.0f + radius);
} else {
srcRectF.set(0, 0, width, height);
if (isCoverSrc) {
srcRectF = borderRectF;
}
}
}
/**
* 计算RectF的圆角半径
*/
private void calculateRadii() {
if (isCircle) {
return;
}
if (cornerRadius > 0) {
for (int i = 0; i < borderRadii.length; i++) {
borderRadii[i] = cornerRadius;
srcRadii[i] = cornerRadius - borderWidth / 2.0f;
}
} else {
borderRadii[0] = borderRadii[1] = cornerTopLeftRadius;
borderRadii[2] = borderRadii[3] = cornerTopRightRadius;
borderRadii[4] = borderRadii[5] = cornerBottomRightRadius;
borderRadii[6] = borderRadii[7] = cornerBottomLeftRadius;
srcRadii[0] = srcRadii[1] = cornerTopLeftRadius - borderWidth / 2.0f;
srcRadii[2] = srcRadii[3] = cornerTopRightRadius - borderWidth / 2.0f;
srcRadii[4] = srcRadii[5] = cornerBottomRightRadius - borderWidth / 2.0f;
srcRadii[6] = srcRadii[7] = cornerBottomLeftRadius - borderWidth / 2.0f;
}
}
private void calculateRadiiAndRectF(boolean reset) {
if (reset) {
cornerRadius = 0;
}
calculateRadii();
initBorderRectF();
invalidate();
}
/**
* 目前圆角矩形情况下不支持inner_border需要将其置0
*/
private void clearInnerBorderWidth() {
if (!isCircle) {
this.innerBorderWidth = 0;
}
}
public void isCoverSrc(boolean isCoverSrc) {
this.isCoverSrc = isCoverSrc;
initSrcRectF();
invalidate();
}
public void isCircle(boolean isCircle) {
this.isCircle = isCircle;
clearInnerBorderWidth();
initSrcRectF();
invalidate();
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = Utils.dp2px(context, borderWidth);
calculateRadiiAndRectF(false);
}
public void setBorderColor(@ColorInt int borderColor) {
this.borderColor = borderColor;
invalidate();
}
public void setInnerBorderWidth(int innerBorderWidth) {
this.innerBorderWidth = Utils.dp2px(context, innerBorderWidth);
clearInnerBorderWidth();
invalidate();
}
public void setInnerBorderColor(@ColorInt int innerBorderColor) {
this.innerBorderColor = innerBorderColor;
invalidate();
}
public void setCornerRadius(int cornerRadius) {
this.cornerRadius = Utils.dp2px(context, cornerRadius);
calculateRadiiAndRectF(false);
}
public void setCornerTopLeftRadius(int cornerTopLeftRadius) {
this.cornerTopLeftRadius = Utils.dp2px(context, cornerTopLeftRadius);
calculateRadiiAndRectF(true);
}
public void setCornerTopRightRadius(int cornerTopRightRadius) {
this.cornerTopRightRadius = Utils.dp2px(context, cornerTopRightRadius);
calculateRadiiAndRectF(true);
}
public void setCornerBottomLeftRadius(int cornerBottomLeftRadius) {
this.cornerBottomLeftRadius = Utils.dp2px(context, cornerBottomLeftRadius);
calculateRadiiAndRectF(true);
}
public void setCornerBottomRightRadius(int cornerBottomRightRadius) {
this.cornerBottomRightRadius = Utils.dp2px(context, cornerBottomRightRadius);
calculateRadiiAndRectF(true);
}
public void setMaskColor(@ColorInt int maskColor) {
this.maskColor = maskColor;
invalidate();
}
}

View File

@@ -0,0 +1,11 @@
package com.shehuan.niv;
import android.content.Context;
public class Utils {
public static int dp2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NiceImageView">
<attr name="is_circle" format="boolean" />
<attr name="is_cover_src" format="boolean" />
<attr name="corner_radius" format="dimension" />
<attr name="corner_top_left_radius" format="dimension" />
<attr name="corner_top_right_radius" format="dimension" />
<attr name="corner_bottom_left_radius" format="dimension" />
<attr name="corner_bottom_right_radius" format="dimension" />
<attr name="border_width" format="dimension" />
<attr name="border_color" format="color" />
<attr name="inner_border_width" format="dimension" />
<attr name="inner_border_color" format="color" />
<attr name="mask_color" format="color" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">niceimageview</string>
</resources>

View File

@@ -1,2 +1,2 @@
rootProject.name='快易播放器'
include ':app', ':library'
include ':app', ':JZVideo', ':niceimageview'