热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:Android自定义控件

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android自定义控件相关的知识,希望对你有一定的参考价值。我们在开发

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android自定义控件相关的知识,希望对你有一定的参考价值。



我们在开发的过程中,有时会遇到一些android系统自带的控件解决不了我们的需求,比如说我们在开发项目时显示的图片轮播,当我们展示的时候不希望图片变形,还要保证图片能够完整的显示出来,我们如何做呢?如果只是一个简单的ImageView控件恐怕很难实现吧!有人会说ImageView的ScaleType属性就能够解决图片填充不满的问题,但是那样的话图片很容易失真,达不到产品原先的需求。首先我们来认识一下ImageView的ScaleType属性的一些值。当我们查看ImageView的ScaleType的源码时会发现ScaleType的一些枚举值,也就是我们所用的属性值

public static enum ScaleType {
CENTER,
CENTER_CROP,
CENTER_INSIDE,
FIT_CENTER,
FIT_END,
FIT_START,
FIT_XY,
MATRIX;
private ScaleType() {
}
}

那么我们就按照枚举值的顺序来认识一下这些值如何使用。
android:scaleType=”center”
center就是居中,按图片的原来大小居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示,目的是让图片居中。
android:scaleType=”centerCrop”
这个就是缩放图片的一种,它的作用就是让图片等比例缩放,但是唯一美中不足的就是这个图片的缩放会对图片造成一定的裁剪(当设置的View的宽高和图片的宽高比例不同的时候)。图片依旧是居中显示
android:scaleType=”centerInside”
将图片的内容完整居中显示,通过按比例缩小或原来的大小使得图片长/宽等于或小于View的长/宽
android:scaleType=”fitCenter”
把图片按比例扩大/缩小到View的宽度,居中显示
android:scaleType=”fitEnd”
把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
android:scaleType=”fitStart”
把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
android:scaleType=”fitXY”
把图片不按比例扩大/缩小到跟View的大小一致,这一种也是最容易产生图片失真的
android:scaleType=”matrix”
用矩阵来绘制,动态缩小放大图片来显示
以上效果图如下
这里写图片描述
介绍了上面的ScaleType以后下面就开始进入我们的正题,上面的属性值恐怕有时候是满足不了我们的需求吧,多多少少还是达不到图片既不失真又要等比例显示的效果吧。有人会说,我可以根据图片的宽高然后设置控件的宽高啊,这一种是可以解决图片的失真和等比例显示的效果,你直接用
`android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
这样不是更好吗?但是你想想这样的话图片会达到轮播图的图片效果吗?轮播图的图片一般是宽度填充整个屏幕的,但是高度怎么办呢?有人说我可以根据自己手机的屏幕宽度/图片的宽度得到的比值去乘以图片的高度得到的值设置为控件的高度就可以解决了。但是这又有一个问题,你这样的话你的手机屏幕显示的是非常完美的,但是如果到其它手机你能确保也一样吗?恐怕不行吧!那么我们如何解决呢?我们如果想要完美的显示在所有的手机上面就需要自定义一个控件了。
Android自定义控件需要一些自定义的属性,我们需要在app\\src\\main\\res\\values下新建一个xml文件名字为attrs也就是属性文件,在文件里面我们要使用declare-styleable来声明一个我们自己的格式的一些属性


<resources>
<declare-styleable name&#61;"CustomLayout">
<attr name&#61;"test" format&#61;"string">attr>
declare-styleable>
resources>

其中declare-styleable name&#61;”CustomLayout”里面的name值最好跟我们自定义控件名相同&#xff0c;name&#61;”test” format&#61;”string”&#xff0c;name是根据自己的习惯来定但是要做到见名知意&#xff0c;就像layout_width让人一看就知道就布局的宽一样。format就是数据的格式&#xff0c;它有string 、float、boolean、color、dimension、enum、flag、fraction、integer、reference这10种格式&#xff0c;本次只用到float这种格式。因为要实现图片等比例缩放需要用到一个比例内容如下


<resources>
<declare-styleable name&#61;"CustomLayout">
<attr name&#61;"ratio" format&#61;"float">attr>
declare-styleable>
resources>

自定义控件的时候需要重写onMeasure方法&#xff0c;onMeasure是用来计算控件的宽高的&#xff0c;当我们知道控件的宽度或高度想要根据比例设置高度或宽度的时候&#xff0c;就需要在此方法中进行测量计算。在onMeasure方法中&#xff0c;我们会看到两个参数onMeasure(int widthMeasureSpec, int heightMeasureSpec)&#xff0c;onMeasure传入的两个参数是由上一层控件传入的大小&#xff0c;有多种情况&#xff0c;重写该方法时需要对计算控件的实际大小&#xff0c;然后调用setMeasuredDimension(int, int)设置实际大小。widthMeasureSpec其实就是width的宽度值与宽度的模式&#xff0c;说到模式大家都应该很熟悉的&#xff0c;有三种模式分别是&#xff1a;MeasureSpec.AT_MOST、MeasureSpec.EXACTLY、MeasureSpec.UNSPECIFIED。当模式为MeasureSpec.AT_MOST时则意味着控件大小一般随着控件的子空间或内容进行变化&#xff0c;此时控件尺寸只要不超过父控件允许的最大尺寸即可&#xff0c;我们经常使用的wrap_content就是这种模式。当模式为MeasureSpec.EXACTLY时&#xff0c;说明控件的大小为精确值&#xff0c;是我们已知的大小的时候可以设置此模式&#xff0c;我们经常使用的match_parent就是这种模式。当模式为MeasureSpec.UNSPECIFIED时&#xff0c;说明控件的大小不确定&#xff0c;控件的大小是可以随便变化的&#xff0c;我们通常使用的父控件为Adapter的就是通过传入的大小来确定的就是这种模式。那么widthMeasureSpec里面的值又是什么情况呢&#xff0c;下面是我打印的一个当控件的宽度为match_parent也就是模式为MeasureSpec.EXACTLY时的widthMeasureSpec的值

10-28 12:55:50.785 5350-5350/custom.lyxrobert.com.customcontrols I/System.out: widthMeasureSpec------>1073742904

那么1073742904是什么意思呢&#xff1f;
这里写图片描述

其中的10000111000‬转换成10进制就是1080也就是我的手机的屏宽&#xff0c;那么‭01000000000000000000010000111000‬前面的又是什么情况呢&#xff1f;

public static final int AT_MOST &#61; -2147483648;
public static final int EXACTLY &#61; 1073741824;
public static final int UNSPECIFIED &#61; 0;

1073741824的二进制则为‭01000000000000000000000000000000‬也就是01<<30其中01代表的是mode&#xff0c;看到这里相比大家也就知道怎么回事了吧。
那么我们就可以根据widthMeasureSpec来获取我们想要的宽度方法则是MeasureSpec.getSize(widthMeasureSpec)&#xff0c;高度也是如此不过传入的参数就是heightMeasureSpec。
如果我们知道宽度和高度也是不行的&#xff0c;如果用户想要给图片设置一定的padding值怎么办&#xff1f;比如说padding为10&#xff0c;那么图片的内边距都会为10&#xff0c;图片以前的比例就很难保持。所以我们为防止这种情况的发生还是通过获取相应的padding值来进行处理。图片的宽度则为int img_width&#61;width - getPaddingLeft() - getPaddingRight();通过宽度/计算出的图片的宽高比得到图片的高度int img_height &#61; (int) (imageWidth / ratio &#43; 0.5f);但是这样还是不行&#xff0c;因为图片宽度左右各减少10&#xff0c;而高度虽然也等比例缩小了&#xff0c;但是显示出来的效果恐怕只有图片的左右的间距与上下的会有不同的效果

图片没有设置padding时
图片没有设置padding时
图片设置padding为20dp时
图片设置padding为20dp时
我们发现图片的上下的边距并不是我们所设置的&#xff0c;那么如果达到这种效果呢&#xff0c;就是需要根据我们获取的img_height 的值再加上得到top和bottom的padding值height &#61; img_height &#43; getPaddingTop() &#43; getPaddingBottom();设置之后的图片显示为
这里写图片描述

package custom.lyxrobert.com.customcontrols;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* Created by ytx on 2016/10/28.
*/

public class CustomLayout extends FrameLayout {
private float ratio;
public CustomLayout(Context context) {
super(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta &#61; context.obtainStyledAttributes(attrs,R.styleable.CustomLayout);
ratio &#61; ta.getFloat(R.styleable.CustomLayout_rario, -1);
ta.recycle();
}
public CustomLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
&#64;Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width &#61; MeasureSpec.getSize(widthMeasureSpec);// 获取宽度值
int widthMode &#61; MeasureSpec.getMode(widthMeasureSpec);// 获取宽度模式
int height;
int heightMode &#61; MeasureSpec.getMode(heightMeasureSpec);// 获取高度模式
if (widthMode &#61;&#61; MeasureSpec.EXACTLY
&& heightMode !&#61; MeasureSpec.EXACTLY && ratio > 0) {
int img_width &#61; width - getPaddingLeft() - getPaddingRight();
int img_height &#61; (int) (img_width / ratio &#43; 0.5f);
height &#61; img_height &#43; getPaddingTop() &#43; getPaddingBottom();
heightMeasureSpec &#61; MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
}
// 按照最新的高度测量控件
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

布局文件为,如果想给给图片添加边距请在custom.lyxrobert.com.customcontrols.CustomLayout里面添加&#xff0c;不要在ImageView里面设置&#xff0c;否则将不会起作用&#xff0c;因为我们的计算是在CustomLayout里面的onMeasure方法里面实现的。lyxrobert:rario&#61;”1.7”里面的1.7是图片的宽和高的像素比


<LinearLayout xmlns:android&#61;"http://schemas.android.com/apk/res/android"
xmlns:lyxrobert&#61;"http://schemas.android.com/apk/res-auto"
android:layout_width&#61;"match_parent"
android:layout_height&#61;"match_parent"
android:orientation&#61;"vertical"
>

<custom.lyxrobert.com.customcontrols.CustomLayout
android:layout_width&#61;"match_parent"
android:layout_height&#61;"wrap_content"
lyxrobert:rario&#61;"1.7">

<ImageView
android:layout_width&#61;"match_parent"
android:layout_height&#61;"match_parent"
android:src&#61;"&#64;drawable/test"
/>

custom.lyxrobert.com.customcontrols.CustomLayout>
LinearLayout>

点击查看无限循环广告轮播图
点击免费下载源码
如有疑问请留言



推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
王欣纶淑玲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有