定义控件Android+简书,【Android群英传】——第三章:Android控件架构与自定义控件详解...

news/2024/7/3 1:53:12

之前学习了《Android群英传》,不过当时时间很零碎,很多问题没有深究、理解,趁着放假,认真回顾了之前的代码,同时解决了之前没有解决的问题,这里只是记录一下写Demo过程中遇到的问题及解决办法,具体笔记都在书上(感觉书上记录笔记方便一点),源代码放在我的GitHub

3.2 View的测量

重写onMeasure方法,这里自己调用setMeasuredDimension方法,就不需要将测量值传到super.onMeasure()中,在View里面去调用setMeasuredDimension方法

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));

}

测量长宽的模板代码

private int measureWidth(int measureSpec){

int result = 0;

int specMode = MeasureSpec.getMode(measureSpec);//得到测量模式

int specSize = MeasureSpec.getSize(measureSpec);//得到测量值

if (specMode == MeasureSpec.EXACTLY){

result = specSize;

}else{//若不为EXACTLY模式,则设置默认大小

result = 200;

if (specMode == MeasureSpec.AT_MOST){

result = Math.min(result,specSize);

}

}

return result;

}

3.6 自定义View

闪动的文字效果

这里继承TextView的时候,会报错,但是运行不会受影响

)布局:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center"

android:layout_below="@+id/myTopBar"

android:text="Android"

android:textSize="28sp"

android:layout_centerHorizontal="true"/>

2)代码:

8b3fd45ecc0d

闪动的文字效果

创建复合控件

1)布局:

android:id="@+id/myTopBar"

android:layout_width="wrap_content"

android:layout_height="40dp"

custom:leftBackground="@drawable/ic_launcher_background"

custom:leftText="Back"

custom:leftTextColor="#FFFFFF"

custom:rightBackground="@drawable/ic_launcher_background"

custom:rightText="More"

custom:rightTextColor="#FFFFFF"

custom:title="消息"

custom:titleTextColor1="#CA1212"

custom:titleTextSize="10sp"/>

2)代码:

8b3fd45ecc0d

创建复合控件

重写View来实现全新的控件

1)布局:

android:id="@+id/myCanvas"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_below="@+id/myTopBar"/>

2)代码:

8b3fd45ecc0d

重写View来实现全新的控件

音频条形图

1)布局:

android:id="@+id/myAudio"

android:layout_below="@+id/myTopBar"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

2)代码:

8b3fd45ecc0d

音频条形图

3.7 自定义ViewGroup

1)布局:

android:id="@+id/myViewGroup"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="fitXY"

android:src="@drawable/bg" />

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="fitXY"

android:src="@drawable/bg2" />

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="fitXY"

android:src="@drawable/bg3" />

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="fitXY"

android:src="@drawable/bg4" />

2)代码:

8b3fd45ecc0d

自定义ViewGroup

child.layout(l,i*mScreenHeight,r,(i+1)*mScreenHeight);写这个方法时,第二个参数我没有写i*,导致界面无法显示

@Override

public void onLayout(boolean changed,int l,int t,int r,int b){

int childCount = getChildCount();

Log.d(TAG, "onLayout: childCount: "+childCount);//有n个子view

//设置ViewGroup的高度

MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();

mlp.height = mScreenHeight*childCount;

Log.d(TAG, "onLayout: mScreenHeight: "+mScreenHeight);

setLayoutParams(mlp);

//将子view放到viewGroup中

for (int i = 0; i < childCount; i++) {

View child = getChildAt(i);

if (child.getVisibility() != View.GONE){

//ViewGroup在执行Layout的过程中,通过遍历来调用View的Layout方法,并传入参数确定其位置

child.layout(l,i*mScreenHeight,r,(i+1)*mScreenHeight);

}

}

}

在onTouchEvent()方法中,在case MotionEvent.ACTION_MOVE:分支上,书上写的是if(getScaleY()>getHeight()-mScreenHeight)判断为>,但是实际应该为

//实现ViewGroup的触控事件和滑动事件

@Override

public boolean onTouchEvent(MotionEvent event){

int y = (int) event.getY();

switch (event.getAction()){

case MotionEvent.ACTION_DOWN:

mLastY = y;

mStart = getScrollY();//手指起始位置

break;

case MotionEvent.ACTION_MOVE:

if(!mScroller.isFinished()){

mScroller.abortAnimation();

}

int dy = mLastY-y;

if(getScrollY()<0){

dy = 0;

}

//之前得判断为getScaleY()>getHeight()-mScreenHeight

//这段代码加上后,向下滑,不能滑动,因为getScaleY()方法返回为1

//getHeight()方法返回大于2621,mScreenHeight=2621

//所以这个判断恒为真

//所以我觉得是getScaleY()

if(getScaleY()

dy = 0;

}

scrollBy(0,dy);//手指滑动时让viewGroup的所有子view跟着滑动 dy 距离

mLastY = y;

break;

case MotionEvent.ACTION_UP:

mEnd = getScrollY();//记录触摸终点

// int dScrollY = (int) (mEnd - mStart);//得到手指滑动距离

int dScrollY = checkAlignment();

if (dScrollY>0) {

if (dScrollY

mScroller.startScroll(0, (int) getScrollY(),0,-dScrollY);//回到原来的位置

}else{//若超过一定距离

mScroller.startScroll(0, (int) getScrollY(),0,mScreenHeight-dScrollY);//使用Scroller类平滑到下一个子view

}

}else{

if(-dScrollY

mScroller.startScroll(0, (int) getScrollY(),0,-dScrollY);

}else{

mScroller.startScroll(0, (int) getScrollY(),0,-mScreenHeight-dScrollY);

}

}

break;

}

postInvalidate();

return true;//将继续向上传递审核

}

