android图片查看(2)

上一篇文章里我们已经完成了图片查看的基本功能,接下来,我们要在这基础上增加一些新的功能。
Android support v7 Library里面有一个叫Palette的库,通过这个库,我们可以很方便的从图像中抽取颜色,我们看一下官方文档的介绍

A helper class to extract prominent colors from an image.
A number of colors with different profiles are extracted from the image:
1. Vibrant
2. Vibrant Dark
3. Vibrant Light
4. Muted
5. Muted Dark
6. Muted Light
These can be retrieved from the appropriate getter method.

我们这里不深究颜色是怎么提取的和每种颜色的区别,有兴趣的同学可以去查看官方文档。因为现在的背景是黑色的,所以我从图像中抽取Muted Dark这个颜色作为我们toolbar的背景。
Palette提供了四种方法生成对象

  • Palette generate(Bitmap bitmap)
  • Palette generate(Bitmap bitmap, int numColors)
  • generateAsync(Bitmap bitmap, PaletteAsyncListener listener)
  • generateAsync(Bitmap bitmap, int numColors, final PaletteAsyncListener listener)
    前两种是同步方法,不过如果图片颜色比较丰富的话提取颜色的算法可能会比较耗时,所以,我们最好不要在主线程中使用。这里我们使用异步方法。
    我们修改前面的加载图片方法
Picasso.with(this)
                .load(url)
                .into(new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        photoImageView.setImageBitmap(bitmap);
                        Palette.from(bitmap).generate(palette1 -> {

                            int colorMutedDark = palette1.getDarkMutedColor(colorDefault);
                            toolbar.setBackgroundColor(colorMutedDark);

                        });

                        if (attacher == null) {
                            attacher = new PhotoViewAttacher(photoImageView);
                        } else {
                            attacher.update();
                        }
                    }

                    @Override
                    public void onBitmapFailed(Drawable errorDrawable) {
                        //TODO do something
                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {
                        //TODO do something
                    }
                });

这样,我们的toolbar就能根据不同的图片变色了,有没有觉得很好玩呢:)。接下来,我们加点动画,让toolbar慢慢的从默认的颜色变化到指定的颜色,同时改变透明度。
这里涉及到颜色的改变,View Animation没有这个能力,我们使用Property Animation。
我们定义两个动画,因为这两个动画要一起动,所以再定义一个动画集合去控制

    private ObjectAnimator colorAnimator;//toolbar变色动画
    private ObjectAnimator alphaAnimator;//toolbar透明度变化动画
    private AnimatorSet animatorSet;//动画集合

Palette取到颜色之后我们开始动画,所以继续修改上面的代码

@Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        photoImageView.setImageBitmap(bitmap);
                        Palette.from(bitmap).generate(palette1 -> {

                            int colorMutedDark = palette1.getDarkMutedColor(colorDefault);
//                            toolbar.setBackgroundColor(colorMutedDark);

                            colorAnimator = ObjectAnimator.ofInt(toolbar, "backgroundColor", colorDefault,
                                    colorMutedDark);
                            colorAnimator.setEvaluator(new ArgbEvaluator());
                            alphaAnimator = ObjectAnimator.ofFloat(toolbar, "alpha", 1.0f, 0.5f);

                            animatorSet.play(alphaAnimator).with(colorAnimator);
                            animatorSet.setInterpolator(new AccelerateInterpolator());
                            animatorSet.setDuration(DURATION);
                            animatorSet.start();
                        });

                        if (attacher == null) {
                            attacher = new PhotoViewAttacher(photoImageView);
                        } else {
                            attacher.update();
                        }
                    }

这样,我们就可以实现在DURATION时间内将toolbar的颜色变化到Palette提取出来的颜色,并将toolbar的透明度变为0.5。
接下来,我们还要做什么呢?还是加动画:)。很多app,比如网易新闻客户端的图片查看界面都有这样的功能,点击一下图片,图片上方的标题栏可以隐藏,再点击一下标题栏又会出现,我接下来也要实现这个功能。动画部分我们还是使用Property Animation,我们定义进入和退出两个动画

    private ObjectAnimator inAnimator;//appbar进入动画
    private ObjectAnimator exitAnimator;//appbar退出动画

接下来定义进入和退出方法

private void animIn(View view) {

        if (inAnimator == null) {
            inAnimator = ObjectAnimator.ofFloat(view, "translationY", -view.getHeight(), 0);
            inAnimator.setDuration(DURATION_IN_OUT);
            inAnimator.setInterpolator(new DecelerateInterpolator());
            inAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    if (view.getVisibility() != View.VISIBLE) {
                        view.setVisibility(View.VISIBLE);
                    }
                }
            });
        }
        inAnimator.start();
    }

    private void animOut(View view) {

        if (outAnimator == null) {
            outAnimator = ObjectAnimator.ofFloat(view, "translationY", 0, -view.getHeight());
            outAnimator.setDuration(DURATION_IN_OUT);
            outAnimator.setInterpolator(new DecelerateInterpolator());
            outAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    if (view.getVisibility() == View.VISIBLE) {
                        view.setVisibility(View.GONE);
                    }
                }
            });
        }
        outAnimator.start();
    }

