画廊Gallery

Gallery是一个早期的画廊控件,左右滑动手势可展示内嵌的图片列表,类似于一个平面的万花筒。虽然Android现在将Gallery标记为Deprecation(表示已废弃),建议开发者采用HorizontalScrollView或者ViewPager来代替,但是Gallery用做自定义相册来轮播图片其实是个挺好的选择,所以下面我们还是简单介绍它的用法,并结合其它控件加深对图像开发的理解。

Gallery的常用属性说明如下:
spacing : 指定图片之间的间隔大小。
unselectedAlpha : 指定未选定图片的透明度。取值为0到1,0表示完全透明,1表示完全不透明。

Gallery的常用方法说明如下:
setSpacing : 设置图片之间的间隔大小。
setUnselectedAlpha : 设置未选定图片的透明度。
setAdapter : 设置图像视图的适配器。
getSelectedItemId : 获取当前选中的图像id。0表示第一个图像。
setSelection : 设置当前选中第几个图像。
setOnItemClickListener : 设置单项的点击监听器。

现在我们结合Gallery与ImageView来观看画廊的相册效果,首先放置一个FrameLayout布局,里面放入一个Gallery控件与一个ImageView控件,其中ImageView控件要充满整个屏幕,Gallery控件可放在屏幕上方或下方;然后监听Gallery控件的单项点击事件,点击指定图片项时,便给ImageView控件填充该图片,也就是点小图看大图。

下面是Gallery与ImageView结合使用的效果截图:

下面是Gallery与ImageView结合使用的代码例子:

