Giter Site home page Giter Site logo

iielse / imageviewer Goto Github PK

View Code? Open in Web Editor NEW
2.2K 31.0 310.0 27.09 MB

A simple and customizable Android full-screen image viewer 一个简单且可自定义的Android全屏图像浏览器

License: MIT License

Kotlin 100.00%
viewer imageviewer photobrowser gallery zoom wechat viewpager gif image video gesture draggable transferee

imageviewer's People

Contributors

ielse avatar iielse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imageviewer's Issues

9宫格 gif

9宫格里面图片展示,是不支持gif嘛?,为什么我放入了一个gif,显示错乱

P02 show的API设计的不是很好

public void show(ImageView i, List<ImageView> imageGroupList, final List<Uri> urlList) {

之前设计的是 第二个imageGroupList和第三个参数urlList是对应关系,且顺序也需要对应,且点击触发show的imageView必须是 imageGroupList中的元素
限制太多

public void show(ImageView i, SparseArray<ImageView> imageGroupList, final List<Uri> urlList) {

思考后发现,把第二个入参改成了 SparseArray类型,imageGroupList的key(position) 映射 urlList中的url地址要灵活很多, 点击触发show的imageView依旧需要在imageGroupList中,来确认初始位置。 这样设计更适合聊天界面来查看图片列表。

要改变的地方 3处

/**
     * @param i              被点击的ImageView
     * @param imageGroupList
     * @param urlList        被加载的图片url列表,数量必须大于等于 imageGroupList.size。 且顺序应当和imageGroupList保持一致
     */
    public void show(ImageView i, SparseArray<ImageView> imageGroupList, final List<Uri> urlList) {
        if (i == null || imageGroupList == null || urlList == null || imageGroupList.size() < 1 ||
                urlList.size() < imageGroupList.size()) {
            String info = "i[" + i + "]";
            info += "#imageGroupList " + (imageGroupList == null ? "null" : "size : " + imageGroupList.size());
            info += "#urlList " + (urlList == null ? "null" : "size :" + urlList.size());
            throw new IllegalArgumentException("error params \n" + info);
        }

        initPosition = -1;
        for (int x = 0; x < imageGroupList.size(); x++) {
            if (imageGroupList.get(imageGroupList.keyAt(x)) == i) {
                initPosition = imageGroupList.keyAt(x);
                break;
            }
        }
        if (initPosition < 0) {
            throw new IllegalArgumentException("param ImageView i must be a member of the List <ImageView> imageGroupList!");
        }

        ...
    }
private boolean setDefaultDisplayConfigs(final ImageView imageView, final int pos, boolean hasPlayBeginAnimation) {
            boolean isFindEnterImagePicture = false;

            ViewState.write(imageView, ViewState.STATE_ORIGIN).alpha(0).scaleXBy(1.5f).scaleYBy(1.5f);
            if (mImageGroupList.get(pos) != null) {  // 这里
                ImageView originRef = mImageGroupList.get(pos);
                if (pos == initPosition && !hasPlayBeginAnimation) {
 @Override
    public void onPageSelected(int position) {
        iSource = adapter.mImageSparseArray.get(position);
        if (iOrigin != null) {
            iOrigin.setVisibility(View.VISIBLE);
        }
        if (mImageGroupList.get(position) != null) { // 这里
            iOrigin = mImageGroupList.get(position);
            if (iOrigin.getDrawable() != null) iOrigin.setVisibility(View.INVISIBLE);
        }

调用

conversationAdapter1 = ConversationAdapter1().apply {
                cb = object : ConversationAdapter1.Callback {
                    override fun onPictureClick(view: ImageView, uri: Uri, uriList: List<Uri>, position: Int) {
                        // view 被点击的imageView
                        // uri 被点击的imageView对应展示的图片地址信息
                        // uriList 一整个要展示的图片列表
                       
                        vImageWatcher.show(view, SparseArray<ImageView>().apply {
                            put(uriList.indexOf(uri), view)
                        }, uriList)
                    }
                }
            }

效果
image

第一个图片总是两边显示不全

不知道为什么,第一个图片,两边总是显示不全,被遮住了。缩小也不行。搞了了好久,浪费了3个多小时,唉换框架!

如果不用Glide,用Fresco呢

有个问题是fresco我们用的是自定义的imageview集成自SimpleDraweeView,不像glide可以直接load到imageview

MessagePicturesLayout set(List<String> urlThumbList, List<String> urlList) 方法

如果不设置值
eg: demo中注释// lPictures.set(mData.getPictureThumbList(), mData.getPictureList());

 Process: ch.ielse.demo.p02, PID: 378
                                                               java.lang.IllegalArgumentException: dataList.size != thumbDataList.size
                                                                   at ch.ielse.demo.p02.MessagePicturesLayout.notifyDataChanged(MessagePicturesLayout.java:76)
                                                                   at ch.ielse.demo.p02.MessagePicturesLayout.onSizeChanged(MessagePicturesLayout.java:146)
                                                                   at android.view.View.sizeChange(View.java:17638)
                                                                   at android.view.View.setFrame(View.java:17600)
                                                                   at android.view.View.layout(View.java:17517)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1079)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.support.v7.widget.RecyclerView$LayoutManager.layoutDecoratedWithMargins(RecyclerView.java:8659)
                                                                   at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1583)
                                                                   at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1488)
                                                                   at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:585)
                                                                   at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3506)
                                                                   at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3254)
                                                                   at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3767)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
                                                                   at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
                                                                   at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
                                                                   at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
                                                                   at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                   at com.android.internal.policy.DecorView.onLayout(DecorView.java:724)
                                                                   at android.view.View.layout(View.java:17520)
                                                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                                                   at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2342)
                                                                   at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2069)
                                                                   at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1246)
                                                                   at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6301)
                                                                   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
                                                                   at android.view.Choreographer.doCallbacks(Choreographer.java:683)
                                                                   at android.view.Choreographer.doFrame(Choreographer.java:619)
                                                                   at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
                                                                   at android.os.Handler.handleCallback(Handler.java:751)
                                                                   at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                   at android.os.Looper.loop(Looper.java:154)
                                                                   at android.app.ActivityThread.main(ActivityThread.java:6077)
                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