然后监听点击事件。这里要注意的是我们用了PhotoView这个库,这个库会拦截点击事件,所以不能直接在imageView上添加onClickListener,PhotoView 提供了setOnPhotoTapListener方法来监听点击事件。我们继续修改上面的代码。

@Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        photoImageView.setImageBitmap(bitmap);
                        Palette.from(bitmap).generate(palette1 -> {

                            int colorMutedDark = palette1.getDarkMutedColor(colorDefault);
//                            toolbar.setBackgroundColor(colorMutedDark);

                            colorAnimator = ObjectAnimator.ofInt(toolbar, "backgroundColor", colorDefault,
                                    colorMutedDark);
                            colorAnimator.setEvaluator(new ArgbEvaluator());
                            alphaAnimator = ObjectAnimator.ofFloat(toolbar, "alpha", 1.0f, 0.5f);

                            animatorSet.play(alphaAnimator).with(colorAnimator);
                            animatorSet.setInterpolator(new AccelerateInterpolator());
                            animatorSet.setDuration(DURATION);
                            animatorSet.start();
                        });

                        if (attacher == null) {
                            attacher = new PhotoViewAttacher(photoImageView);
                            attacher.setOnPhotoTapListener((view, x, y) -> {

                                if (appbar.getVisibility() == View.VISIBLE) {
                                    animOut(appbar);
                                } else if (appbar.getVisibility() != View.VISIBLE) {
                                    animIn(appbar);
                                }
                            });
                        } else {
                            attacher.update();
                        }
                    }

好了,这样就能实现标题栏的隐藏和出现了。到此为止,基本功能已经全部实现,我们看一下完整的代码

package me.masteryi.gankio;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.Toast;

import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;

import butterknife.Bind;
import butterknife.ButterKnife;
import me.masteryi.gankio.utils.FileUtil;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import uk.co.senab.photoview.PhotoViewAttacher;

/**
 * Created by Lee
 * Date 2016/2/12
 * Email jon_ly@163.com
 * Blog http://masteryi.me
 */
public class PhotoActivity extends AppCompatActivity {

    private static final String TAG = "PhotoActivity";

    private static final int DURATION = 1000;//toolbar变色/透明度变化持续时间
    private static final int DURATION_IN_OUT = 300;//toolbar进入/退出动画持续时间

    public static final String PHOTO_URL = "photo_url";
    @Bind(R.id.photo_iv)
    ImageView photoImageView;
    @Bind(R.id.toolbar)
    Toolbar toolbar;
    @Bind(R.id.appbar)
    AppBarLayout appbar;

    private String url;//需要显示图片url
    private PhotoViewAttacher attacher;
    private Palette palette;
    private int colorDefault;//toolbar默认颜色

    private ObjectAnimator colorAnimator;//toolbar变色动画
    private ObjectAnimator alphaAnimator;//toolbar透明度变化动画
    private ObjectAnimator inAnimator;//appbar进入动画
    private ObjectAnimator outAnimator;//appbar退出动画
    private AnimatorSet animatorSet;//动画集合

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_photo);
        ButterKnife.bind(this);

        setSupportActionBar(toolbar);
        toolbar.setTitleTextColor(Color.WHITE);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(v -> finish());

        //图片URL从其他页面传过来
        url = getIntent().getStringExtra(PHOTO_URL);
        //toolbar默认颜色为colorPrimary
        colorDefault = ContextCompat.getColor(this, R.color.colorPrimary);
        //动画集合
        animatorSet = new AnimatorSet();

        //加载图片
        Picasso.with(this)
                .load(url)
                .into(new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        photoImageView.setImageBitmap(bitmap);
                        Palette.from(bitmap).generate(palette1 -> {

                            int colorMutedDark = palette1.getDarkMutedColor(colorDefault);
//                            toolbar.setBackgroundColor(colorMutedDark);

                            colorAnimator = ObjectAnimator.ofInt(toolbar, "backgroundColor", colorDefault,
                                    colorMutedDark);
                            colorAnimator.setEvaluator(new ArgbEvaluator());
                            alphaAnimator = ObjectAnimator.ofFloat(toolbar, "alpha", 1.0f, 0.5f);

                            animatorSet.play(alphaAnimator).with(colorAnimator);
                            animatorSet.setInterpolator(new AccelerateInterpolator());
                            animatorSet.setDuration(DURATION);
                            animatorSet.start();
                        });

                        if (attacher == null) {
                            attacher = new PhotoViewAttacher(photoImageView);
                            attacher.setOnPhotoTapListener((view, x, y) -> {

                                if (appbar.getVisibility() == View.VISIBLE) {
                                    animOut(appbar);
                                } else if (appbar.getVisibility() != View.VISIBLE) {
                                    animIn(appbar);
                                }
                            });
                        } else {
                            attacher.update();
                        }
                    }

                    @Override
                    public void onBitmapFailed(Drawable errorDrawable) {

                        Toast.makeText(PhotoActivity.this, "加载图片出错", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {

                    }
                });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.menu_photo, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case R.id.menu_download:
                downloadImage();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    private void downloadImage() {

        Target target = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

                Observable.create((Observable.OnSubscribe<Boolean>) subscriber -> {
                    Log.d(TAG, "thread1:" + Thread.currentThread().getName());
                    String imageName = FileUtil.url2ImageName(url);
                    subscriber.onNext(FileUtil.saveImage(imageName, bitmap));

                })
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(aBoolean -> {

                            Log.d(TAG, "thread2:" + Thread.currentThread().getName());
                            if (aBoolean) {
                                Toast.makeText(PhotoActivity.this, "保存图片成功", Toast.LENGTH_SHORT).show();
                            } else {
                                Toast.makeText(PhotoActivity.this, "保存图片失败", Toast.LENGTH_SHORT).show();
                            }

                        }, throwable -> {
                            Toast.makeText(PhotoActivity.this, "保存图片失败", Toast.LENGTH_SHORT).show();
                            Log.d(TAG, throwable.getMessage());
                            throwable.printStackTrace();
                        });
            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {

                Toast.makeText(PhotoActivity.this, "保存图片失败", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        };

        Picasso.with(this)
                .load(url)
                .into(target);
    }

    private void animIn(View view) {

        if (inAnimator == null) {
            inAnimator = ObjectAnimator.ofFloat(view, "translationY", -view.getHeight(), 0);
            inAnimator.setDuration(DURATION_IN_OUT);
            inAnimator.setInterpolator(new DecelerateInterpolator());
            inAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    if (view.getVisibility() != View.VISIBLE) {
                        view.setVisibility(View.VISIBLE);
                    }
                }
            });
        }
        inAnimator.start();
    }

    private void animOut(View view) {

        if (outAnimator == null) {
            outAnimator = ObjectAnimator.ofFloat(view, "translationY", 0, -view.getHeight());
            outAnimator.setDuration(DURATION_IN_OUT);
            outAnimator.setInterpolator(new DecelerateInterpolator());
            outAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    if (view.getVisibility() == View.VISIBLE) {
                        view.setVisibility(View.GONE);
                    }
                }
            });
        }
        outAnimator.start();
    }

}

