标签:instant 项目 解耦 接口隔离 适合 sdn bottom setimage offset
大图查看器是许多app的常用功能,主要使用场景是用户点击图片,然后启动一个新界面来展示图片的完整尺寸,并能通过手势移动图片以及放大缩小。当然,上面说的是最基本的功能,实际使用中还要包括:如果是本地图片应该可以移除,如果是网络图片,应提供一个保存到本地的功能等。
本文为什么叫封装一个大图查看器,而不是叫做编写一个大图查看器呢?因为大图查看器的最核心功能,展示图片以及手势操控我们使用了一个开源库来完成,这个开源库叫做subsampling-scale-image-view,这个开源库非常靠谱,使用也非常简单,我记得知乎的Android app中也是使用了这个库。这个库的Github地址是:subsampling-scale-image-view。
我先把我做出来的效果图展示出来:
首先第一张是:
然后来看第二张:
两张界面截图展示的是同一张图片,但区别在于,第一张图片右下角有一个下载的图标,对应的是查看网络图片这种方式(大家都需要保存网络图片这个功能);而第二张图片右下角没有了图标,而右上角有一个垃圾桶的图标,用来进行移除操作,想象一下,本来查看的就是本地图片,那用户也就不用再保存它一次了,而移除操作在很多实际使用场景中有效,比如说在微信中,你想发朋友圈,你选择了一几张本地照片以后进行大图浏览,而这时候你发现其中几张不太好,想移除它,于是为了用户方便,应该给用户一个在大图查看器中进行移除的方法。
<style name="Dialog_Fullscreen"> <item name="android:windowFullscreen">true</item> <item name="android:windowNoTitle">true</item> </style>这就是全屏Dialog的实现方式。接下来,定义Dialog的布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <android.support.v4.view.ViewPager android:id="@+id/scale_image_view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/scale_image_close" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:padding="24dp" android:src="@drawable/ic_clear_white_24dp" tools:ignore="ContentDescription"/> <ImageView android:id="@+id/scale_image_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentEnd="true" android:padding="24dp" android:src="@drawable/ic_delete_white_24dp" tools:ignore="ContentDescription"/> <ImageView android:id="@+id/scale_image_save" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:padding="24dp" android:src="@drawable/ic_file_download_white_24dp" tools:ignore="ContentDescription"/> <TextView android:id="@+id/scale_image_count" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:layout_marginBottom="32dp" android:textSize="16sp" android:textColor="@android:color/white"/> </RelativeLayout>
public class ScaleImageView { private static final byte URLS = 0; private static final byte FILES = 1; private byte status; private Activity activity; private List<String> urls; private List<File> files; private List<File> downloadFiles; private int selectedPosition; private Dialog dialog; private ImageView delete; private ImageView download; private TextView imageCount; private ViewPager viewPager; private List<View> views; private MyPagerAdapter adapter; private OnDeleteItemListener listener; private int startPosition; public ScaleImageView(Activity activity) { this.activity = activity; init(); } public void setOnDeleteItemListener(OnDeleteItemListener listener) { this.listener = listener; } private void init() { RelativeLayout relativeLayout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.dialog_scale_image, null); ImageView close = (ImageView) relativeLayout.findViewById(R.id.scale_image_close); delete = (ImageView) relativeLayout.findViewById(R.id.scale_image_delete); download = (ImageView) relativeLayout.findViewById(R.id.scale_image_save); imageCount = (TextView) relativeLayout.findViewById(R.id.scale_image_count); viewPager = (ViewPager) relativeLayout.findViewById(R.id.scale_image_view_pager); dialog = new Dialog(activity, R.style.Dialog_Fullscreen); dialog.setContentView(relativeLayout); close.setOnClickListener(v -> dialog.dismiss()); delete.setOnClickListener(v -> { int size = views.size(); files.remove(selectedPosition); if (listener != null) { listener.onDelete(selectedPosition); } viewPager.removeView(views.remove(selectedPosition)); if (selectedPosition != size) { int position = selectedPosition + 1; String text = position + "/" + views.size(); imageCount.setText(text); } adapter.notifyDataSetChanged(); }); download.setOnClickListener(v -> { try { MediaStore.Images.Media.insertImage(activity.getContentResolver(), downloadFiles.get(selectedPosition).getAbsolutePath(), downloadFiles.get(selectedPosition).getName(), null); } catch (FileNotFoundException e) { e.printStackTrace(); } Snackbar.make(viewPager, "图片保存成功", Snackbar.LENGTH_SHORT).show(); }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { selectedPosition = position; String text = ++position + "/" + views.size(); imageCount.setText(text); } @Override public void onPageScrollStateChanged(int state) { } }); } }首先,我们关注一下最上面三行定义的几个变量,URLS和FILES两个常量分别表示网络查看模式和本地查看模式,而status则用来标示现在查看器处于哪个模式下。
public interface OnDeleteItemListener { void onDelete(int position); }
public void setUrls(List<String> urls, int startPosition) { if (this.urls == null) { this.urls = new ArrayList<>(); } else { this.urls.clear(); } this.urls.addAll(urls); status = URLS; delete.setVisibility(View.GONE); if (downloadFiles == null) { downloadFiles = new ArrayList<>(); } else { downloadFiles.clear(); } this.startPosition = startPosition++; String text = startPosition + "/" + urls.size(); imageCount.setText(text); } public void setFiles(List<File> files, int startPosition) { if (this.files == null) { this.files = new LinkedList<>(); } else { this.files.clear(); } this.files.addAll(files); status = FILES; download.setVisibility(View.GONE); this.startPosition = startPosition++; String text = startPosition + "/" + files.size(); imageCount.setText(text); }
public void create() {
dialog.show();
views = new ArrayList<>();
adapter = new MyPagerAdapter(views, dialog);
if (status == URLS) {
for (String url : urls) {
FrameLayout frameLayout = (FrameLayout) activity.getLayoutInflater().inflate(R.layout.view_scale_image, null);
SubsamplingScaleImageView imageView = (SubsamplingScaleImageView) frameLayout.findViewById(R.id.scale_image_view);
views.add(frameLayout);
IOThread.getSingleThread().execute(() -> {
File downLoadFile;
try {
downLoadFile = Glide.with(activity).load(url).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get();
downloadFiles.add(downLoadFile);
activity.runOnUiThread(() -> imageView.setImage(ImageSource.uri(Uri.fromFile(downLoadFile))));
} catch (Exception e) {
e.printStackTrace();
}
});
}
viewPager.setAdapter(adapter);
} else if (status == FILES) {
for (File file : files) {
FrameLayout frameLayout = (FrameLayout) activity.getLayoutInflater().inflate(R.layout.view_scale_image, null);
SubsamplingScaleImageView imageView = (SubsamplingScaleImageView) frameLayout.findViewById(R.id.scale_image_view);
views.add(frameLayout);
imageView.setImage(ImageSource.uri(Uri.fromFile(file)));
}
viewPager.setAdapter(adapter);
}
viewPager.setCurrentItem(startPosition);
}
private static class MyPagerAdapter extends PagerAdapter { private List<View> views; private Dialog dialog; MyPagerAdapter(List<View> views, Dialog dialog) { this.views = views; this.dialog = dialog; } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(views.get(position)); return views.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { if (position == 0 && views.size() == 0) { dialog.dismiss(); return; } if (position == views.size()) { container.removeView(views.get(--position)); } else { container.removeView(views.get(position)); } } @Override public int getCount() { return views.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public int getItemPosition(Object object) { return POSITION_NONE; } }
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView android:id="@+id/scale_image_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>
ScaleImageView scaleImageView = new ScaleImageView(activity); scaleImageView.setUrls(urls, position); scaleImageView.create();
ScaleImageView scaleImageView = new ScaleImageView(activity); scaleImageView.setFiles(files, position); scaleImageView.setOnDeleteItemListener(deletePosition -> adapter.removeItem(deletePosition)); scaleImageView.create();
public class ScaleImageView { private static final byte URLS = 0; private static final byte FILES = 1; private byte status; private Activity activity; private List<String> urls; private List<File> files; private List<File> downloadFiles; private int selectedPosition; private Dialog dialog; private ImageView delete; private ImageView download; private TextView imageCount; private ViewPager viewPager; private List<View> views; private MyPagerAdapter adapter; private OnDeleteItemListener listener; private int startPosition; public ScaleImageView(Activity activity) { this.activity = activity; init(); } public void setUrls(List<String> urls, int startPosition) { if (this.urls == null) { this.urls = new ArrayList<>(); } else { this.urls.clear(); } this.urls.addAll(urls); status = URLS; delete.setVisibility(View.GONE); if (downloadFiles == null) { downloadFiles = new ArrayList<>(); } else { downloadFiles.clear(); } this.startPosition = startPosition++; String text = startPosition + "/" + urls.size(); imageCount.setText(text); } public void setFiles(List<File> files, int startPosition) { if (this.files == null) { this.files = new LinkedList<>(); } else { this.files.clear(); } this.files.addAll(files); status = FILES; download.setVisibility(View.GONE); this.startPosition = startPosition++; String text = startPosition + "/" + files.size(); imageCount.setText(text); } public void setOnDeleteItemListener(OnDeleteItemListener listener) { this.listener = listener; } private void init() { RelativeLayout relativeLayout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.dialog_scale_image, null); ImageView close = (ImageView) relativeLayout.findViewById(R.id.scale_image_close); delete = (ImageView) relativeLayout.findViewById(R.id.scale_image_delete); download = (ImageView) relativeLayout.findViewById(R.id.scale_image_save); imageCount = (TextView) relativeLayout.findViewById(R.id.scale_image_count); viewPager = (ViewPager) relativeLayout.findViewById(R.id.scale_image_view_pager); dialog = new Dialog(activity, R.style.Dialog_Fullscreen); dialog.setContentView(relativeLayout); close.setOnClickListener(v -> dialog.dismiss()); delete.setOnClickListener(v -> { int size = views.size(); files.remove(selectedPosition); if (listener != null) { listener.onDelete(selectedPosition); } viewPager.removeView(views.remove(selectedPosition)); if (selectedPosition != size) { int position = selectedPosition + 1; String text = position + "/" + views.size(); imageCount.setText(text); } adapter.notifyDataSetChanged(); }); download.setOnClickListener(v -> { try { MediaStore.Images.Media.insertImage(activity.getContentResolver(), downloadFiles.get(selectedPosition).getAbsolutePath(), downloadFiles.get(selectedPosition).getName(), null); } catch (FileNotFoundException e) { e.printStackTrace(); } Snackbar.make(viewPager, "图片保存成功", Snackbar.LENGTH_SHORT).show(); }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { selectedPosition = position; String text = ++position + "/" + views.size(); imageCount.setText(text); } @Override public void onPageScrollStateChanged(int state) { } }); } public void create() { dialog.show(); views = new ArrayList<>(); adapter = new MyPagerAdapter(views, dialog); if (status == URLS) { for (String url : urls) { FrameLayout frameLayout = (FrameLayout) activity.getLayoutInflater().inflate(R.layout.view_scale_image, null); SubsamplingScaleImageView imageView = (SubsamplingScaleImageView) frameLayout.findViewById(R.id.scale_image_view); views.add(frameLayout); IOThread.getSingleThread().execute(() -> { File downLoadFile; try { downLoadFile = Glide.with(activity).load(url).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get(); downloadFiles.add(downLoadFile); activity.runOnUiThread(() -> imageView.setImage(ImageSource.uri(Uri.fromFile(downLoadFile)))); } catch (Exception e) { e.printStackTrace(); } }); } viewPager.setAdapter(adapter); } else if (status == FILES) { for (File file : files) { FrameLayout frameLayout = (FrameLayout) activity.getLayoutInflater().inflate(R.layout.view_scale_image, null); SubsamplingScaleImageView imageView = (SubsamplingScaleImageView) frameLayout.findViewById(R.id.scale_image_view); views.add(frameLayout); imageView.setImage(ImageSource.uri(Uri.fromFile(file))); } viewPager.setAdapter(adapter); } viewPager.setCurrentItem(startPosition); } private static class MyPagerAdapter extends PagerAdapter { private List<View> views; private Dialog dialog; MyPagerAdapter(List<View> views, Dialog dialog) { this.views = views; this.dialog = dialog; } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(views.get(position)); return views.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { if (position == 0 && views.size() == 0) { dialog.dismiss(); return; } if (position == views.size()) { container.removeView(views.get(--position)); } else { container.removeView(views.get(position)); } } @Override public int getCount() { return views.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public int getItemPosition(Object object) { return POSITION_NONE; } } public interface OnDeleteItemListener { void onDelete(int position); } }
标签:instant 项目 解耦 接口隔离 适合 sdn bottom setimage offset
原文地址:http://blog.csdn.net/qq_28899635/article/details/71552072