android图片查看(2)

来源:互联网 发布:爱思助手mac下载 编辑:程序博客网 时间:2024/06/06 06:53

上一篇文章里我们已经完成了图片查看的基本功能,接下来,我们要在这基础上增加一些新的功能。
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 0
原创粉丝点击