import com.example.exmcard.adapter.GalleryAdapter;
import com.example.exmcard.util.MetricsUtil;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Gallery;
import android.widget.ImageView;@SuppressWarnings("deprecation")
public class GalleryActivity extends Activity implements OnItemClickListener {private ImageView iv_gallery;private Gallery gl_gallery;// 图片数组private int[] mImageRes = {R.drawable.scene1, R.drawable.scene2,R.drawable.scene3, R.drawable.scene4,R.drawable.scene5, R.drawable.scene6};private int dip_pad;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_gallery);dip_pad = MetricsUtil.dip2px(this, 20);iv_gallery = (ImageView) findViewById(R.id.iv_gallery);iv_gallery.setImageResource(mImageRes[0]);gl_gallery = (Gallery) findViewById(R.id.gl_gallery);gl_gallery.setPadding(dip_pad, dip_pad, dip_pad, dip_pad);gl_gallery.setSpacing(dip_pad);gl_gallery.setUnselectedAlpha(0.5f);gl_gallery.setAdapter(new GalleryAdapter(this, mImageRes));gl_gallery.setOnItemClickListener(this);}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {iv_gallery.setImageResource(mImageRes[position]);}}

图像切换ImageSwitcher

可能大家已经发现,前面Gallery与ImageView在切换大图时比较生硬,前后两张图片闪一下就切过去,用户体验不够友好。那有没有办法让图片切换自然些呢,比如说通过渐变动画的方式?答案肯定是有的,就是把ImageView换成ImageSwitcher,通过ImageSwitcher控件来实现图片的切换动画。ImageSwitcher实质是个视图动画师ViewAnimator,用于处理前后图像的变换动画;与之对应的是,TextSwitcher用于处理前后文本的变换动画;另外ViewFlipper也是从ViewAnimator派生而来,则是用于处理两个页面视图的变换动画。有关ViewFlipper的详细介绍参见《 Android开发笔记(二十一)横幅轮播页》。

ImageSwitcher的常用方法说明如下:
setFactory : 设置一个视图工厂。该视图工厂对象从ViewFactory派生而来,内部需要重写makeView方法来返回视图工厂里的具体视图。对于ImageSwitcher来说,视图工厂应当返回的当然是ImageView对象了。
setImageResource : 设置当前图像的资源ID。该方法与下面的setImageDrawable和setImageURI为三选一操作,调用了其中一个方法,就无需调用另外两个方法。
setImageDrawable : 设置当前图像的Drawable对象。
setImageURI : 设置当前图像的URI地址。
setInAnimation : 设置当前图像的进入动画。
setOutAnimation : 设置前一个图像的退出动画。

按照ImageSwitcher的上述方法,我们便能实现前后两个图像的切换动画(如淡入淡出动画)。可是还没有实现左右滑动切换图片的功能,既然Gallery上的小图能够左右滑动,那么我们希望ImageSwitcher的大图也能够左右滑动,这时要借助于手势事件来实现滑动切换功能。首先定义一个GestureDetector对象;然后调用ImageSwitcher的setOnTouchListener方法设置触摸监听器OnTouchListener,在该监听器的onTouch方法中让GestureDetector对象接管事件处理;最后重写GestureDetector对象的手势监听器OnGestureListener,主要是在onFling方法中增加对左滑和右滑的处理逻辑判断。

下面是Gallery与ImageSwitcher结合使用的效果截图:

下面是Gallery与ImageSwitcher结合使用的代码例子:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.Gallery;
import android.widget.ImageSwitcher;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.ViewSwitcher.ViewFactory;import com.example.exmcard.adapter.GalleryAdapter;
import com.example.exmcard.util.MetricsUtil;@SuppressWarnings("deprecation")
public class SwitcherActivity extends Activity implements OnTouchListener, OnItemClickListener {private ImageSwitcher is_switcher;private Gallery gl_switcher;// 图片数组private int[] mImageRes = {R.drawable.scene1, R.drawable.scene2,R.drawable.scene3, R.drawable.scene4,R.drawable.scene5, R.drawable.scene6};private int dip_pad;private GestureDetector mGesture;private float mFlipGap = 20f;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_switcher);dip_pad = MetricsUtil.dip2px(this, 20);is_switcher = (ImageSwitcher) findViewById(R.id.is_switcher);is_switcher.setFactory(new ViewFactoryImpl());is_switcher.setImageResource(mImageRes[0]);mGesture = new GestureDetector(this, new GestureListener(this));is_switcher.setOnTouchListener(this);gl_switcher = (Gallery) findViewById(R.id.gl_switcher);gl_switcher.setPadding(dip_pad, dip_pad, dip_pad, dip_pad);gl_switcher.setSpacing(dip_pad);gl_switcher.setUnselectedAlpha(0.5f);gl_switcher.setAdapter(new GalleryAdapter(this, mImageRes));gl_switcher.setOnItemClickListener(this);}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {is_switcher.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));is_switcher.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out));is_switcher.setImageResource(mImageRes[position]);}public class ViewFactoryImpl implements ViewFactory {@Overridepublic View makeView() {ImageView iv = new ImageView(SwitcherActivity.this);iv.setBackgroundColor(0xFFFFFFFF);iv.setScaleType(ScaleType.FIT_XY);iv.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));return iv;}}@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouch(View v, MotionEvent event) {mGesture.onTouchEvent(event);return true;}private class GestureListener implements GestureDetector.OnGestureListener {private Context mContext;private GestureListener(Context context) {mContext = context;}@Overridepublic final boolean onDown(MotionEvent event) {return true;}@Overridepublic final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {if (e1.getX() - e2.getX() > mFlipGap) {is_switcher.setInAnimation(AnimationUtils.loadAnimation(mContext,R.anim.push_left_in));is_switcher.setOutAnimation(AnimationUtils.loadAnimation(mContext,R.anim.push_left_out));int next_pos = (int) (gl_switcher.getSelectedItemId()+1);if (next_pos >= mImageRes.length) {next_pos = 0;}is_switcher.setImageResource(mImageRes[next_pos]);gl_switcher.setSelection(next_pos);return true;}if (e1.getX() - e2.getX() < -mFlipGap) {is_switcher.setInAnimation(AnimationUtils.loadAnimation(mContext,R.anim.push_right_in));is_switcher.setOutAnimation(AnimationUtils.loadAnimation(mContext,R.anim.push_right_out));int pre_pos = (int) (gl_switcher.getSelectedItemId()-1);if (pre_pos < 0) {pre_pos = mImageRes.length-1;}is_switcher.setImageResource(mImageRes[pre_pos]);gl_switcher.setSelection(pre_pos);return true;}return false;}@Overridepublic final void onLongPress(MotionEvent event) {}@Overridepublic final boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {return false;}@Overridepublic final void onShowPress(MotionEvent event) {}@Overridepublic boolean onSingleTapUp(MotionEvent event) {return false;}}}

调色板Palette

Palette是Android在5.0中引入的调色板控件,它用于分析一个位图对象的整体色调,最后给出样品的色彩RGB值,这样开发者就可以根据具体图片动态设置整个页面的背景色,从而实现统一的页面风格。

Palette在android-support-v7-palette.jar中定义,同时需要最新的android-support-v4.jar支持。使用之前先在sdk的“sdk\extras\android\support\v7\palette\libs”目录中找到jar包并在自己的工程中引用,如果在运行过程中报错“Caused by: java.lang.NoClassDefFoundError: android.support.v4.graphics.ColorUtils”,则是因为Palette调用了v4包中新加的类ColorUtils,解决办法是把最新的android-support-v4.jar导入到你的工程。

Palette的常用方法主要是两个:
from : 从指定的Bitmap对象生成一个调色板建造者对象Palette.Builder。然后调用该Builder对象的generate方法即开始色调分析,generate方法的参数是个PaletteAsyncListener监听器,监听器的onGenerated方法就是完成分析之后的回调处理。
getVibrantSwatch : 获得Palette对象的样品。该方法在onGenerated中调用,返回值是Palette.Swatch样品对象,调用该样品对象的getRgb方法即可获得样品的色彩值。

下面是Gallery与Palette结合使用的效果截图:

下面是Gallery与Palette结合使用的代码例子:

import com.example.exmcard.adapter.GalleryAdapter;
import com.example.exmcard.util.MetricsUtil;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.graphics.Palette;
import android.support.v7.graphics.Palette.PaletteAsyncListener;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener;@SuppressWarnings("deprecation")
public class PaletteActivity extends Activity implements OnItemClickListener, PaletteAsyncListener {private ImageView iv_palette;private Gallery gl_palette;// 图片数组private int[] mImageRes = {R.drawable.scene1, R.drawable.scene2,R.drawable.scene3, R.drawable.scene4,R.drawable.scene5, R.drawable.scene6};private int dip_pad;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_palette);dip_pad = MetricsUtil.dip2px(this, 20);iv_palette = (ImageView) findViewById(R.id.iv_palette);showBackground(mImageRes[0]);gl_palette = (Gallery) findViewById(R.id.gl_palette);gl_palette.setPadding(dip_pad, dip_pad, dip_pad, dip_pad);gl_palette.setSpacing(dip_pad);gl_palette.setUnselectedAlpha(0.5f);gl_palette.setAdapter(new GalleryAdapter(this, mImageRes));gl_palette.setOnItemClickListener(this);}private void showBackground(int res_id) {Drawable drawable = getResources().getDrawable(res_id);Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();Palette.Builder builder = Palette.from(bitmap);builder.generate(this);}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {showBackground(mImageRes[position]);}@Overridepublic void onGenerated(Palette palette) {Palette.Swatch swatch = palette.getVibrantSwatch();if (swatch != null) {iv_palette.setBackgroundColor(swatch.getRgb());}}}

卡片视图CardView

CardView也是Android在5.0中新引入的卡片视图控件,顾名思义它拥有一个卡片式的圆角边框,边框外缘有一圈阴影,边框内缘有一圈空白。该控件的实现原理并不复杂,事实上早期便有许多人自己写了类似卡片效果的控件,只不过后来Android顺应民意推出了原生的卡片视图。

使用CardView之前,要把“sdk\extras\android\support\v7\cardview”导入为一个库工程,并引用到自己的工程中。如果在app运行的时候报错:“Caused by: java.lang.NoClassDefFoundError: android.support.v7.cardview.R$styleable”,这是因为CardView源码中引用了android.support.v7.cardview.R.styleable,而开发者自己的工程包名不是android.support.v7.cardview,所以就会找不到这个R$styleable。
解决步骤如下:
1、要引用整个android-support-v7-cardview工程,不能直接把android-support-v7-cardview.jar复制到自己工程的libs目录。
2、把project.properties里面的“target=android-19”改为“target=android-21”,注意库工程和自己的工程都要改。
3、库工程和自己的工程都Clean Project,然后再编译运行。

CardView的常用属性说明如下(因为引用的是库工程,所以CardView节点的属性要像自定义控件一样对待,即先在根节点定义一个命名空间app指向res-auto,然后再使用app:属性名称来定义属性值,不可直接使用android:属性名称):
cardBackgroundColor : 指定卡片的背景颜色。
cardCornerRadius : 指定卡片的圆角半径。
cardElevation : 指定卡片内容距离阴影边缘的间隔。
contentPadding : 指定卡片边缘阴影的高程,即阴影的宽度。

CardView的常用方法说明如下:
setCardBackgroundColor : 设置卡片的背景颜色。
setRadius : 设置卡片的圆角半径。
setContentPadding : 设置卡片内容距离阴影边缘的间隔。
setCardElevation : 设置卡片边缘阴影的高程,即阴影的宽度。

下面是Gallery与CardView结合使用的效果截图:

下面是Gallery与CardView结合使用的代码例子:

import com.example.exmcard.util.MetricsUtil;import android.content.Context;
import android.support.v7.widget.CardView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;@SuppressWarnings("deprecation")
public class CardAdapter extends BaseAdapter {private Context mContext;private int[] mImageRes;private int dip_pad;private int dip_radius;public CardAdapter(Context context, int[] imageRes) {mContext = context;mImageRes = imageRes;dip_pad = MetricsUtil.dip2px(mContext, 20);dip_radius = MetricsUtil.dip2px(mContext, 5);}@Overridepublic int getCount() {return mImageRes.length;}@Overridepublic Object getItem(int position) {return mImageRes[position];}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {CardView card = new CardView(mContext);//这里不能使用LinearLayout.LayoutParams。否则会报错“java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to android.widget.Gallery$LayoutParams”card.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));card.setRadius(dip_radius);card.setContentPadding(dip_pad, dip_pad, dip_pad, dip_pad);card.setCardElevation(3f);//card.setCardBackgroundColor(Color.GREEN);ImageView iv = new ImageView(mContext);iv.setImageResource(mImageRes[position]);iv.setLayoutParams(new Gallery.LayoutParams(120, 160));iv.setScaleType(ImageView.ScaleType.FIT_XY);card.addView(iv);return card;}}

下面是使用CardView的布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:padding="5dp" ><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center_horizontal|top"android:orientation="vertical" ><android.support.v7.widget.CardViewandroid:id="@+id/cv_one"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center_horizontal|top"app:cardCornerRadius="20dp" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="fitCenter"android:src="@drawable/scene1" /></android.support.v7.widget.CardView></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center_horizontal|top"android:orientation="vertical" ><android.support.v7.widget.CardViewandroid:id="@+id/cv_two"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center_horizontal|top" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="fitCenter"android:src="@drawable/scene2" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="风景如画"android:textColor="#000000"android:textSize="17sp" /></LinearLayout></android.support.v7.widget.CardView></LinearLayout></LinearLayout>

点击下载本文用到的自定义相册的工程代码

点此查看Android开发笔记的完整目录

Android开发笔记(一百二十四)自定义相册相关推荐