总结

图片查看的功能已经基本实现,后面有空的话会补上收藏跟分享功能。
一个看似简单的功能还是包含很多东西的,需要了解各种第三方库的使用,期间也碰到了很多坑。比如

  • 图片加载我们用的是Picasso,平时用的比较多的可能就是现实图片,直接Picasso.with(this).load(url).into(imageview)就完事了,但是下载图片我们需要得到bitmap对象,所以这里就需要用Target来实现。
  • RxJava/RxAndroid最近很火,RxJava配合lambda变大时可以让代码变得非常简洁,但是对于刚接触的新手来说还是没那么简单的,我最近也在努力学习相关知识,代码中的异步调用尽量都用RxJava实现,由于理解不深,难免会出现滥用或者误用的情况,希望大家能够指出我的错误,也非常欢迎有兴趣的同学一起交流。
  • Android Studio是一个非常好用的IDE,可以自动帮我们生成很多代码,但是,初学者如果过于依赖的话也会造成负面影响。之前我新建Activity一般都会选择Basic Activity,因为很方便,AS会自动生成布局文件,Java代码和value文件,这次我心血来潮,新建了一个Empty Acticity大部分东西都得自己来写,发现很多很基础的东西都不记得了,期间碰到很多问题,所以,对新手来说最好还是自己多写写代码巩固一下知识。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android调用系统查看图片可以通过使用隐式意图实现。首先需要获取图片的Uri,可以通过图片的文件路径或URL获取。然后使用Intent创建一个ACTION_VIEW的意图,并将图片的Uri作为数据添加到意图中。最后通过调用startActivity方法来启动查看图片的系统应用。 具体实现步骤如下: 1. 获取图片的Uri,可以使用FileProvider将文件路径转换为ContentUri,或者直接使用网络图片的URL获取Uri。 2. 创建一个Intent对象,并设置Intent的Action为ACTION_VIEW,指定要查看的数据类型为图片类型(image/*)。 3. 将图片的Uri添加到Intent中,通过setDataAndType方法设置数据和类型。 4. 通过调用startActivity方法启动系统的图片查看应用。 以下是一个示例代码: ```java Uri imageUri = FileProvider.getUriForFile(context, "com.example.fileprovider", imageFile); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(imageUri, "image/*"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); context.startActivity(intent); ``` 需要注意的是,如果图片是通过FileProvider的方式获取的Uri,需要添加FLAG_GRANT_READ_URI_PERMISSION标志,以授权其他应用可以读取该Uri的权限。 另外,为了避免没有系统应用可以查看图片的情况,可以先使用resolveActivity方法判断是否有对应的应用可以处理该Intent,如果返回null,则表示没有可以查看图片的应用。可以通过以下代码进行判断: ```java if (intent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(intent); } else { // 没有合适的应用可以查看图片 } ``` 以上就是Android调用系统查看图片的简单实现方式。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值