图片放大效果体验不佳

P02,点击小图进入大图后,两指不断扩张放大图片,然后单指滑动图片到屏幕边缘,这时候继续放大图片,图片的位置会自动回到屏幕中心。

自定义 IndexProvider 中 点击事件不触发

` new ImageWatcher.IndexProvider() {
private View view;

                @Override
                public View initialView(Context context) {
                    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                            MyUtils.dip2px(context, 40));//
                    lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
                    view = LayoutInflater.from(context).inflate(R.layout.image_index, null);
                    view.setLayoutParams(lp);
                    return view;
                }

                @Override
                public void onPageChanged(final ImageWatcher imageWatcher, int position, List<Uri> list) {
                    TextView textIndex = view.findViewById(R.id.tv_index);
                    TextView tvShare = view.findViewById(R.id.tv_share);
                    textIndex.setText(String.format("%s/%s", position + 1, list.size()));
                    tvShare.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            ToastUtils.show("分享");
                        }
                    };`

横向超长图片双击无法看清楚的问题

横向超长图片双击无法看清楚的问题
比如:http://image.xcar.com.cn/attachments/a/day_20141126/2014112609_68d9843ed0c3e1d05735CObUWVqIy3rr.jpg
这个长图,双击根本看不清楚
修复代码:
ImageWatcher.java->handleDoubleTapTouchResult()

