精华内容
下载资源
问答
  • 2021-08-26 18:12:26

    教程文档下载.pdf

    交 流 分 享 扣 扣 群 : 925920448 \color{red}{交流分享扣扣群:925920448}

    更多相关内容
  • flutter 仿微信朋友发布图片

    千次阅读 2019-12-05 17:46:48
    控件类, 里面放了很多自己写的一些组件,所以有很多相机用不...另外也可以传网络图片进去显示,格式为: PhotoFrame(imagesShow:_imagesShow); _imagesShow = [ {id: 60, image: https://www.tricklen.com/p...

    控件类,
    里面放了很多自己写的一些组件,所以有很多相机用不到的引用,
    但为了防止误删一些引用,所有的都没有删除,如果拿去用,灰色的可以直接删掉即可,
    另外也可以传网络图片进去显示,格式为:

        PhotoFrame(imagesShow:_imagesShow);
        _imagesShow = [
    			{id: 60, image: https://www.tricklen.com/publicImage/1bed62c0e9e7406795317f1b16e94632.jpg},
    			 {id: 61, image: https://www.tricklen.com/publicImage/ed179d808682455e9cf8b8f0f9d40f08.jpg},
    			  {id: 62, image: https://www.tricklen.com/publicImage/4015cf30afd94e60a3d3a5b2bd562827.jpg},
    			   {id: 137, image: https://www.tricklen.com/publicImage/3046cc0f8d8746e7a0f3c70cb7add240.jpg},
    			    {id: 138, image: https://www.tricklen.com/publicImage/5a668a7baae941a6ac826978ddbdf84e.jpg}
    	];
    

    其中,id为网图的id,是为了删除识别的需要

    
    import 'package:flutter/material.dart';
    import 'dart:math' as math;
    import 'package:redenvelope/pages/extendBlackList/blackLiatDetails.dart';
    import 'package:redenvelope/pages/extendBlackList/blackLiatDetails1.dart';
    import 'package:redenvelope/constant/colors.dart';
    import 'package:redenvelope/widget/UserImg.dart';
    import 'package:fluttertoast/fluttertoast.dart'; //弹出框库
    import 'package:image_picker/image_picker.dart'; //调用相机 相册
    import 'package:dio/dio.dart';
    import 'dart:io';
    import 'package:photo/photo.dart'; //调用photo库
    import 'package:photo_manager/photo_manager.dart';
    import 'package:flutter_image_compress/flutter_image_compress.dart'; //图片压缩
    import 'dart:async';
    import 'package:redenvelope/constant/App.dart';
    import 'package:redenvelope/widget/UserImg.dart';
    import 'package:redenvelope/pages/extendBlackList/domeData.dart';
    
    // 相机组件
    class PhotoFrame extends StatefulWidget{
      var imagesShow;
      PhotoFrame({this.imagesShow});
      @override
      State<StatefulWidget> createState() {
        print("---------------图片是否传递---------------------");
        print(imagesShow);
        return new PhotoFrameState();
      }
    }
    
    class PhotoFrameState extends State<PhotoFrame> with WidgetsBindingObserver {
    
      List<Widget> _imageShow = [];
    
      // 获取的需要显示的数组
      List _imageUrlShow = [];
    
      var item; //数据封装
    
      Widget addImage;
    
      int index = 1;
      List<String> imageUrl = []; //存放偶像头像地址的数组
    
      File _image; //当前图片
      List<File> images = []; //记录所有图片
      List<Widget> ConList = []; //显示复数图片的数组
      List<UploadFileInfo> _rq = []; //FormData内传递的值
    
    
      // 单张相机取图片
      Future getImage() async {
    
        var image = await ImagePicker.pickImage(source: ImageSource.camera); //相机
        _image = image;
    
        print(_image);
        images.add(_image);
        ff();
    
    
      }
    
      // 多张连选取图
      void _pickImage() async {
    
        List<AssetEntity> imgList = await PhotoPicker.pickAsset(
          //需要BuildContext
          context: context,
    
          ///以下是可选参数。
          themeColor: AppColors.colorPrimary,
          //标题颜色和底部颜色
          padding: 1.0,
          //项目填充
          dividerColor: Colors.grey,
          //分隔线颜色
          disableColor: Colors.grey.shade300,
          //复选框禁用颜色
          itemRadio: 0.88,
          //内容项目radio
          maxSelected: 8 - images.length -_imageUrlShow.length,
          //最大选择器图像计数
          provider: I18nProvider.chinese,
          //提供者:I18nProvider.chinese,
          // i18n提供者,默认为中文。 ,您可以自定义I18nProvider或使用ENProvider()
          rowCount: 3,
          //项目行数
          textColor: Colors.white,
          //文字颜色
          thumbSize: 150,
          //预览拇指大小,默认为64
          sortDelegate: SortDelegate.common,
          //默认是常见的,或者您可以自定义委托来对图库进行排序
          checkBoxBuilderDelegate: DefaultCheckBoxBuilderDelegate(
            activeColor: Colors.white,
            unselectedColor: Colors.white,
          ),
          //默认为DefaultCheckBoxBuilderDelegate,或者您创建自定义委托以创建复选框
    
          //loadingDelegate: this,
          //如果你想构建自定义加载小部件,请扩展LoadingDelegate,[参见example / lib / main.dart]
    
          badgeDelegate: const DurationBadgeDelegate(),
        );
    
        //List<String> r = [];//路径
        for (var e in imgList) {
          _image = await e.file;
          //r.add(_image.absolute.path);//获取路径
    
          print(_image);
          images.add(_image);
        }
    
        ff();
    
    
      }
    
      // 处理图片
      void ff() {
    
        if (ConList.length > 1) {
          ConList.removeRange(1, ConList.length);
        }
        // 先读取传过来的图片,并显示
        if(_imageUrlShow.length!=0){
          for (var i = 0; i < _imageUrlShow.length; i++) {
            ConList.add(
              new Stack(
                alignment: const FractionalOffset(1.30, -0.3),
                children: <Widget>[
                  Container(
                    height: 95,
                    width: 95,
                    child: Image.network(_imageUrlShow[i]["image"], fit: BoxFit.cover),
                  ),
                  IconButton(
    
                    iconSize: 20,
                    icon: Container(
    
                      child: Icon(Icons.clear,color: Colors.black,),
                      decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(10.0), //10像素圆角
    
                      ),
                    ),
                    onPressed: () {
                      setState(() {
                        print("--------------------是否传递图片过来过---------------------------");
                        print(_imageUrlShow[i]["id"].toString());
                        print(ConList);
                        print(_imageUrlShow);
    
                        // 添加删除图片的id
                        SaveData.imagesRemoveId =
                            SaveData.imagesRemoveId +_imageUrlShow[i]["id"].toString()+"|";
    
                        //删除数组中存储的图片地址
                        var x = _imageUrlShow.remove(_imageUrlShow[i]);
    
    
                        print(x);
                        //删除组件
                        ConList.remove(ConList[i + 1]);
    
                        ff();
                      });
                    },
                  ),
                ],
              ),
            );
          }
        }
    
    
        // 在读取本地图片,并显示
        if(images.length!=0){
          for (var i = 0; i < images.length; i++) {
            ConList.add(
              new Stack(
                alignment: const FractionalOffset(1.30, -0.3),
                children: <Widget>[
                  Container(
                    height: 95,
                    width: 95,
                    child: Image.file(images[i], fit: BoxFit.cover),
                  ),
                  IconButton(
                    color: Colors.grey[350],
                    iconSize: 20,
                    icon: Container(
    
                      child: Icon(Icons.clear,color: Colors.black,),
                      decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(10.0), //10像素圆角
    
                      ),
                    ),
                    onPressed: () {
                      setState(() {
                        //删除当前图片
                        _image = null;
                        //删除数组中存储的图片地址
                        var x = images.remove(images[i]);
    
                        print(x);
                        //删除组件
                        ConList.remove(ConList[i + 1]);
                        print(ConList);
                        ff();
                      });
                    },
                  ),
                ],
              ),
            );
          }
          _saveDate();
        }
    
    
        setState(() {});
      }
    
      // 封装数据
      Future _saveDate() async {
    
        _rq.clear();
    
        //压缩图片并封装
        for (var i = 0, len = images.length; i < len; i++) {
          File file = images[i];
    
          file = await FlutterImageCompress.compressAndGetFile(
            file.absolute.path,
            Directory.systemTemp.path + '/head' + i.toString() + '.jpg',
            minWidth: 1920,
            minHeight: 1080,
            quality: 60,
          );
    
          _rq.add(new UploadFileInfo(
              file, App.userid.toString() + i.toString() + ".jpg"));
        }
    
        SaveData.imagesListFlie   = images;
        SaveData.imagesList   = _rq;
    
        print("图片文件数组长度"+SaveData.imagesListFlie.length.toString());
        print("图片上传数据流数组长度"+SaveData.imagesList.length.toString());
    
        return true;
      }
    
      @override
      void initState() {
        super.initState();
        _imageUrlShow = widget.imagesShow==null?
        []:
        widget.imagesShow;
    
        ConList.add(Container(
          color: Colors.grey[200],
          height: 95,
          width: 95,
          child: FlatButton(
              onPressed: () {
                //弹出底部弹窗
                showModalBottomSheet(
                    context: context,
                    builder: (BuildContext context) {
                      return Column(
                        mainAxisSize: MainAxisSize.min,
                        children: <Widget>[
                          Container(
                            decoration: BoxDecoration(
                              //背景装饰
    
                              borderRadius: BorderRadius.circular(5.0),
                            ),
                            child: Column(
                              mainAxisSize: MainAxisSize.min,
                              children: <Widget>[
                                ListTile(
                                  title: Center(
                                    child: Center(
                                      child: Text(
                                        '请选择',
                                        style: TextStyle(color: Colors.black26,fontFamily:'appIconFonts'),
                                      ),
                                    ),
                                  ),
                                ),
                                Divider2(),
                                ListTile(
                                  title: Center(
                                    child: Text("拍照",style: TextStyle(fontFamily:'appIconFonts'),),
                                  ),
                                  onTap: () {
                                    //调用相机
                                    Navigator.of(context).pop();
                                    images.length + _imageUrlShow.length < 8
                                        ? getImage()
                                        : Fluttertoast.showToast(
                                        msg: "图片的数量不能超过8张",
                                        toastLength: Toast.LENGTH_SHORT,
                                        gravity: ToastGravity.CENTER,
                                        timeInSecForIos: 1,
                                        backgroundColor: Colors.black12,
                                        textColor: Colors.black,
                                        fontSize: 16.0);
                                  },
                                ),
                                Divider2(),
                                ListTile(
                                  title: Center(
                                    child: Text("从本地相册选择",style: TextStyle(fontFamily:'appIconFonts'),),
                                  ),
                                  onTap: () {
                                    Navigator.of(context).pop();
                                    //读取相册
                                    images.length + _imageUrlShow.length < 8
                                        ? _pickImage()
                                        : Fluttertoast.showToast(
                                        msg: "图片的数量不能超过8张",
                                        toastLength: Toast.LENGTH_SHORT,
                                        gravity: ToastGravity.CENTER,
                                        timeInSecForIos: 1,
                                        backgroundColor: Colors.black12,
                                        textColor: Colors.black,
                                        fontSize: 16.0);
                                  },
                                ),
                              ],
                            ),
                          ),
                          Container(
                            height: 10,
                            color: Colors.black26,
                          ),
                          ListTile(
                            title: Center(
                              child: Text(
                                "取消",
                                style: TextStyle(
                                    fontWeight: FontWeight.w600,fontFamily:'appIconFonts'
                                ),
                                textScaleFactor: 1.0,
                              ),
                            ),
                          ),
                        ],
                      );
                    });
              },
              child: Icon(
                Icons.add_a_photo,
                color: Colors.black26,
              )),
        ));
    
        ff();
      }
    
      @override
      void dispose() {
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        if (App.wangLuoZhaugnTai == 1) {
          return Center(
            child: Text('网络错误,无法执行...',style: TextStyle(fontFamily:'appIconFonts'),),
          );
        }
    
    
        print(ConList);
    
    
        return Container(
    //
            padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
            margin: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 0.0),
            child: Container(
              child: Wrap(
                spacing: 8.0, // 主轴(水平)方向间距
                runSpacing: 4.0, // 纵轴(垂直)方向间距
                children: ConList,
              ),
            ));
      }
    }
    
    

    需要几个插件
    image_picker
    flutter_image_compress
    photo
    在这里插入图片描述
    在这里插入图片描述
    这个是压缩图片的,非必须,但是如果不用,就可以直接注释掉关于这个插件的调用

    调用很简单,一句话,如果不用显示上次图片,不用传递参数

    	PhotoFrame();
    

    另外需要一个存储类,用来存储选中的图片

    // 存储选择图片
    class SaveData {
    
      // 存储图片文件
      static  List imagesListFlie=[] ;
    
      // 存储图片字节码
      static  List imagesList = [];
    
    // 需要删除的图片的id,这些图片为上次上传的图片
      static  String imagesRemoveId = '';
    
      // 当前坐标
      static double X;
      static double Y;
    
      // 清除缓存,初始化数据
      static void  clearListFlie(){
        SaveData.imagesListFlie.clear();
        SaveData.imagesList.clear();
        SaveData.imagesRemoveId = "";
      }
    
    
    }
    

    clearListFlie方法用于重复调用此控件的时候防止上次的数据残留,可以写在每次调用控件的之前

    展开全文
  • 原文链接:...用了 Python 的 matplolibt 和 R 的 ggplot2 后,我再也不想用 MATLAB 画图了。我现在这里先给出本博文用到的包:libraryLoading required package: latticeLoading req...

    原文链接:https://wklchris.github.io/R-plotting-basic.html

    R 的绘图功能一直为业内所津津乐道。用了 Python 的 matplolibt 和 R 的 ggplot2 后,我再也不想用 MATLAB 画图了。

    我现在这里先给出本博文用到的包:

    library
    Loading required package: lattice
    Loading required package: survival
    Loading required package: Formula
    Loading required package: ggplot2

    Attaching package: 'Hmisc'

    The following objects are masked from 'package:base':

    format.pval, round.POSIXt, trunc.POSIXt, units
    library
    Loading required package: sm
    Package 'sm', version 2.2-5.4: type help(sm) for summary information

    基础命令

    使用 dev.new() 命令新建一个图片视图,这样你可以输出多个图片到屏幕,而不是让之后输出的覆盖之前的图形。关于 dev.next(), dev.prev(), dev.set() 及 dev.off() 等内容,参考 help(dev.cur).

    plot() 绘图类型

    基本的绘图类型有以下几种,使用 type= 参数指定:

    • p:仅数据点,默认值。

    • l:仅线段

    • b:线段与点

    • c:仅线段,但点的位置留出空白

    • o:线段与点,但线段会延伸到点内部

    • h:直方图风格,即带竖直密度线

    • s:阶梯图

    • S:其他特殊情况

    • n;不绘制图形。用于指定标题、坐标轴名称的情况

    输出到文件

    将画图的内容输出到文件,可以指定路径,不指定就输出到当前工作目录。例如输出 pdf:

    pdf("plot.pdf")
    plot(c(1, 2, 3), c(3, 4, 2))
    dev.off()

    除了 pdf() 外,其他可用的输出格式对应函数:

    • wmf:win.metafile(),仅在 Windows 系统下使用

    • png: png()

    • jpeg: jpeg()

    • bmp: bmp()

    • tiff: tiff()

    • ps: postscript()

    例子。详细的参数在下文讨论。

    x

    d27b12838f549079efc2e6595916467a.png

    绘图参数:par()

    函数 par() 用来获取当前图形的参数。如果加入 no.readonly=TRUE, 表示该参数列表是非只读的,即用户可以进行修改。例如对于上图,我们获取其参数,进行更改后再传到新的图中(pch 参数可能有些费解,我们在下文讨论):

    # 方法一:类交互式的更改方法

    05a0ad08cf3a0ca1487fab113f59ec1a.png

    点样式、线宽与线型

    参数可选值
    pch 点样式0空方块,1空圆,2空三角,3加号,4乘号,5斜空方块,6空倒三角,7叉方块,8星号,9斜叉方块,10圈加号,11六芒星,12田,13圈乘号,14加框尖角,15方块,16圆点,17三角,18斜方块,19带边线圆点,20带边线2/3圆点,21填充圆,22填充方块,23填充斜方块,24填充三角,25填充倒三角。
    cex 点大小数字,例如 0.5。
    lty 线型1实线,2短虚线,3点线,4点划线,5长虚线,6长短划线。
    lwd 线宽数字。

    注: pch = 19 相比 pch = 16,主要体现在 lwd 与 cex 不同时,带边线圆点的尺寸较大。

    颜色

    调整颜色的参数有:

    • col: 绘图颜色。

    • col.axis:坐标轴刻度颜色。

    • col.lab:坐标轴名称颜色。

    • col.main:图形标题颜色。

    • col.sub:副标题颜色。

    • fg:图形前景色。

    • bf:图形背景色。

    指定颜色的方式有如下几种:

    • 数字下标:col=1

    • 名称:col=”white”

    • 十六进制值:col=”#FFFFFF”

    • 标准化RGB/HSV值:col=rgb(0,1,1)/hsv(0,0,1)

    至于 R 支持的颜色名称,多达 600 余种,这里给出一些我认为常见的:

    OutputColors

    a4f8110868cf07034aa17b354ac9402e.png

    R 中还有其他方式可以生成一系列的颜色,比如:

    par

    439412410a030c727948fdb7a7089be5.png

    标签和标题文本

    从上文可以看出端倪,标签与标题参数有:

    • 标题/副标题:title/sub

    • 坐标轴标题:xlab/ylab

    在标题中使用上文介绍的参数:

    title(main="My Title", col.main="red",
    sub="My Subtitle", col.sub="blue",
    xlab="My X label", ylab="My Y label",
    col.lab="green", cex.lab=0.75)

    要定义它们的字体,可添加的参数有:

    参数含义
    cex基础缩放倍数
    cex.axis坐标轴刻度的缩放倍数
    cex.lab坐标轴标题的缩放倍数
    cex.main图形标题的缩放倍数
    cex.sub图形副标题的缩放倍数
    font字体样式。1常规,2加粗,3加斜,4加粗加斜,5符号字体
    font.axis坐标轴刻度的字体样式
    font.lab/ main/ sub类推
    ps字体磅值。文字的最终大小为 cex * ps
    family字族。例如 serif衬线, sans无衬线, mono等宽

    字族的使用需要注意:Windows 中,等宽映射为 Courier New,衬线 Times New Roman,无衬线 Arial。你可以使用 windowsFonts() 函数来更改或者创建映射,例如我个人常用的 DejaVu 等宽字体:

    windowsFonts

    4fc2d3a9170e8a4a8507c27d3ad9e8a6.png

    如果你需要将图片输出到 pdf,这个参数也是可以使用的:

    pdf(file="filename.pdf", family="M")

    图形尺寸与边距

    参数 pin 用于指定图形尺寸(英寸),例如 pin=c(4, 3) 表示 4 英寸宽 3 英寸高。

    用 mai()/mar() 依次指定下左上右四个方向的边距,单位分别是英寸与英分。默认是 mar(c(5, 4, 4, 2)) + 0.1

    自定义其他元素

    坐标轴

    函数 side() 用于自定义坐标轴:

    axis(side, at=, labels=, pos=, lty=, col=, las=, tck=, ...)
    • side: 指定在哪绘制坐标轴:1下2左3上4右

    • at:刻度线位置

    • labels:刻度线旁的标签,缺省时使用 at 中的值

    • pos:坐标轴与另一坐标轴相交位置的值

    • lty/col:线型/线与刻度的颜色

    • las:标签平行于(=0)或垂直于(=2)坐标轴

    • tck:刻度线。负值表示在图形外侧,0表示禁用刻度,1表示全长(即网格线);默认 -0.01

    网格线:abline() 与次要刻度

    如果想使用次要刻度,请安装 Hmisc 包。次要刻度的长度将会是主刻度的 tick.ratio 倍。

    网格线使用 abline() 命令,并分别用 h/v 指定网格线是竖直还是水平。

    # 需要加载:library(Hmisc)

    fd667770df0b6594ae09bc652fb742f8.png

    图例

    命令 legend() 用于添加图例。

    legend(location, legend, [title=, ...])

    参数含义:

    • location:指定图例左上角的坐标,或者使用以下关键字:

      • 关键字:left/right, bottom/top, bottomleft/right, topleft/right, center

      • 如果使用了以上关键字,可以使用 inset= 参数指定向图形内移动的比例(分数形式)

    • legend:标签组成的字符型向量。

    • title:图例标题的字符串

    • 其他参数:

      • col/pch/lwd/lty:图例线条颜色/点样式/线宽/线型

      • bty/fill:盒型样式/颜色填充(用于条形图、箱形图或饼图)

      • bg:背景色

      • text.col:文本颜色

      • horiz:TRUE 会将图例水平放置

    例子参见“直方图”一节的最后一例。

    标注

    文字标注

    主要有两个函数:text() 与 mtext()。前者向绘图区添加标注,后者向图形的边界添加标注。

    text(location, "string", pos, ...)
    mtext("string", side, line=n, ...)

    可以参考“标签和标题文本”一节的例子。其中:

    • pos:使用1下2左3上4右的对应关系,比如“颜色”一节中就使用了 pos=1 的参数。

      • 如果指定了 pos,那么也可以指定 offset= 作为偏移量比值(相对单个字符宽)

    • side:指定放置文本的图片边界,同样是1下2左3上4右。

      • 你可以使用 line= 来移动文本(正值向外,负值向内);

      • 还可以通过 adj=0/1 指定文本向左下/右上对齐。

    数学标注

    类似 LaTeX 的标注方式,不过实质上仍有一些区别:

    代码效果代码效果代码效果
    x%+-%yx±y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x±yx±yx%/%yx÷y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x÷yx÷yx%*%yx×y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x×yx×y
    x%.%yx⋅y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x⋅yx⋅yx[i]xi" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">xixix^2x2" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x2x2
    x%prop%yx∝y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x∝yx∝ysqrt(x, y)xy" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">y√xxyx!=yx≠y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x≠yx≠y
    x%~~%yx≈y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x≈yx≈yx%=~%yx≅y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x≅yx≅yx%==%yx≡y" role="presentation" style="display: inline-block; line-height: 0; text-align: left; font-size: 18.72px; overflow-wrap: normal; word-spacing: normal; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border-width: 0px; border-style: initial; border-color: initial; padding-top: 1px; padding-bottom: 1px;">x≡yx≡y

    部分字体相关的命令:

    • plain(x):正体

    • italic(x):意大利字族(加斜)

    • bold(x):加粗

    • bolditalic(x):加斜加粗

    • underline(x):下划线

    叠加绘图

    叠加绘图最简单的方法,就是使用绘图的 new=TRUE

    plot

    如果想要添加额外的点、线,使用 points() 命令与 lines() 命令。以及上面提到的参考线 abline() 命令:

    plot

    子图

    函数 layout()

    函数 layout() 是一个强大的命令。例如:

    layout(matrix(c(1,1,2,3), 2, 2, byrow = TRUE))

    就指定了图 1 占用第一行,图 2 和 3 共用第二行。也可以用 widths=/heights= 参数指定各列宽/各行高之间的比例:

    tmp

    函数 par() 的 mfrow 参数

    前文介绍过的 par() 中的 mfrow= 参数也是一个控制子图的方式。下例是两行两列的子图:

    opar par(mfrow=c(2,2))
    plot(...) # 图 1,左上
    plot(...) # 图 2,右上
    plot(...) # 图 3,左下
    plot(...) # 图 4,右下
    par(opar)

    函数 par() 的 fig 参数

    这种方式支持你以任何的位置、组合任意的图形。它比规整的 layout() 更加灵活。以下不使用 0.8 而使用 0.65 是为了看上去更紧凑。

    opar

    统计图

    条形图:barplot()

    直接上例子。

    tmp

    饼图:pie()

    并不推荐的统计图类型,因此 R 中的功能也很有限。

    pie
    dt

    直方图:hist() 及核密度曲线

    直方图表示的是一维的数据(连续型)特征,纵轴是其在对应横轴区间内的频数或者频率。

    hist

    其中 freq 参数默认指定纵轴为频数而不是频率,break 用于指定横轴上分组的个数。

    set.seed

    轴须图是一种一维的数据呈现,而上面的左图中的密度曲线是一种核密度估计。要比较核密度图,参考 sm 包的 sm.density.compare() 函数。如果只是要绘制,使用 density() 函数辅助即可:

    plot

    箱形图:boxplot() 及小提琴图

    或者叫箱线图、盒须图。它描述了连续变量的五个特征参数:

    fig

    如果是 dataframe 数据集中的类别型变量 A ,使用如下语句生成并列箱形图:

    boxplot(y~A, data=dataframe)

    如果将公式改写成 y~A*B,那么会将类别型变量 A 和 B 的各水平两两组合,再生成箱形图。

    其他参数:

    • varwidth=F/T:为 TRUE 时,箱形图的宽度与样本数的算术平方根成正比。

    • horizontal=F/T:为 TRUE 时,箱形图被横置。

    • notch=F/T:为 TRUE 时,箱形图在绘制时会显示“凹槽”。

    df

    最后再提一下箱形图与核密度图的一个结合体:小提琴图(violin plot)。这种图的绘制需要 vioplot 包。

    在小提琴图中,核密度曲线被竖直放置,并对称地显示于数据轴的两侧:

    # 需要加载:library(vioplot)

    点图

    用于在水平刻度上绘制大量标签。本例选自参考书目同名章节。各参数:

    • groups:选定一个因子,作为分组依据。

    • gcolor:各组标签的颜色。

    # mtcars 是 R 预装的数据集,其 cyl 变量有三个水平

    猜你可能喜欢

    MySQL 面试之必会知识点

    R语言文本分词之——Rwordseg包

    Python科学计算:pandas

    Python科学计算:numpy

    kmeans算法python代码——可直接运行

    梯度下降算法

    展开全文
  • 再看文章之前,希望大家先打开自己的微信点到朋友中去,仔细观察是不是发现朋友里的有个“九宫格”的图片区域,点击图片又会跳到图片的详细查看页面,并且支持图片的滑动和缩放?这个功能是不是很常用呢?!那么...

    再看文章之前,希望大家先打开自己的微信点到朋友圈中去,仔细观察是不是发现朋友圈里的有个“九宫格”的图片区域,点击图片又会跳到图片的详细查看页面,并且支持图片的滑动和缩放?这个功能是不是很常用呢?!那么我今天正好做了这个Demo,下面为大家讲解一下。首先按照惯例先看一下效果图吧,尤其不会录制gif动画(哎~没办法,模拟器不支持多点触控,刚好我的手机又没有Root,不能录屏,悲催啊,大家见谅,想要看真实效果的话,烦请移到文章最下方转载文章中进行源码下载,点击下载源码,运行后再看效果哈~~),这里先就拿几张静态的图片顶替一下好了。见谅!

    7ac9f7b507fbadd833c586d42d1231ef.png

    效果嘛,将就着看吧!实在看不明白就想想微信朋友圈,或者拖到下方,点击下载源码!这里,首先分析一下主界面吧,布局都是很简单的,主界面仅仅就是一个ListView的控件,ListView的Item上值得注意的是,Item上包含了一个GridView,这个GridView呗用作实现“九宫格”的效果,主界面布局就是一个ListView,这里不说了,我们先来看看ListView的Item的布局吧,以下是item_list.xml

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="5dp"

    android:paddingTop="5dp" >

    android:id="@+id/iv_avatar"

    android:layout_width="50dp"

    android:layout_height="50dp"

    android:background="@drawable/ic_launcher"

    android:scaleType="centerCrop" />

    android:id="@+id/tv_title"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_marginLeft="5dp"

    android:layout_toRightOf="@id/iv_avatar"

    android:text="爷,今天心情好!"

    android:textSize="16sp" />

    android:id="@+id/tv_content"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_below="@+id/tv_title"

    android:layout_marginLeft="5dp"

    android:layout_marginTop="3dp"

    android:layout_toRightOf="@id/iv_avatar"

    android:text="今天又是雾霾!"

    android:textSize="16sp" />

    android:id="@+id/gridview"

    android:layout_width="220dp"

    android:layout_height="wrap_content"

    android:layout_below="@id/tv_content"

    android:layout_marginLeft="5dp"

    android:layout_marginTop="3dp"

    android:layout_toRightOf="@id/iv_avatar"

    android:columnWidth="70dp"

    android:gravity="center"

    android:horizontalSpacing="2.5dp"

    android:numColumns="3"

    android:stretchMode="columnWidth"

    android:verticalSpacing="2.5dp" />

    好了,大家看到了,布局也是极其简单的,但是有个问题就是ListView嵌套进了GridView,那么就会出现一个问题,导致GridView显示的不全,那么该怎么解决这个问题呢?其实也简单,就是重写一个GridView,测量一下GridView的高度,再设置上去。具体解决方案请看上篇博文ListView嵌套GridView显示不全解决方法或者源码,如下NoScrollGridView.java

    package com.example.imagedemo;

    import android.content.Context;

    import android.util.AttributeSet;

    import android.widget.GridView;

    /**

    * 自定义的“九宫格”——用在显示帖子详情的图片集合 解决的问题:GridView显示不全,只显示了一行的图片,比较奇怪,尝试重写GridView来解决

    *

    * @author lichao

    * @since 2014-10-16 16:41

    *

    */

    public class NoScrollGridView extends GridView {

    public NoScrollGridView(Context context) {

    super(context);

    // TODO Auto-generated constructor stub

    }

    public NoScrollGridView(Context context, AttributeSet attrs) {

    super(context, attrs);

    // TODO Auto-generated constructor stub

    }

    public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) {

    super(context, attrs, defStyle);

    // TODO Auto-generated constructor stub

    }

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    // TODO Auto-generated method stub

    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,

    MeasureSpec.AT_MOST);

    super.onMeasure(widthMeasureSpec, expandSpec);

    }

    }

    接下来看看ListView上面Item的实体是什么样的数据结构,这就显得非常简单了。

    public class ItemEntity {

    private String avatar; // 用户头像URL

    private String title; // 标题

    private String content; // 内容

    private ArrayList imageUrls; // 九宫格图片的URL集合

    public ItemEntity(String avatar, String title, String content,

    ArrayList imageUrls) {

    super();

    this.avatar = avatar;

    this.title = title;

    this.content = content;

    this.imageUrls = imageUrls;

    }

    ...

    }

    好了,有了ListView,那么不可避免的就是做Item上的数据适配了。继承一个BaseAdapter,代码如下,都比较简单:

    /**

    * 首页ListView的数据适配器

    *

    * @author Administrator

    *

    */

    public class ListItemAdapter extends BaseAdapter {

    private Context mContext;

    private ArrayList items;

    public ListItemAdapter(Context ctx, ArrayList items) {

    this.mContext = ctx;

    this.items = items;

    }

    @Override

    public int getCount() {

    return items == null ? 0 : items.size();

    }

    @Override

    public Object getItem(int position) {

    return items.get(position);

    }

    @Override

    public long getItemId(int position) {

    return position;

    }

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder;

    if (convertView == null) {

    holder = new ViewHolder();

    convertView = View.inflate(mContext, R.layout.item_list, null);

    holder.iv_avatar = (ImageView) convertView

    .findViewById(R.id.iv_avatar);

    holder.tv_title = (TextView) convertView

    .findViewById(R.id.tv_title);

    holder.tv_content = (TextView) convertView

    .findViewById(R.id.tv_content);

    holder.gridview = (NoScrollGridView) convertView

    .findViewById(R.id.gridview);

    convertView.setTag(holder);

    } else {

    holder = (ViewHolder) convertView.getTag();

    }

    ItemEntity itemEntity = items.get(position);

    holder.tv_title.setText(itemEntity.getTitle());

    holder.tv_content.setText(itemEntity.getContent());

    // 使用ImageLoader加载网络图片

    DisplayImageOptions options = new DisplayImageOptions.Builder()//

    .showImageOnLoading(R.drawable.ic_launcher) // 加载中显示的默认图片

    .showImageOnFail(R.drawable.ic_launcher) // 设置加载失败的默认图片

    .cacheInMemory(true) // 内存缓存

    .cacheOnDisk(true) // sdcard缓存

    .bitmapConfig(Config.RGB_565)// 设置最低配置

    .build();//

    ImageLoader.getInstance().displayImage(itemEntity.getAvatar(),

    holder.iv_avatar, options);

    final ArrayList imageUrls = itemEntity.getImageUrls();

    if (imageUrls == null || imageUrls.size() == 0) { // 没有图片资源就隐藏GridView

    holder.gridview.setVisibility(View.GONE);

    } else {

    holder.gridview.setAdapter(new NoScrollGridAdapter(mContext,

    imageUrls));

    }

    // 点击回帖九宫格,查看大图

    holder.gridview.setOnItemClickListener(new OnItemClickListener() {

    @Override

    public void onItemClick(AdapterView> parent, View view,

    int position, long id) {

    // TODO Auto-generated method stub

    imageBrower(position, imageUrls);

    }

    });

    return convertView;

    }

    /**

    * 打开图片查看器

    *

    * @param position

    * @param urls2

    */

    protected void imageBrower(int position, ArrayList urls2) {

    Intent intent = new Intent(mContext, ImagePagerActivity.class);

    // 图片url,为了演示这里使用常量,一般从数据库中或网络中获取

    intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_URLS, urls2);

    intent.putExtra(ImagePagerActivity.EXTRA_IMAGE_INDEX, position);

    mContext.startActivity(intent);

    }

    /**

    * listview组件复用,防止“卡顿”

    *

    * @author Administrator

    *

    */

    class ViewHolder {

    private ImageView iv_avatar;

    private TextView tv_title;

    private TextView tv_content;

    private NoScrollGridView gridview;

    }

    }

    这里有需要解释的地方了,看看listview上的图片处理,由于图片都是从网络获取的,为了避免图片过多造成OOM,那么这里加载图片的时候必不可少的需要做内存优化,图片的优化方式有很多,我这里采取了最简单最直接得方式,使用了开源的ImageLoader这个图片加载框架,这个框架简直是太优秀了,减少了开发者一系列不必要而且时常会出现的麻烦,关于ImageLoader并不是本篇博文需要讲解的知识,关于ImageLoader,欢迎在GitHub主页上下载,地址是https://github.com/nostra13/Android-Universal-Image-Loader,既然使用了ImageLoader这个框架,就不得不在程序上做一些初始化的操作,首先需要自定义一个全局的上下文Application类,将ImageLoader的相关属性初始化上去,直接看代码好了,见名知意:MyApplication.java

    public class MyApplication extends Application {

    @Override

    public void onCreate() {

    super.onCreate();

    DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() //

    .showImageForEmptyUri(R.drawable.ic_launcher) //

    .showImageOnFail(R.drawable.ic_launcher) //

    .cacheInMemory(true) //

    .cacheOnDisk(true) //

    .build();//

    ImageLoaderConfiguration config = new ImageLoaderConfiguration//

    .Builder(getApplicationContext())//

    .defaultDisplayImageOptions(defaultOptions)//

    .discCacheSize(50 * 1024 * 1024)//

    .discCacheFileCount(100)// 缓存一百张图片

    .writeDebugLogs()//

    .build();//

    ImageLoader.getInstance().init(config);

    }

    }

    定义这个Application之后,需要在清单文件中配置一下,在Manifest.xml中的Application节点上添加:

    android:name="com.example.imagedemo.MyApplication"        此外由于ImageLoader是网络获取图片,又需要本地sdcard缓存图片,所以需要加上一下的权限,这是Imageloader标准权限:

    再看看上面的Item上数据,里面有个GridView,显然这个GridView也是需要做数据适配的,这个数据反应的是从网络加载图片,比较简单,看代码NoScrollGridAdapter.java

    ......

    Override

    public View getView(int position, View convertView, ViewGroup parent) {

    View view = View.inflate(ctx, R.layout.item_gridview, null);

    ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);

    DisplayImageOptions options = new DisplayImageOptions.Builder()//

    .cacheInMemory(true)//

    .cacheOnDisk(true)//

    .bitmapConfig(Config.RGB_565)//

    .build();

    ImageLoader.getInstance().displayImage(imageUrls.get(position),

    imageView, options);

    return view;

    }

    ......

    这样,所有的数据适配就做好了,接下来就需要做图片查看器了,当我们点击ListView上Item里的“九宫格”——NoScrollGridView的某张图片的时候,需要把这个图片的url传给一个图片查看器,图片查看器里会根据传递进来的url去网络加载这张图片,那么其实图片查看器就是一个新的单独的Activity,这个Activity会包含一个ViewPager,用来管理多张图片的查看。image_detail_pager.xml

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

    android:id="@+id/pager"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@android:color/black" />

    android:id="@+id/indicator"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_gravity="bottom"

    android:background="@android:color/transparent"

    android:gravity="center"

    android:text="@string/viewpager_indicator"

    android:textColor="@android:color/white"

    android:textSize="18sp" />

    HackyViewPager.java

    public class HackyViewPager extends ViewPager {

    private static final String TAG = "HackyViewPager";

    public HackyViewPager(Context context) {

    super(context);

    }

    public HackyViewPager(Context context, AttributeSet attrs) {

    super(context, attrs);

    }

    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

    try {

    return super.onInterceptTouchEvent(ev);

    } catch (IllegalArgumentException e) {

    // 不理会

    Log.e(TAG, "hacky viewpager error1");

    return false;

    } catch (ArrayIndexOutOfBoundsException e) {

    // 不理会

    Log.e(TAG, "hacky viewpager error2");

    return false;

    }

    }

    }

    ImagePagerActivity.java

    /**

    * 图片查看器

    */

    public class ImagePagerActivity extends FragmentActivity {

    private static final String STATE_POSITION = "STATE_POSITION";

    public static final String EXTRA_IMAGE_INDEX = "image_index";

    public static final String EXTRA_IMAGE_URLS = "image_urls";

    private HackyViewPager mPager;

    private int pagerPosition;

    private TextView indicator;

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.image_detail_pager);

    pagerPosition = getIntent().getIntExtra(EXTRA_IMAGE_INDEX, 0);

    ArrayList urls = getIntent().getStringArrayListExtra(

    EXTRA_IMAGE_URLS);

    mPager = (HackyViewPager) findViewById(R.id.pager);

    ImagePagerAdapter mAdapter = new ImagePagerAdapter(

    getSupportFragmentManager(), urls);

    mPager.setAdapter(mAdapter);

    indicator = (TextView) findViewById(R.id.indicator);

    CharSequence text = getString(R.string.viewpager_indicator, 1, mPager

    .getAdapter().getCount());

    indicator.setText(text);

    // 更新下标

    mPager.setOnPageChangeListener(new OnPageChangeListener() {

    @Override

    public void onPageScrollStateChanged(int arg0) {

    }

    @Override

    public void onPageScrolled(int arg0, float arg1, int arg2) {

    }

    @Override

    public void onPageSelected(int arg0) {

    CharSequence text = getString(R.string.viewpager_indicator,

    arg0 + 1, mPager.getAdapter().getCount());

    indicator.setText(text);

    }

    });

    if (savedInstanceState != null) {

    pagerPosition = savedInstanceState.getInt(STATE_POSITION);

    }

    mPager.setCurrentItem(pagerPosition);

    }

    @Override

    public void onSaveInstanceState(Bundle outState) {

    outState.putInt(STATE_POSITION, mPager.getCurrentItem());

    }

    private class ImagePagerAdapter extends FragmentStatePagerAdapter {

    public ArrayList fileList;

    public ImagePagerAdapter(FragmentManager fm, ArrayList fileList) {

    super(fm);

    this.fileList = fileList;

    }

    @Override

    public int getCount() {

    return fileList == null ? 0 : fileList.size();

    }

    @Override

    public Fragment getItem(int position) {

    String url = fileList.get(position);

    return ImageDetailFragment.newInstance(url);

    }

    }

    }

    已知图片查看的界面是继承自FragmentActivity的,所以支持显示的界面必须需要Fragment来实现,那么就自定义个Frangment吧,用这个Fragment来从url中获取图片资源,显示图片。image_detail_fragment.xml

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@android:color/black" >

    android:id="@+id/image"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:adjustViewBounds="true"

    android:contentDescription="@string/app_name"

    android:scaleType="centerCrop" />

    android:id="@+id/loading"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_gravity="center"

    android:visibility="gone" />

    ImageDetailFragment.java

    /**

    * 单张图片显示Fragment

    */

    public class ImageDetailFragment extends Fragment {

    private String mImageUrl;

    private ImageView mImageView;

    private ProgressBar progressBar;

    private PhotoViewAttacher mAttacher;

    public static ImageDetailFragment newInstance(String imageUrl) {

    final ImageDetailFragment f = new ImageDetailFragment();

    final Bundle args = new Bundle();

    args.putString("url", imageUrl);

    f.setArguments(args);

    return f;

    }

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    mImageUrl = getArguments() != null ? getArguments().getString("url")

    : null;

    }

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

    Bundle savedInstanceState) {

    final View v = inflater.inflate(R.layout.image_detail_fragment,

    container, false);

    mImageView = (ImageView) v.findViewById(R.id.image);

    mAttacher = new PhotoViewAttacher(mImageView);

    mAttacher.setOnPhotoTapListener(new OnPhotoTapListener() {

    @Override

    public void onPhotoTap(View arg0, float arg1, float arg2) {

    getActivity().finish();

    }

    });

    progressBar = (ProgressBar) v.findViewById(R.id.loading);

    return v;

    }

    @Override

    public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    ImageLoader.getInstance().displayImage(mImageUrl, mImageView,

    new SimpleImageLoadingListener() {

    @Override

    public void onLoadingStarted(String imageUri, View view) {

    progressBar.setVisibility(View.VISIBLE);

    }

    @Override

    public void onLoadingFailed(String imageUri, View view,

    FailReason failReason) {

    String message = null;

    switch (failReason.getType()) {

    case IO_ERROR:

    message = "下载错误";

    break;

    case DECODING_ERROR:

    message = "图片无法显示";

    break;

    case NETWORK_DENIED:

    message = "网络有问题,无法下载";

    break;

    case OUT_OF_MEMORY:

    message = "图片太大无法显示";

    break;

    case UNKNOWN:

    message = "未知的错误";

    break;

    }

    Toast.makeText(getActivity(), message,

    Toast.LENGTH_SHORT).show();

    progressBar.setVisibility(View.GONE);

    }

    @Override

    public void onLoadingComplete(String imageUri, View view,

    Bitmap loadedImage) {

    progressBar.setVisibility(View.GONE);

    mAttacher.update();

    }

    });

    }

    }

    写到这里,此篇博文也宣告结束了。需要提出的是,我这里的图片查看器实现的图片的缩放效果使用的是开源组件PhotoView,关于PhotoView的github项目地址在这里,https://github.com/chrisbanes/PhotoView需要点进去这个项目的网址,去下载源码,将源码全部拷贝到项目中来,使用也是相当方便的,demo如下:

    ImageView mImageView;

    PhotoViewAttacher mAttacher;

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    // Any implementation of ImageView can be used!

    mImageView = (ImageView) findViewById(R.id.iv_photo);

    // Set the Drawable displayed

    Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);

    mImageView.setImageDrawable(bitmap);

    // Attach a PhotoViewAttacher, which takes care of all of the zooming functionality.

    mAttacher = new PhotoViewAttacher(mImageView);

    }

    // If you later call mImageView.setImageDrawable/setImageBitmap/setImageResource/etc then you just need to call

    attacher.update();

    刚开始这个图片查看器是我自己自定义View来实现的,其实需要实现图片的手势识别+多点触控+缩放,是可以使用矩阵Matrix来实现的,只不过这样显得特别的麻烦不说,而且极易出现BUG,这对于某些“急功近利”的项目来说,是个不好的兆头。所以,我这里摒弃了我用Matrix自定义的效果,改用github大牛为我们写好的开源组件,这样效率就上去了,大家也可以用Matrix自己去实现一下图片的多点触摸缩放的效果,关于Matrix的学习,请参加我以前的博文,Android自定义控件——3D画廊和图像矩阵。其实关于android上的图片缩放真没什么其它的方式,唯一能使用的还是Matrix这个类,不信先来瞧瞧Github大牛写的开源组件PhotoView是怎么实现的,查看以下部分源码:

    // These are set so we don't keep allocating them on the heap

    private final Matrix mBaseMatrix = new Matrix();

    private final Matrix mDrawMatrix = new Matrix();

    private final Matrix mSuppMatrix = new Matrix();

    private final RectF mDisplayRect = new RectF();

    private final float[] mMatrixValues = new float[9];

    /**

    * Set's the ImageView's ScaleType to Matrix.

    */

    private static void setImageViewScaleTypeMatrix(ImageView imageView) {

    /**

    * PhotoView sets it's own ScaleType to Matrix, then diverts all calls

    * setScaleType to this.setScaleType automatically.

    */

    if (null != imageView && !(imageView instanceof IPhotoView)) {

    if (!ScaleType.MATRIX.equals(imageView.getScaleType())) {

    imageView.setScaleType(ScaleType.MATRIX);

    }

    }

    }

    以上只是PhotoView的部分源码,一目了然的发现它的实现也是基于Matrix的,时间与篇幅的局限性,大家需要更好的了解PhotoView的实现的话,就下载它的源码查看吧,要理解大神的想法是需要一些扎实的基础,关于PhotoView的具体实现细节,我也弄不太明白,可能是我对Matrix了解的不深刻吧,希望以后加强学习,也希望以后跟你们交流学习,共同进步!

    展开全文
  • 项目上线由于图片各异,最近会偶尔出现分享到朋友时候根本就打不开share的界面,但是到微信聊天是可以;下面贴出先前的代码:Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.send_img);...
  • 仿微信朋友发表图片拖拽和删除功能
  • 微信sdk暂未开放一次分享多张图片到朋友,但是有没有别的办法解决呢?显然是有的,不然我也不在这废话了。下面的代码亲测有效,轻轻松松分享多图:判断是否安装了微信代码if(!AppUtils.isInstalled...
  • 本文实例为大家分享了Android实现微信朋友圈图片和视频播放的具体代码,供大家参考,具体内容如下1.效果图:2.源码地址:链接3.参数控制,是否显示播放按钮holder.layout.setIsShowAll(mList.get(position)....
  • Circos图是在基因组相关的分析结果展示中非常常见的一类图型。由于Circos图中展示的信息量大,图形十分美观,很...在R语言中,RCircos这个软件包可以实现快速生成Circos图片。接下来,我们就来看看怎样用R来绘制图...
  • 如图所示,想要增加外显示每个模块的百分比分布,这个用R能做到吗?希望有大佬能帮忙解答,感谢!![图片说明](https://img-ask.csdn.net/upload/201712/31/1514726982_459593.png)
  • android7.0实现分享图片到朋友功能发布时间:2020-08-29 00:46:50来源:脚本之家阅读:132作者:十个雨点本文实例为大家分享了android实现分享图片到朋友功能的具体代码,供大家参考,具体内容如下在Android7.0...
  • 最新项目需求展示图片,在网上找了一,发现这个比较好用,和大家分享一下。但是还有个图片的点击滑动查看功能,等我找到后会在发布博客的 二、使用方法 1、核心类是NineGridLayout,继承自ViewGroup的抽象类,...
  • 1、true分享好友,false分享朋友 class ShareActivity : AppCompatActivity() { private val imageUris: ArrayList<Uri> = ArrayList() override fun onCreate(savedInstanceState: Bundle?) { ...
  • 一、该功能可以用recycleview实现,只是判断比较多 二、自定义view ...//每张图片的横向间距 int vSpace = Utils.dip2px(30);//每张图片的纵向间距 int childWidth = 0;//每张图片的宽度 int childHeight = 0;
  • 对android有点了解的人都知道在列表显示中我们可以使用GridLayoutManager这个布局可以轻松实现图片文字的一行显示的个数,所以在使用recyclerview渲染列表的时候我们就使用GridLayoutManager这个布局来代替以往的Li....
  • 探究微信朋友图片点击效果

    千次阅读 2017-04-25 10:19:09
    有段时间闲来没事的时候,想研究一下微信朋友图片点击效果,一开始的感觉是用跳转activity去实现。但是后面为了封装而好用。于是自己重新写了一个类,封装其它们。 我是准备用PopupWindow来做整体框架;简单来...
  • html代码(部分) <div class="w"> <div class="main"> <!--焦点图模块--> <div class="focus fl"> <a href="javascript:;" class="arrow-l">..." class="arrow-r".
  • Android 仿微信朋友9宫格图片展示&多选图片

    万次阅读 热门讨论 2016-03-31 14:50:44
    最近的一个项目中,有一个类似于朋友的小模块,发现里面有几个技术点网上记录的并不多,值得记录一下,于是把两个主要的功能给抽取成了一个Demo,分享给大家希望对大家有所帮助。
  • Android 仿微信朋友添加图片

    千次阅读 2018-05-09 22:31:00
    github地址(欢迎下载Demo)   ... 老习惯,先上图,着急用的朋友,直接带走Demo,先拿来用吧,毕竟老板催...仿微信添加图片.gif 1、首先这是用GridView实现的 &lt;?xml version="1.0" encodin...
  • 1.朋友listview适配器 import android.content.Context; import android.content.Intent; import android.nfc.Tag; import android.util.Log; import android.view.LayoutInflater; import android.view.View; ...
  • = null) { ImageView thumbView = itemView.findViewById(R.id.iamge_view); thumbView.getGlobalVisibleRect(bounds); } list.get(i).setBounds(bounds); // list.get(i).setUrl(list.get(i).getUrl()); } } 这个...
  • 本文为大家分享了类似微信朋友,点击+号图片,可以加图片功能,供大家参考,具体内容如下xml:xmlns:app=...
  • 页面长按生成图片,可分享至微信好友或者朋友 vue h5页面长按保存为图片,页面长按生成图片,可分享至微信好友或者朋友 qrcodejs2–Vue生成二维码,支持微信扫描 生成 整体图片: HTML格式 <div class="" v...
  • 首先上效果图上图功能具体思路是一个activity跳转,跳转到一个新的页面查看图片,中间加了一个缩放的过渡动画。 要实现这种,我们要先去掉activity的跳转动画startActivity(intent); //取消activity动画 ...
  • 模仿朋友分享图片

    2020-05-28 17:43:34
    今天学习了Android主要实现的是模仿朋友分享图片,接下来请欣赏一下我写的代码。 先来看看效果图,这是一个手机模拟器。 MainActivity 代码: public class MainActivity extends AppCompatActivity { ...
  • Android 高仿微信发朋友浏览图片效果

    万次阅读 多人点赞 2015-11-23 22:18:46
    最近一直在高仿微信、高仿微信,今天小编再给大家分享一个仿微信发朋友浏览图片的效果.... 好了,先看一下效果吧: 下面就来说一下具体怎么实现的:实现思路1.首先我们要获取数据源,数据源就是我们的每条说说...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,115
精华内容 13,646
关键字:

圈r图片