  1. Android开发笔记(二十四)res目录的结构与配置

    res目录结构 res是Android项目工程中存放各类的目录,主要包括布局.图形与配置等等.res的子目录主要有: anim : 存放动画的描述文件 drawable : 存放各类图形的描述文件,包 ...

  2. Android开发笔记(五十四)数据共享接口ContentProvider

    ContentProvider 前面几节介绍了进程间通信的几种方式,包括消息包级别的Messenger.接口调用级别的AIDL.启动页面/服务级别的Notification,还有就是本节这个数据库级别 ...

  3. Android开发笔记(七十四)布局文件优化

    include/merge 布局优化中常常用到include/merge标签,include的含义类似C代码中的include,意思是直接把指定布局片段包含进当前的布局文件.include适用于多个布 ...

  4. matlab火星漫游车转向控制,OSG开发笔记(二十四):OSG漫游之平移与转向

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 本文章博客地址:https://blog.csdn.net/qq21497936/ ...

  5. Android开发笔记(二十二)瀑布流网格WaterfallGridView

    瀑布流网格的产生背景 Android中展示门类信息一般使用列表视图ListView或者网格视图GridView,特别是电商类APP的首页,除了顶部导航.底部标签.上方横幅外,主要页面都是展示各种商品和 ...

  6. Android开发笔记(二十五)assets目录下的文件读取

