version:
update:修复圆角显示,封面缩略图拉伸 fix bug:
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 625 B After Width: | Height: | Size: 625 B |
|
Before Width: | Height: | Size: 378 B After Width: | Height: | Size: 378 B |
|
Before Width: | Height: | Size: 531 B After Width: | Height: | Size: 531 B |
|
Before Width: | Height: | Size: 486 B After Width: | Height: | Size: 486 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 176 B After Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 169 B After Width: | Height: | Size: 169 B |
|
Before Width: | Height: | Size: 169 B After Width: | Height: | Size: 169 B |
|
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 168 B |
|
Before Width: | Height: | Size: 169 B After Width: | Height: | Size: 169 B |
|
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 168 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 469 B After Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 717 B |
|
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 958 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 224 B |
|
Before Width: | Height: | Size: 922 B After Width: | Height: | Size: 922 B |
|
Before Width: | Height: | Size: 946 B After Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 470 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -94,6 +94,7 @@ dependencies {
|
|||||||
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
|
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
|
||||||
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
|
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
|
||||||
implementation 'com.github.SheHuan:NiceImageView:1.0.5'
|
// implementation 'com.github.SheHuan:NiceImageView:1.0.5'
|
||||||
implementation project(path: ':library')
|
implementation project(path: ':JZVideo')
|
||||||
|
implementation project(path: ':niceimageview')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,10 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
String[] permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private TextView tips;
|
private TextView tips, tv_scan;
|
||||||
private SwipeRefreshLayout refreshLayout;
|
private SwipeRefreshLayout refreshLayout;
|
||||||
private VideoAdapter adapter;
|
private VideoAdapter adapter;
|
||||||
|
private List<String> paths = new ArrayList<>();
|
||||||
private RecycleGridLayoutManager mManager;
|
private RecycleGridLayoutManager mManager;
|
||||||
|
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
initView();
|
initView();
|
||||||
// String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator;
|
// String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator;
|
||||||
// traverseFolder(rootPath);
|
// traverseFolder(rootPath);
|
||||||
|
|
||||||
ScanTask scanTask = new ScanTask();
|
ScanTask scanTask = new ScanTask();
|
||||||
scanTask.execute();
|
scanTask.execute();
|
||||||
}
|
}
|
||||||
@@ -89,6 +91,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
private void initView() {
|
private void initView() {
|
||||||
initActionBar();
|
initActionBar();
|
||||||
tips = findViewById(R.id.tips);
|
tips = findViewById(R.id.tips);
|
||||||
|
tv_scan = findViewById(R.id.tv_scan);
|
||||||
refreshLayout = findViewById(R.id.swipeRefreshLayout);
|
refreshLayout = findViewById(R.id.swipeRefreshLayout);
|
||||||
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -111,6 +114,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x),
|
recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x),
|
||||||
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);
|
((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
|
||||||
|
adapter = new VideoAdapter(MainActivity.this);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initActionBar() {
|
private void initActionBar() {
|
||||||
@@ -198,6 +203,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> doInBackground(Void... voids) {
|
protected List<String> doInBackground(Void... voids) {
|
||||||
|
long s1 = System.currentTimeMillis();
|
||||||
|
paths.clear();
|
||||||
List<String> fileList = new ArrayList<>();
|
List<String> fileList = new ArrayList<>();
|
||||||
String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator;
|
String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator;
|
||||||
File file = new File(rootPath);
|
File file = new File(rootPath);
|
||||||
@@ -232,6 +239,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
} else {
|
} else {
|
||||||
Log.e("traverseFolder1", "文件不存在!");
|
Log.e("traverseFolder1", "文件不存在!");
|
||||||
}
|
}
|
||||||
|
Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms");
|
||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,22 +247,26 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
protected void onProgressUpdate(String... values) {
|
protected void onProgressUpdate(String... values) {
|
||||||
super.onProgressUpdate(values);
|
super.onProgressUpdate(values);
|
||||||
// Log.e("ScanTask", "onProgressUpdate: " + values[0]);
|
// Log.e("ScanTask", "onProgressUpdate: " + values[0]);
|
||||||
|
paths.add(values[0]);
|
||||||
|
tv_scan.setVisibility(View.VISIBLE);
|
||||||
|
tv_scan.setText("正在扫描:" + values[0]);
|
||||||
|
adapter.setData(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(List<String> strings) {
|
protected void onPostExecute(List<String> strings) {
|
||||||
super.onPostExecute(strings);
|
super.onPostExecute(strings);
|
||||||
Log.e("ScanTask", "onPostExecute: " + strings);
|
Log.e("ScanTask", "onPostExecute: " + strings.size());
|
||||||
if (strings.size() == 0) {
|
if (strings.size() == 0) {
|
||||||
tips.setVisibility(View.VISIBLE);
|
tips.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
tips.setVisibility(View.GONE);
|
tips.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
adapter = new VideoAdapter(MainActivity.this, strings);
|
adapter.setData(strings);
|
||||||
// recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
|
// recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
}
|
}
|
||||||
|
tv_scan.setVisibility(View.GONE);
|
||||||
refreshLayout.setRefreshing(false);
|
refreshLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.media.Image;
|
import android.media.Image;
|
||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
@@ -17,10 +18,13 @@ import android.widget.TextView;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
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.shehuan.niv.NiceImageView;
|
||||||
import com.uiui.videoplayer.R;
|
import com.uiui.videoplayer.R;
|
||||||
import com.uiui.videoplayer.activity.ActivityTikTok;
|
import com.uiui.videoplayer.activity.ActivityTikTok;
|
||||||
@@ -65,6 +69,11 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
|
|||||||
Bitmap frame;
|
Bitmap frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setData(List<String> paths) {
|
||||||
|
this.videoPath = paths;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public VideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public VideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
@@ -76,61 +85,66 @@ public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.VideoHolder>
|
|||||||
public void onBindViewHolder(@NonNull final VideoHolder holder, final int position) {
|
public void onBindViewHolder(@NonNull final VideoHolder holder, final int position) {
|
||||||
final String path = videoPath.get(position);
|
final String path = videoPath.get(position);
|
||||||
File file = new File(path);
|
File file = new File(path);
|
||||||
if (file.exists() && file.isFile()) {
|
// if (file.exists() && file.isFile()) {
|
||||||
// BitmapRetultListener bitmapRetultListener = new BitmapRetultListener() {
|
// BitmapRetultListener bitmapRetultListener = new BitmapRetultListener() {
|
||||||
// @Override
|
// @Override
|
||||||
// public void onScanCompleted(Bitmap bitmap) {
|
// public void onScanCompleted(Bitmap bitmap) {
|
||||||
// Glide.with(holder.video_image).load(bitmap).into(holder.video_image);
|
// Glide.with(holder.video_image).load(bitmap).into(holder.video_image);
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
Observable.create(new ObservableOnSubscribe<VideoResult>() {
|
Observable.create(new ObservableOnSubscribe<VideoResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void subscribe(ObservableEmitter<VideoResult> emitter) throws Exception {
|
public void subscribe(ObservableEmitter<VideoResult> emitter) throws Exception {
|
||||||
FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
|
FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
|
||||||
mmr.setDataSource(path);
|
mmr.setDataSource(path);
|
||||||
String duration = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
|
String duration = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||||
Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象.
|
Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象.
|
||||||
Long time = Long.valueOf(duration);
|
Long time = Long.valueOf(duration);
|
||||||
|
|
||||||
mmr.release();
|
mmr.release();
|
||||||
VideoResult result = new VideoResult();
|
VideoResult result = new VideoResult();
|
||||||
result.frame = bitmap;
|
result.frame = bitmap;
|
||||||
result.time = time;
|
result.time = time;
|
||||||
emitter.onNext(result);
|
emitter.onNext(result);
|
||||||
}
|
}
|
||||||
}).subscribeOn(Schedulers.newThread())
|
}).subscribeOn(Schedulers.newThread())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(new Observer<VideoResult>() {
|
.subscribe(new Observer<VideoResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSubscribe(Disposable d) {
|
public void onSubscribe(Disposable d) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(VideoResult result) {
|
||||||
|
try {
|
||||||
|
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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(VideoResult result) {
|
public void onError(Throwable e) {
|
||||||
try {
|
|
||||||
Glide.with(holder.video_image).load(result.frame).into(holder.video_image);
|
|
||||||
holder.duration.setText(Utils.TimeFormat(result.time));
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Throwable e) {
|
public void onComplete() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// this.listener = bitmapRetultListener;
|
// this.listener = bitmapRetultListener;
|
||||||
holder.title.setText(getFileName(path));
|
holder.title.setText(getFileName(path));
|
||||||
Log.e("title:", holder.title.getText().toString());
|
Log.e("title:", holder.title.getText().toString());
|
||||||
}
|
// }
|
||||||
holder.root.setOnClickListener(new View.OnClickListener() {
|
holder.root.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activity.MainActivity">
|
tools:context=".activity.MainActivity">
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
||||||
android:id="@+id/swipeRefreshLayout"
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="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.recyclerview.widget.RecyclerView
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/swipeRefreshLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
android:background="@color/white">
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tips"
|
android:id="@+id/tips"
|
||||||
@@ -27,7 +36,21 @@
|
|||||||
android:text="没有找到视频文件"
|
android:text="没有找到视频文件"
|
||||||
android:textColor="@color/defaultColor"
|
android:textColor="@color/defaultColor"
|
||||||
android:visibility="gone" />
|
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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,24 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activity.MainActivity">
|
tools:context=".activity.MainActivity">
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
||||||
android:id="@+id/swipeRefreshLayout"
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/white"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
>
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/tv_scan">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/swipeRefreshLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
>
|
android:background="@color/white">
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tips"
|
android:id="@+id/tips"
|
||||||
@@ -28,7 +36,21 @@
|
|||||||
android:text="没有找到视频文件"
|
android:text="没有找到视频文件"
|
||||||
android:textColor="@color/defaultColor"
|
android:textColor="@color/defaultColor"
|
||||||
android:visibility="gone" />
|
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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -12,12 +12,11 @@
|
|||||||
android:layout_height="162dp"
|
android:layout_height="162dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="centerCrop"
|
||||||
app:is_cover_src="true"
|
app:is_cover_src="true"
|
||||||
app:corner_radius="5dp"
|
app:corner_radius="10dp"
|
||||||
android:background="@color/black"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.504"
|
app:layout_constraintHorizontal_bias="0.500"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|||||||
1
niceimageview/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
26
niceimageview/build.gradle
Normal 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
@@ -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
|
||||||
2
niceimageview/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.shehuan.niv" />
|
||||||
337
niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
niceimageview/src/main/java/com/shehuan/niv/Utils.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
niceimageview/src/main/res/values/attrs.xml
Normal 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>
|
||||||
3
niceimageview/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">niceimageview</string>
|
||||||
|
</resources>
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
rootProject.name='快易播放器'
|
rootProject.name='快易播放器'
|
||||||
include ':app', ':library'
|
include ':app', ':JZVideo', ':niceimageview'
|
||||||
|
|||||||