if (vsCurrent.scaleY <= vsDefault.scaleY && vsCurrent.scaleX <= vsDefault.scaleX) {

        final String imageOrientation = (String) iSource.getTag(R.id.image_orientation);
        float expectedScale = (MAX_SCALE - vsDefault.scaleX) * 0.4f + vsDefault.scaleX;
        if (imageOrientation.equals("horizontal")) {
            ViewState viewState = ViewState.read(iSource, ViewState.STATE_DEFAULT);
            //图片在双击的时候放大的倍数,如果图片过长看不放大根本看不见
            final float scale = viewState.width / viewState.height;
            float maxScale = MAX_SCALE;
            if (scale > 2.0f) {
                maxScale = MAX_SCALE * scale / 2;
            }
            expectedScale = (maxScale - vsDefault.scaleX) * 0.4f + vsDefault.scaleX;
        }

        animSourceViewStateTransform(iSource, ViewState.write(iSource, ViewState.STATE_TEMP).scaleX(expectedScale).scaleY(expectedScale));
    } else {
        animSourceViewStateTransform(iSource, vsDefault);
    }

希望可以请求合并

P01 open failed: ENOENT (No such file or directory)

华为系统相册返回Uri不能直接使用 uri.getPath 。不然使用BitmapFactory.decodeFile会返回空

解析方案参考 https://github.com/Yalantis/uCrop 源码

private static Bitmap obtainBmpSource(@NonNull Context context, @NonNull Uri uri, int requiredWidth, int requiredHeight) throws Exception {
        final ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
        final FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
        options.inSampleSize = calculateInSampleSize(options, requiredWidth, requiredHeight);
        options.inJustDecodeBounds = false;

        Bitmap decodeSampledBitmap = null;

        boolean success = false;
        while (!success) {
            try {
                decodeSampledBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
                success = true;
            } catch (OutOfMemoryError error) {
                Log.e("ImageCropper", "decodeSampledBitmap: BitmapFactory.decodeFileDescriptor: ", error);
                options.inSampleSize++;
            }
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            close(parcelFileDescriptor);
        }

        int exifOrientation = getExifOrientation(context, uri);
        int exifDegrees = exifToDegrees(exifOrientation);
        int exifTranslation = exifToTranslation(exifOrientation);

        Matrix matrix = new Matrix();
        if (exifDegrees != 0) {
            matrix.preRotate(exifDegrees);
        }
        if (exifTranslation != 1) {
            matrix.postScale(exifTranslation, 1);
        }
        if (!matrix.isIdentity()) {
            decodeSampledBitmap = transformBitmap(decodeSampledBitmap, matrix);
        }
        return decodeSampledBitmap;
    }