    AssetManager工具类 assets目录用于存放应用程序的资产文件,该目录下的文件不会被系统编译,所以无法通过R.*.*这种方式来访问.Android专门为assets目录提供了一个工具类As ...

  7. Android开发笔记(二十)顶部导航栏ActionBar

    标题栏ActionBar ActionBar是在Android3.0之后引入的,所以Android2.x之前的版本不能直接使用ActionBar.现在ActionBar广泛用做APP的顶部导航栏,它在 ...

  8. Android开发笔记(八十四)使用Properties读写属性值

    Properties概述 Java中的配置文件常为.properties文件,而Properties类便是读写此类文件的工具.属性文件有两种格式,一种是文本格式,其内容是"键=值" ...

  9. Android开发笔记(六十四)网页加载与JS调用

    内置浏览器 网页视图WebView 如果一个网站已经有现成的网页及业务逻辑,那么使用WebView将其内嵌到app中,省去了app重画页面与http通信的事情,无疑是更经济的做法.WebView就是A ...

  10. Android开发笔记(三十四)Excel文件的读写

    Android中操作Excel文件的场合较少见,主要是一些专业领域导入导出报表时使用,所以处理Excel读写的开源代码也很稀缺.目前读写Excel主要采用开源库jxl,这个是韩国人写的excel操作工 ...

最新文章

