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大部分东西都得自己来写,发现很多很基础的东西都不记得了,期间碰到很多问题,所以,对新手来说最好还是自己多写写代码巩固一下知识。
- android图片查看(2)
- Android图片查看(一)
- android 查看图片、保存图片
- Android图片查看器
- android 查看图片缩略图
- android 查看图片缩略图
- android手机图片查看
- Android 图片查看器
- Android图片查看器
- Android查看网络图片
- android查看网络图片
- Android查看网络图片
- Android 查看图片
- android查看网络图片
- android查看网络图片
- android查看网络图片
- android图片查看(1)
- Android图片查看器
- 京东轮播图
- hdu2141 Can you find it? (二分)
- 【BZOJ3598】【SCOI2014】方伯伯的商场之旅
- 248,AFNetworking 3的使用(二)
- iOS-UI-基本控件之UITextField
- android图片查看(2)
- c++primer阅读笔记之函数
- sql注入
- oracle之表对象操作
- bzoj3209 花神的数论题
- 17.指针与数组
- HDU_1711_NumberSequence
- Product of Array Exclude Itself
- VMware Fusion自动切换分辨率的头疼问题解决办法