在case MotionEvent.ACTION_UP:分支上,我把getScrollY()方法,写成了getScaleY()方法,导致返回的结果始终为1(因为getScaleY()方法返回的是缩放值,但是我没有对他进行缩放操作,所以返回的缩放值始终是100%,即1),getScrollY()是返回视图的滚动顶部位置,是值位于[0,mScreenHeight]的。

case MotionEvent.ACTION_UP:

mEnd = getScrollY();//记录触摸终点

// int dScrollY = (int) (mEnd - mStart);//得到手指滑动距离

int dScrollY = checkAlignment();

if (dScrollY>0) {

if (dScrollY

mScroller.startScroll(0, (int) getScrollY(),0,-dScrollY);//回到原来的位置

}else{//若超过一定距离

mScroller.startScroll(0, (int) getScrollY(),0,mScreenHeight-dScrollY);//使用Scroller类平滑到下一个子view

}

}else{

if(-dScrollY

mScroller.startScroll(0, (int) getScrollY(),0,-dScrollY);

}else{

mScroller.startScroll(0, (int) getScrollY(),0,-mScreenHeight-dScrollY);

}

}

break;

源代码放在我的GitHub上


http://www.niftyadmin.cn/n/3567789.html

相关文章

android工程构建工具,如何升级Android Studio 2.3以构建工具25以修复“SDK Build Tools修订版(21.1.2)对于项目来说太低了所需的最低要求是25.0.0”...

参见英文答案 >Error:The SDK Build Tools revision (23.0.3) is too low for project ‘:app’. Minimum required is 25.0.0 7个我应该在哪些配置变量和值中设置升级到Build Tools 25.0.2的位置&#xff1f;在Android Studio消息之后,…

20210709 goto语句 猜数字 99乘法表

#include<stdio.h> #include<math.h> #include<string.h> int main() { //shutdown -s -t 60 关机指令shutdown,-s:设置 -t时间 60s //shutdown -a 取消关机指令 char input[20] { 0 }; system("shutdown -s -t 60"); while…

c三子棋主程序

#define _CRT_SECURE_NO_WARNINGS 1 //三子棋 #include"game.h" void menu() { printf("**********************\n"); printf("**** *1.play *******\n"); printf("**** *0.exit *******\n"); printf("*****…

linux调用jar路径问题与解决

为什么80%的码农都做不了架构师&#xff1f;>>> 直接写jar&#xff0c;报错找不到&#xff0c;必须写完整路径 /usr/local/java/jdk1.8.0_144/bin/jar -xvf /MemberSheep/shpcoin180829/Shpcoin.war java -version能打印出来为啥jar不行呢 # java -version java ve…

android调用本地js文件上传,js 通过 jszip、JSZipUtils实现本地上传zip文件或者远程zip文件解压并获取文件中的内容...

测试&#xff1a;1、html中引入js库2、拉取文件并解压的方法function getRomoteZipFile(){return new Promise(function(resolve, reject) {// step1 请求文件JSZipUtils.getBinaryContent("http://**/***.zip", function(err, data) {if (err) {reject(err);} else …

android多个音频文件上传,在单个目录中存储多个音频文件 - Android

我正在尝试构建一个android录音机应用程序&#xff0c;其中的音频录制内容应存储在我的手机内部存储器中的目录中。在单个目录中存储多个音频文件 - Android这是我在Android的Studio代码&#xff1a;File AudioDirnew File("/sdcard/Audiofiles/");AudioDir.mkdir();…

c。三子棋(japplet)头文件

#define _CRT_SECURE_NO_WARNINGS 1 #define ROW 3 #define COL 3 #include<stdio.h> #include<stdlib.h> #include<time.h> //声明 //棋盘初始化 void InitBoard(char board[ROW][COL], int row, int col); //打印棋盘 void DisplayBoard(char board[ROW]…

VMware虚拟机从一台电脑转移复制到另一台电脑的方法

2019独角兽企业重金招聘Python工程师标准>>> VMware虚拟机安装的目的主要是用来学习和测试&#xff0c;VMware虚拟机系统文件是可以转移复制的&#xff0c;把.vmx文件和所有的.vmdk文件全部拷贝即可。 这里简单解释下这个文件&#xff0c;vmx是虚拟系统配置文件&…