  1. c#如何取自身应用程序文件名和路径?
  2. Python代码:数字图像处理(DIP)7.1.2子带编码example7.2
  3. 让ABAP开发者更加轻松的若干快捷键
  4. 我的世界java版导入地图_网易我的世界备份与导入地图
  5. day12装饰器进阶
  6. php树形数据结构是什么,数据结构 之 树
  7. 解决oracle数据库连接不上的问题
  8. open函数返回-1_记录学习python的第3天-递归函数/文件操作
  9. CPU多核并发缓存架构介绍
  10. Dubbo的微内核机制
  11. 高效实用Kafka-Kafka消息处理(底层原理)
  12. 学习SQL:INNER JOIN与LEFT JOIN
  13. MacOS如何修复磁盘权限
  14. Python-二分及bisect模块
  15. 何凯明 Single Image Haze Removal Using Dark Channel Prior
  16. 怎么将wmv格式转换成mp4
  17. 在python3中、下列输出变量a的正确写法是_超星尔雅大数据Python答案免费微信公众号...
  18. android图片添加文字,android图片上添加文字
  19. matlab coder 4.0,利用MATLAB Coder将MATLAB代码生成C/C++代码
  20. AI教程:2.5D字体制作方法

热门文章

  1. 工程数学(数值分析)第五讲:数据拟合
  2. Markdown文档如何分页以及导出的PDF如何分页
  3. 十大经典排序算法(附代码、动画及改进方案)
  4. eclipse离线安装Activiti Designer插件
  5. 写程序没思路怎么办?
  6. 机器学习9、10、12/100天-SVM直观认识
  7. 保密作战--在网络上隐藏自己
  8. Soul 网关源码阅读(四)Dubbo请求概览
  9. Mysql Docker 主从配置
  10. MySQL懒查询_mysql 联查的基本命令