vue iview多张图片大图预览、缩放翻转


Posted in Javascript onJuly 13, 2019

本文实例为大家分享了vue iview多张图片大图预览,可缩放翻转,供大家参考,具体内容如下

先看效果:

vue iview多张图片大图预览、缩放翻转

完整项目代码地址

具体代码如下:

<style lang="less">
@import "../advanced-router.less";
</style>
 
<template>
 <div class="balance-accounts">
  <Row class-name="detail-row">
   <Card>
    <p slot="title">
     回单照片
    </p>
    <div class="demo-upload-list" v-for="(item,index) in opPicsList" :key="index">
     <img :src="item.url">
     <div class="demo-upload-list-cover">
      <Icon type="ios-search-strong" @click.native="handleView(item.name)"></Icon>
     </div>
    </div>
   </Card>
  </Row>
 </div>
</template>
<script>
import * as API from "@/api/adminApi";
import iconLeft from "@/images/icon-left.png";
import iconRight from "@/images/icon-right.png";
import iconClose from "@/images/icon-close.png";
import iconRotate from "@/images/icon-rotate.png";
import iconNoImages from "@/images/icon-no-images.png";
 
export default {
 name: "shopping-info",
 data() {
 return {
  opPicsList: [
  {
   name: "none",
   url: iconNoImages
  }
  ],
  bigImage: null,
  currentImageName: "",
  currentRotate: 0
 };
 },
 props: ['imageList'],
 methods: {
 loadDetail() {
  let vm = this;
  API.getFundClearDetail({ orderId: this.$route.query.orderId }).then(
  data => {
   if (data.resultObj.detail) {
   if (data.resultObj.detail.opPics.length > 0) {
    vm.opPicsList.splice(0, vm.opPicsList.length);
    data.resultObj.detail.opPics
    .split(",")
    .forEach((element, index) => {
     vm.opPicsList.push({
     name: index,
     url: element
     });
    });
   }
   }
  }
  );
 },
 rollImg() {
  /* 获取当前页面的缩放比
   若未设置zoom缩放比,则为默认100%,即1,原图大小
  */
  var zoom = parseInt(this.bigImage.style.zoom) || 100;
  /* event.wheelDelta 获取滚轮滚动值并将滚动值叠加给缩放比zoom
   wheelDelta统一为±120,其中正数表示为向上滚动,负数表示向下滚动
  */
  zoom += event.wheelDelta / 12;
  /* 如果缩放比大于0,则将缩放比加载到页面元素 */
  if (zoom >= 100) {
  this.bigImage.style.zoom = zoom + "%";
  }
  /* 如果缩放比不大于0,则返回false,不执行操作 */
  return false;
 },
 handleView(name) {
  if (this.opPicsList[0].name == "none") {
  this.$Message.error("没有图片哦~");
  return;
  }
  this.currentImageName = name;
 
  let elementArr = document.getElementsByClassName("showBigImage");
  if (elementArr.length == 0) {
  this.createShowImage();
  }
  for (let y = 0; y < this.opPicsList.length; y++) {
  if (name == this.opPicsList[y].name) {
   document.getElementById("bigImageE").src = this.opPicsList[y].url;
   break;
  }
  }
 },
 closeImageShow() {
  let elementArr = document.getElementsByClassName("showBigImage");
  let main = document.getElementsByClassName("main");
  let count = elementArr.length;
  for (let i = 0; i < count; i++) {
  main[0].removeChild(elementArr[0]);
  }
 },
 rotateImage() {
  let imageE = document.getElementById("bigImageE");
  this.currentRotate = (this.currentRotate + 90) % 360;
  imageE.style.transform =
  imageE.style.transform.split(" ")[0] +
  " rotate(" +
  this.currentRotate +
  "deg)";
 },
 toLeftImage() {
  for (let y = 0; y < this.opPicsList.length; y++) {
  if (this.currentImageName == this.opPicsList[y].name) {
   if (y - 1 < 0) {
   this.$Message.info("已经是最左边的一张图了哦~");
   } else {
   this.currentImageName = this.opPicsList[y - 1].name;
   let imageE = document.getElementById("bigImageE");
   imageE.src = this.opPicsList[y - 1].url;
   // 加载完成执行
   imageE.onload = function() {
    if (imageE.naturalHeight < window.innerHeight) {
    //图片高度小于屏幕则需要垂直居中处理
    imageE.style.height = imageE.naturalHeight + "px";
    imageE.style.top = "50%";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(-50%)";
    imageE.style.zoom = "100%";
    } else {
    //需要去除前一张图片的效果
    imageE.style.height = window.innerHeight + "px";
    imageE.style.top = "0";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(0%)";
    imageE.style.zoom = "100%";
    }
   };
   }
   break;
  }
  }
 },
 toRightImage() {
  for (let y = 0; y < this.opPicsList.length; y++) {
  if (this.currentImageName == this.opPicsList[y].name) {
   if (y + 1 == this.opPicsList.length) {
   this.$Message.info("已经是最右边的一张图了哦~");
   } else {
   this.currentImageName = this.opPicsList[y + 1].name;
   let imageE = document.getElementById("bigImageE");
   imageE.src = this.opPicsList[y + 1].url;
   // 加载完成执行
   imageE.onload = function() {
    if (imageE.naturalHeight < window.innerHeight) {
    //图片高度小于屏幕则需要垂直居中处理
    imageE.style.height = imageE.naturalHeight + "px";
    imageE.style.top = "50%";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(-50%)";
    imageE.style.zoom = "100%";
    } else {
    //需要去除前一张图片的效果
    imageE.style.height = window.innerHeight + "px";
    imageE.style.top = "0";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(0%)";
    imageE.style.zoom = "100%";
    }
   };
   }
   break;
  }
  }
 },
 createShowImage() {
  //创建图片显示
  let main = document.getElementsByClassName("main");
  let topContainer = document.createElement("div");
  let scrollContainer = document.createElement("div");
  topContainer.style.position = "fixed";
  topContainer.style.zIndex = "80";
  topContainer.style.background = "rgba(0,0,0,0.80)";
  topContainer.style.height = "100%";
  topContainer.style.width = "100%";
  topContainer.style.textAlign = "center";
  topContainer.className = "showBigImage";
 
  let imageContainer = document.createElement("div");
  imageContainer.style.width = window.innerWidth + "px";
  imageContainer.style.height = window.innerHeight + "px";
  imageContainer.style.margin = "0 auto";
  imageContainer.style.overflow = "auto";
  imageContainer.style.top = "50%";
  imageContainer.style.position = "relative";
  imageContainer.style.transform = "translateY(-50%)";
 
  let imageE = document.createElement("img");
  imageE.src = iconNoImages;
  imageE.title = "鼠标滚轮滚动可缩放图片";
  imageE.id = "bigImageE";
  // 加载完成执行
  imageE.onload = function() {
  if (imageE.naturalHeight < window.innerHeight) {
   //图片高度小于屏幕则需要垂直居中处理
   // imageE.style.width = "100%";
   imageE.style.top = "50%";
   imageE.style.position = "relative";
   imageE.style.transform = "translateY(-50%)";
  } else {
   imageE.style.height = window.innerHeight + "px";
  }
  };
 
  this.bigImage = imageE;
 
  //添加鼠标滚轮事件缩放图片
  if (imageE.addEventListener) {
  // IE9, Chrome, Safari, Opera
  imageE.addEventListener("mousewheel", this.rollImg, false);
  // Firefox
  imageE.addEventListener("DOMMouseScroll", this.rollImg, false);
  } else {
  // IE 6/7/8
  imageE.attachEvent("onmousewheel", this.rollImg);
  }
  imageContainer.appendChild(imageE);
  topContainer.appendChild(imageContainer);
 
  main[0].appendChild(topContainer);
 
  //创建点击左右浏览按钮
  //左按钮
  let imgLeft = document.createElement("img");
  imgLeft.src = iconLeft;
  imgLeft.style.zIndex = "101";
  imgLeft.style.position = "fixed";
  imgLeft.style.top = "50%";
  imgLeft.style.transform = "translateY(-50%)";
  imgLeft.style.left = "12%";
  imgLeft.style.cursor = "pointer";
  imgLeft.className = "showBigImage";
  //添加鼠标点击事件切换图片
  imgLeft.addEventListener("click", this.toLeftImage);
  //右按钮
  let imgRight = document.createElement("img");
  imgRight.src = iconRight;
  imgRight.style.zIndex = "101";
  imgRight.style.position = "fixed";
  imgRight.style.top = "50%";
  imgRight.style.transform = "translateY(-50%)";
  imgRight.style.right = "12%";
  imgRight.style.cursor = "pointer";
  imgRight.className = "showBigImage";
  //添加鼠标点击事件切换图片
  imgRight.addEventListener("click", this.toRightImage);
 
  //大图片选转
  let imgRotate = document.createElement("img");
  imgRotate.id = "rotateImageBtn";
  imgRotate.src = iconRotate;
  imgRotate.style.zIndex = "102";
  imgRotate.style.position = "fixed";
  imgRotate.style.top = "5%";
  imgRotate.style.right = "5%";
  imgRotate.style.transform = "translateY(-50%)";
  imgRotate.style.cursor = "pointer";
  imgRotate.className = "showBigImage";
  //添加鼠标点击事件旋转大图
  imgRotate.addEventListener("click", this.rotateImage);
 
  //关闭按钮
  let imgClose = document.createElement("img");
  imgClose.src = iconClose;
  imgClose.style.zIndex = "101";
  imgClose.style.position = "fixed";
  imgClose.style.top = "5%";
  imgClose.style.right = "1%";
  imgClose.style.transform = "translateY(-50%)";
  imgClose.style.cursor = "pointer";
  imgClose.className = "showBigImage";
  //添加鼠标点击事件关闭显示大图
  imgClose.addEventListener("click", this.closeImageShow);
 
  main[0].appendChild(imgLeft);
  main[0].appendChild(imgRight);
  main[0].appendChild(imgClose);
  main[0].appendChild(imgRotate);
 
 }
 },
 mounted() {
 this.loadDetail();
 }
};
</script>