修改核心代码
RxImagePickerFragment
替换方法入参
private void onQueryOrTakeSuccess(@NonNull String type, @NonNull List<String> pictures) {
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
private void onQueryOrTakeSuccess(@NonNull String type, @NonNull List<Uri> pictures) {

p01_ImageCropprer运行崩溃

您的debug-apk运行崩溃,重新编译也崩溃。
1.单选图片确定后崩溃
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at ch.ielse.view.imagecropper.ImageCropper.cropInternal(ImageCropper.java:101)
at ch.ielse.view.imagecropper.ImageCropper.access$000(ImageCropper.java:25)
at ch.ielse.view.imagecropper.ImageCropper$1.run(ImageCropper.java:139)
2.选择拍照后崩溃
io.reactivex.exceptions.OnErrorNotImplementedException: file:///storage/emulated/0/Android/data/ch.ielse.demo.p01/cache/rxPicker/TEMP1595091369.jpg exposed beyond app through ClipData.Item.getUri()
at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)
at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)
at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:74)
at io.reactivex.observers.SerializedObserver.onError(SerializedObserver.java:155)
at io.reactivex.internal.operators.observable.ObservableTakeUntil$TakeUntilObserver.onError(ObservableTakeUntil.java:73)
at io.reactivex.subjects.PublishSubject.subscribeActual(PublishSubject.java:95)
at io.reactivex.Observable.subscribe(Observable.java:10842)
at io.reactivex.internal.operators.observable.ObservableTakeUntil.subscribeActual(ObservableTakeUntil.java:41)
at io.reactivex.Observable.subscribe(Observable.java:10842)
at io.reactivex.Observable.subscribe(Observable.java:10828)
at io.reactivex.Observable.subscribe(Observable.java:10731)
at ch.ielse.demo.p01.MainActivity.takeCamera(MainActivity.java:107)
at ch.ielse.demo.p01.MainActivity.access$000(MainActivity.java:26)
at ch.ielse.demo.p01.MainActivity$1$1.accept(MainActivity.java:78)
at ch.ielse.demo.p01.MainActivity$1$1.accept(MainActivity.java:75)
at io.reactivex.internal.observers.ConsumerSingleObserver.onSuccess(ConsumerSingleObserver.java:61)
at io.reactivex.internal.operators.single.SingleTakeUntil$TakeUntilMainObserver.onSuccess(SingleTakeUntil.java:92)
at io.reactivex.internal.operators.observable.ObservableAllSingle$AllObserver.onComplete(ObservableAllSingle.java:99)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drainLoop(ObservableFlatMap.java:367)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drain(ObservableFlatMap.java:323)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onComplete(ObservableFlatMap.java:300)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drainLoop(ObservableFlatMap.java:367)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drain(ObservableFlatMap.java:323)
at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onComplete(ObservableFlatMap.java:300)
at io.reactivex.internal.operators.observable.ObservableFromArray$FromArrayDisposable.run(ObservableFromArray.java:110)
at io.reactivex.internal.operators.observable.ObservableFromArray.subscribeActual(ObservableFromArray.java:36)
at io.reactivex.Observable.subscribe(Observable.java:10842)
at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
at io.reactivex.Observable.subscribe(Observable.java:10842)
at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
at io.reactivex.Observable.subscribe(Observable.java:10842)
at io.reactivex.internal.operators.observable.ObservableAllSingle.subscribeActual(ObservableAllSingle.java:34)
at io.reactivex.Single.subscribe(Single.java:2703)
at io.reactivex.internal.operators.single.SingleTakeUntil.subscribeActual(SingleTakeUntil.java:51)
at io.reactivex.Single.subscribe(Single.java:2703)
at io.reactivex.Single.subscribe(Single.java:2689)
at io.reactivex.Single.subscribe(Single.java:2660)
at ch.ielse.demo.p01.MainActivity.requestPermissions(MainActivity.java:155)
at ch.ielse.demo.p01.MainActivity$1.onClick(MainActivity.java:74)
at ch.ielse.demo.p01.SheetDialog$Builder$1.onClick(SheetDialog.java:142)
at android.view.View.performClick(View.java:5730)
at android.view.View$PerformClick.run(View.java:22806)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6519)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1113)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:974)
Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/ch.ielse.demo.p01/cache/rxPicker/TEMP1595091369.jpg exposed beyond app through ClipData.Item.getUri()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1847)
at android.net.Uri.checkFileUriExposed(Uri.java:2346)
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:833)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8976)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8961)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1647)
at android.app.Activity.startActivityForResult(Activity.java:4888)
at android.app.Activity.startActivityFromFragment(Activity.java:4874)
at android.app.Activity$HostCallbacks.onStartActivityFromFragment(Activity.java:7176)
at android.app.Fragment.startActivityForResult(Fragment.java:1150)
at android.app.Fragment.startActivityForResult(Fragment.java:1139)
at ch.ielse.view.imagecropper.RxImagePickerFragment.takeCamera(RxImagePickerFragment.java:170)
at ch.ielse.view.imagecropper.RxImagePicker.takeCamera(RxImagePicker.java:59)
at ch.ielse.demo.p01.MainActivity.takeCamera(MainActivity.java:104)
... 37 more

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.