可以看到,这个图片大图预览是用js创建的,而且是在main元素下添加的元素。因为这个是在ivew-admin框架下写的,其主要内容区的z-index是比菜单和header小的,所以如果在内容去写这个图片全局预览阴影区域无法覆盖整个页面。所以需要在main下加入元素。

组件方式:

<template>
 <div>
 </div>
</template>
<script>
import iconLeft from "@/images/icon-left.png";
import iconRight from "@/images/icon-right.png";
import iconClose from "@/images/icon-close.png";
import iconRotate from "@/images/icon-rotate.png";
import iconNoImages from "@/images/icon-no-images.png";
import {IMAGE_URL_PREFIX} from "@/config/constant";
export default {
 data() {
 return {
  opPicsList: [
  {
   name: "none",
   url: iconNoImages
  }
  ],
  imgName: "",
  bigImage: null,
  currentImageName: "",
  currentRotate: 0
 };
 },
 props: {
 },
 methods: {
 loadImages(opPics) {
  this.opPicsList.splice(0, this.opPicsList.length);
  opPics.split(",").forEach((element, index) => {
  this.opPicsList.push({
   name: index,
   url: IMAGE_URL_PREFIX + element
  });
  });
  this.handleView("0");
 },
 rollImg() {
  /* 获取当前页面的缩放比
   若未设置zoom缩放比,则为默认100%,即1,原图大小
  */
 
  var zoom = parseInt(this.bigImage.style.zoom) || 100;
  /* event.wheelDelta 获取滚轮滚动值并将滚动值叠加给缩放比zoom
   wheelDelta统一为±120,其中正数表示为向上滚动,负数表示向下滚动
  */
  zoom += event.wheelDelta / 12;
  /* 如果缩放比大于0,则将缩放比加载到页面元素 */
  if (zoom >= 100) {
  this.bigImage.style.zoom = zoom + "%";
  }
  /* 如果缩放比不大于0,则返回false,不执行操作 */
  return false;
 },
 handleView(name) {
  if (this.opPicsList[0].name == "none") {
  this.$Message.error("没有图片哦~");
  return;
  }
  this.currentImageName = name;
 
  let elementArr = document.getElementsByClassName("showBigImage");
  if (elementArr.length == 0) {
  this.createShowImage();
  }
  for (let y = 0; y < this.opPicsList.length; y++) {
  if (name == this.opPicsList[y].name) {
   document.getElementById("bigImageE").src = this.opPicsList[y].url;
   // debugger
   // document.getElementById("bigImageE").width = this.opPicsList[y].url;
   // document.getElementById("bigImageE").height = this.opPicsList[y].url;
   // for (let i = 0; i < elementArr.length; i++) {
   // elementArr[i].style.display = "block";
   // }
   break;
  }
  }
 },
 closeImageShow() {
  let elementArr = document.getElementsByClassName("showBigImage");
  let main = document.getElementsByClassName("main");
  let count = elementArr.length;
  for (let i = 0; i < count; i++) {
  main[0].removeChild(elementArr[0]);
  }
 },
 rotateImage() {
  let imageE = document.getElementById("bigImageE");
  this.currentRotate = (this.currentRotate + 90) % 360;
  imageE.style.transform =
  imageE.style.transform.split(" ")[0] +
  " rotate(" +
  this.currentRotate +
  "deg)";
 },
 toLeftImage() {
  for (let y = 0; y < this.opPicsList.length; y++) {
  if (this.currentImageName == this.opPicsList[y].name) {
   if (y - 1 < 0) {
   this.$Message.info("已经是最左边的一张图了哦~");
   } else {
   this.currentImageName = this.opPicsList[y - 1].name;
   let imageE = document.getElementById("bigImageE");
   imageE.src = this.opPicsList[y - 1].url;
   // 加载完成执行
   imageE.onload = function() {
    if (imageE.naturalHeight < window.innerHeight) {
    //图片高度小于屏幕则需要垂直居中处理
    imageE.style.height = imageE.naturalHeight + "px";
    imageE.style.top = "50%";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(-50%)";
    imageE.style.zoom = "100%";
    } else {
    //需要去除前一张图片的效果
    imageE.style.height = window.innerHeight + "px";
    imageE.style.top = "0";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(0%)";
    imageE.style.zoom = "100%";
    }
   };
   }
   break;
  }
  }
 },
 toRightImage() {
  for (let y = 0; y < this.opPicsList.length; y++) {
  if (this.currentImageName == this.opPicsList[y].name) {
   if (y + 1 == this.opPicsList.length) {
   this.$Message.info("已经是最右边的一张图了哦~");
   } else {
   this.currentImageName = this.opPicsList[y + 1].name;
   let imageE = document.getElementById("bigImageE");
   imageE.src = this.opPicsList[y + 1].url;
   // 加载完成执行
   imageE.onload = function() {
    if (imageE.naturalHeight < window.innerHeight) {
    //图片高度小于屏幕则需要垂直居中处理
    imageE.style.height = imageE.naturalHeight + "px";
    imageE.style.top = "50%";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(-50%)";
    imageE.style.zoom = "100%";
    } else {
    //需要去除前一张图片的效果
    imageE.style.height = window.innerHeight + "px";
    imageE.style.top = "0";
    imageE.style.position = "relative";
    imageE.style.transform = "translateY(0%)";
    imageE.style.zoom = "100%";
    }
   };
   }
   break;
  }
  }
 },
 createShowImage() {
  //创建图片显示
  // let elementArr = document.getElementsByClassName("showBigImage");
  // if (elementArr.length == 0) {
  let main = document.getElementsByClassName("main");
  let topContainer = document.createElement("div");
  let scrollContainer = document.createElement("div");
  topContainer.style.position = "fixed";
  topContainer.style.zIndex = "80";
  topContainer.style.background = "rgba(0,0,0,0.80)";
  topContainer.style.height = "100%";
  topContainer.style.width = "100%";
  topContainer.style.textAlign = "center";
  topContainer.className = "showBigImage";
  // topContainer.style.display = "none";
 
  let imageContainer = document.createElement("div");
  imageContainer.style.width = window.innerWidth + "px";
  imageContainer.style.height = window.innerHeight + "px";
  imageContainer.style.margin = "0 auto";
  imageContainer.style.overflow = "auto";
  imageContainer.style.top = "50%";
  imageContainer.style.position = "relative";
  imageContainer.style.transform = "translateY(-50%)";
 
  let imageE = document.createElement("img");
  imageE.src = iconNoImages;
  imageE.title = "鼠标滚轮滚动可缩放图片";
  imageE.id = "bigImageE";
  // 加载完成执行
  imageE.onload = function() {
  if (imageE.naturalHeight < window.innerHeight) {
   //图片高度小于屏幕则需要垂直居中处理
   // imageE.style.width = "100%";
   imageE.style.top = "50%";
   imageE.style.position = "relative";
   imageE.style.transform = "translateY(-50%)";
  } else {
   imageE.style.height = window.innerHeight + "px";
  }
  };
  // imageE.style.width = "100%";
  // imageE.style.width = "475px";
  // imageE.style.height = window.innerHeight + 'px';
 
  // imageE.style.objectFit= "scale-down";
  // imageE.style.height = "100%";
  // imageE.style.top = "50%";
  // imageE.style.position = "relative";
  // imageE.style.transform = "translateY(-50%)";
  this.bigImage = imageE;
 
  //添加鼠标滚轮事件缩放图片
  if (imageE.addEventListener) {
  // IE9, Chrome, Safari, Opera
  imageE.addEventListener("mousewheel", this.rollImg, false);
  // Firefox
  imageE.addEventListener("DOMMouseScroll", this.rollImg, false);
  } else {
  // IE 6/7/8
  imageE.attachEvent("onmousewheel", this.rollImg);
  }
  imageContainer.appendChild(imageE);
  topContainer.appendChild(imageContainer);
 
  main[0].appendChild(topContainer);
 
  //创建点击左右浏览按钮
  //左按钮
  let imgLeft = document.createElement("img");
  imgLeft.src = iconLeft;
  imgLeft.style.zIndex = "101";
  imgLeft.style.position = "fixed";
  imgLeft.style.top = "50%";
  imgLeft.style.transform = "translateY(-50%)";
  imgLeft.style.left = "12%";
  imgLeft.style.cursor = "pointer";
  imgLeft.className = "showBigImage";
  //添加鼠标点击事件切换图片
  imgLeft.addEventListener("click", this.toLeftImage);
  //右按钮
  let imgRight = document.createElement("img");
  imgRight.src = iconRight;
  imgRight.style.zIndex = "101";
  imgRight.style.position = "fixed";
  imgRight.style.top = "50%";
  imgRight.style.transform = "translateY(-50%)";
  imgRight.style.right = "12%";
  imgRight.style.cursor = "pointer";
  imgRight.className = "showBigImage";
  //添加鼠标点击事件切换图片
  imgRight.addEventListener("click", this.toRightImage);
 
  //大图片选转
  let imgRotate = document.createElement("img");
  imgRotate.id = "rotateImageBtn";
  imgRotate.src = iconRotate;
  imgRotate.style.zIndex = "102";
  imgRotate.style.position = "fixed";
  imgRotate.style.top = "5%";
  imgRotate.style.right = "5%";
  imgRotate.style.transform = "translateY(-50%)";
  imgRotate.style.cursor = "pointer";
  imgRotate.className = "showBigImage";
  //添加鼠标点击事件旋转大图
  imgRotate.addEventListener("click", this.rotateImage);
 
  //关闭按钮
  let imgClose = document.createElement("img");
  imgClose.src = iconClose;
  imgClose.style.zIndex = "101";
  imgClose.style.position = "fixed";
  imgClose.style.top = "5%";
  imgClose.style.right = "1%";
  imgClose.style.transform = "translateY(-50%)";
  imgClose.style.cursor = "pointer";
  imgClose.className = "showBigImage";
  //添加鼠标点击事件关闭显示大图
  imgClose.addEventListener("click", this.closeImageShow);
 
  // imgLeft.style.display = "none";
  // imgRight.style.display = "none";
  // imgClose.style.display = "none";
  main[0].appendChild(imgLeft);
  main[0].appendChild(imgRight);
  main[0].appendChild(imgClose);
  main[0].appendChild(imgRotate);
  // main[0].style.textAlign = "center";
  // this.imgName = name;
  // this.visible = true;
  // }
 }
 },
 mounted() {
 // this.loadImages();
 }
};
</script>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 清空form表单中某种元素的值
Dec 26 Javascript
再谈javascript面向对象编程
Mar 18 Javascript
JavaScript实现刷新不重记的倒计时
Aug 10 Javascript
Vue2.0子同级组件之间数据交互方法
Feb 28 Javascript
jQuery中的for循环var与let的区别
Apr 21 jQuery
详解JavaScript添加给定的标签选项
Sep 17 Javascript
对angularJs中2种自定义服务的实例讲解
Sep 30 Javascript
vue-cli脚手架打包静态资源请求出错的原因与解决
Jun 06 Javascript
解决vue elementUI中table里数字、字母、中文混合排序问题
Jan 07 Javascript
原生JavaScript实现的无缝滚动功能详解
Jan 17 Javascript
微信小程序学习总结(三)条件、模板、文件引用实例分析
Jun 04 Javascript
vue项目接口域名动态获取操作
Aug 13 Javascript
vue实现图片预览组件封装与使用
Jul 13 #Javascript
微信小程序基于Taro的分享图片功能实践详解
Jul 12 #Javascript
小程序实现悬浮搜索框
Jul 12 #Javascript
小程序实现搜索框功能
Mar 26 #Javascript
iview的table组件自带的过滤器实现
Jul 12 #Javascript
es6中比较有用的7个技巧小结
Jul 12 #Javascript
echarts大屏字体自适应的方法步骤
Jul 12 #Javascript
You might like
推荐5款跨平台的PHP编辑器
2014/12/25 PHP
PHP实现发送邮件的方法(基于简单邮件发送类)
2015/12/17 PHP
PHP实现APP微信支付的实例讲解
2018/02/10 PHP
PHP实现将上传图片自动缩放到指定分辨率,并保持清晰度封装类示例
2019/06/17 PHP
PHP实现长轮询消息实时推送功能代码实例讲解
2021/02/26 PHP
juqery 学习之四 筛选查找
2010/11/30 Javascript
html5 canvas js(数字时钟)实例代码
2013/12/23 Javascript
简单的JavaScript互斥锁分享
2014/02/02 Javascript
AngularJS基础知识笔记之过滤器
2015/05/10 Javascript
js判断是否为空和typeof的用法(详解)
2016/10/07 Javascript
js学习之----深入理解闭包
2016/11/21 Javascript
解决nodejs中使用http请求返回值为html时乱码的问题
2017/02/18 NodeJs
简单的JS控制button颜色随点击更改的实现方法
2017/04/17 Javascript
iview form清除校验状态的实现
2019/09/19 Javascript
[05:49]DOTA2-DPC中国联赛 正赛 Elephant vs LBZS 选手采访
2021/03/11 DOTA
python实现问号表达式(?)的方法
2013/11/27 Python
利用打码兔和超人打码自封装的打码类分享
2014/03/16 Python
解决Python内层for循环如何break出外层的循环的问题
2019/06/24 Python
Pandas DataFrame数据的更改、插入新增的列和行的方法
2019/06/25 Python
解决python 3 urllib 没有 urlencode 属性的问题
2019/08/22 Python
tensorflow对图像进行拼接的例子
2020/02/05 Python
Python MySQL 日期时间格式化作为参数的操作
2020/03/02 Python
Python任务自动化工具tox使用教程
2020/03/17 Python
Python单元测试及unittest框架用法实例解析
2020/07/09 Python
ECCO爱步官方旗舰店:丹麦鞋履品牌
2018/01/02 全球购物
Ever New加拿大官网:彰显女性美
2018/10/05 全球购物
The Athlete’s Foot新西兰:新西兰最大的运动鞋零售商
2019/12/23 全球购物
学期自我鉴定范文
2013/10/01 职场文书
个性发展自我评价
2014/02/11 职场文书
《走一步再走一步》教学反思
2014/02/15 职场文书
银行委托书范本
2014/04/04 职场文书
应聘护士求职信
2014/07/21 职场文书
殡葬服务心得体会
2014/09/11 职场文书
2015年保洁工作总结范文
2015/04/28 职场文书
详解Spring Boot使用系统参数表提升系统的灵活性
2021/06/30 Java/Android
使用jpa之动态插入与修改(重写save)
2021/11/23 Java/Android