1、自定义View分类
1、自定义View
在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View;
2、自定义ViewGroup
自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,人多继承自ViewGroup或各种Layout;
2、自定义View的图
6df4334c5c4332bc10e6c4db0732332.png 78702912b20c0d41f59622014db4049.png所以,自定义View任督二脉就在于此:
自定义View主要是实现 onMeasure + onDraw
自定义ViewGroup主要是实现onMeasure + onLayout
3、View的层级
View的层级.png 自定义流程.png4、getMeasureWidth与getWidth的区别
21454b47aafa864a9361d28b28d02d4.png5、Android中两种坐标系
Android屏幕坐标系.png 视图坐标系.png6、MeasureSpec 是什么 ?
MeasureSpec是View中的内部类,基本都是二进制运算。由于int是32位的,用高两位表示mode,低30位表示size,MODE SHIFT = 30的作用是移位
-
UNSPECIFIED:
不对View大小做限制,系统使用 -
EXACTLY:
确切的大小,如: 100dp -
AT_MOST:
大小不可超过某数值,如: matchParent,最大不能超过你爸爸
7、为什么要measure ?
计算大小.png 举例说明.png8、Android中 lastLine怎么使用
lastLine是TextView中的一个属性,用于指定文本的最后一行的行号。它可以用来控制文本的显示方式,例如在最后一行添加省略号或者在最后一行显示特定的文本。在Android中,lastLine属性可以通过XML布局文件或者代码动态设置。
lastLine是TextView中的一个属性,用于指定TextView中最后一行的行号。可以通过以下方式使用:
1、在XML布局文件中设置:
<TextView
android:id="@+id/myTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:maxLines="3"
android:ellipsize="end"
android:lastLine="3" />
在这个例子中,我们设置了TextView的最大行数为3,当文本超过3行时,将使用省略号来表示。同时,我们将lastLine属性设置为3,表示最后一行的行号为3。
2、在Java代码中设置:
TextView myTextView = findViewById(R.id.myTextView);
myTextView.setLastLine(3);
这个例子中,我们通过findViewById方法获取了TextView的实例,并调用setLastLine方法将最后一行的行号设置为3。注意:lastLine属性只在TextView的maxLines属性设置为一个大于0的值时才有效。如果maxLines属性设置为0或者不设置,lastLine属性将不起作用。
9、Android visibleState使用
Android中的visibleState是一个状态列表,用于定义视图的可见性状态。它可以用于定义视图的不同状态,例如:可见、不可见、半透明等。
使用visibleState需要以下步骤:
1、在XML布局文件中定义状态列表:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_visible="true" android:alpha="1.0" />
<item android:state_visible="false" android:alpha="0.0" />
</selector>
在视图中设置状态列表:
<View
android:id="@+id/my_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/my_state_list" />
在代码中设置视图的可见性状态:
View myView = findViewById(R.id.my_view);
myView.setVisibility(View.VISIBLE); // 设置可见状态
myView.setVisibility(View.INVISIBLE); // 设置不可见状态
myView.setVisibility(View.GONE); // 设置隐藏状态
注意:在使用visibleState时,需要将视图的背景设置为状态列表。
10、Android flexBox Layout使用
地址:https://blog.csdn.net/weixin_39397471/article/details/90212231
11、自定义FlowLayout
258e112d537e3f2729c455ca6d18cf0.png2、FlowLayout :
package com.example.flowlayout;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class FlowLayout extends ViewGroup {
private static final String TAG = "FlowLayout";
private int mHorizontalSpacing = dp2px(16); //每个item横向间距
private int mVerticalSpacing = dp2px(8); //每个item横向间距
private List<List<View>> allLines = new ArrayList<>(); // 记录所有的行,一行一行的存储,用于layout
List<Integer> lineHeights = new ArrayList<>(); // 记录每一行的行高,用于layout
public FlowLayout(Context context) {
super(context);
// initMeasureParams();
}
//反射
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// initMeasureParams();
}
//主题style
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// initMeasureParams();
}
//四个参数 自定义属性
private void clearMeasureParams() {
allLines.clear();
lineHeights.clear();
}
//度量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
clearMeasureParams();//内存 抖动
//先度量孩子
int childCount = getChildCount();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int selfWidth = MeasureSpec.getSize(widthMeasureSpec); //ViewGroup解析的父亲给我的宽度
int selfHeight = MeasureSpec.getSize(heightMeasureSpec); // ViewGroup解析的父亲给我的高度
List<View> lineViews = new ArrayList<>(); //保存一行中的所有的view
int lineWidthUsed = 0; //记录这行已经使用了多宽的size
int lineHeight = 0; // 一行的行高
int parentNeededWidth = 0; // measure过程中,子View要求的父ViewGroup的宽
int parentNeededHeight = 0; // measure过程中,子View要求的父ViewGroup的高
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
LayoutParams childLP = childView.getLayoutParams();
if (childView.getVisibility() != View.GONE) {
//将layoutParams转变成为 measureSpec
int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight,
childLP.width);
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom,
childLP.height);
childView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
//获取子view的度量宽高
int childMesauredWidth = childView.getMeasuredWidth();
int childMeasuredHeight = childView.getMeasuredHeight();
//如果需要换行
if (childMesauredWidth + lineWidthUsed + mHorizontalSpacing > selfWidth) {
//一旦换行,我们就可以判断当前行需要的宽和高了,所以此时要记录下来
allLines.add(lineViews);
lineHeights.add(lineHeight);
parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);
lineViews = new ArrayList<>();
lineWidthUsed = 0;
lineHeight = 0;
}
// view 是分行layout的,所以要记录每一行有哪些view,这样可以方便layout布局
lineViews.add(childView);
//每行都会有自己的宽和高
lineWidthUsed = lineWidthUsed + childMesauredWidth + mHorizontalSpacing;
lineHeight = Math.max(lineHeight, childMeasuredHeight);
//处理最后一行数据
if (i == childCount - 1) {
allLines.add(lineViews);
lineHeights.add(lineHeight);
parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing;
parentNeededWidth = Math.max(parentNeededWidth, lineWidthUsed + mHorizontalSpacing);
}
}
}
//再度量自己,保存
//根据子View的度量结果,来重新度量自己ViewGroup
// 作为一个ViewGroup,它自己也是一个View,它的大小也需要根据它的父亲给它提供的宽高来度量
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int realWidth = (widthMode == MeasureSpec.EXACTLY) ? selfWidth: parentNeededWidth;
int realHeight = (heightMode == MeasureSpec.EXACTLY) ?selfHeight: parentNeededHeight;
setMeasuredDimension(realWidth, realHeight);
}
//布局
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int lineCount = allLines.size();
int curL = getPaddingLeft();
int curT = getPaddingTop();
for (int i = 0; i < lineCount; i++){
List<View> lineViews = allLines.get(i);
int lineHeight = lineHeights.get(i);
for (int j = 0; j < lineViews.size(); j++){
View view = lineViews.get(j);
int left = curL;
int top = curT;
// int right = left + view.getWidth();
// int bottom = top + view.getHeight();
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
view.layout(left,top,right,bottom);
curL = right + mHorizontalSpacing;
}
curT = curT + lineHeight + mVerticalSpacing;
curL = getPaddingLeft();
}
}
// @Override
// protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// }
public static int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
}
}
2、子布局:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="搜索历史"
android:textColor="@android:color/black"
android:textSize="18sp"/>
<com.example.flowlayout.FlowLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:layout_margin="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="水果味孕妇奶粉" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="儿童洗衣机" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="洗衣机全自动" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="小度" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="儿童汽车可坐人" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="抽真空收纳袋" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="儿童滑板车" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="稳压器 电容" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="羊奶粉" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="奶粉1段" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="图书勋章日" />
</com.example.flowlayout.FlowLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="搜索发现"
android:textColor="@android:color/black"
android:textSize="18sp" />
<com.example.flowlayout.FlowLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="惠氏3段" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="奶粉2段" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="图书勋章日" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="伯爵茶" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="阿迪5折秒杀" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="蓝胖子" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="婴儿洗衣机" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="小度在家" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="遥控车可坐" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="搬家袋" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="剪刀车" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="滑板车儿童" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="空调风扇" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="空鼓锤" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_button_circular"
android:text="笔记本电脑" />
</com.example.flowlayout.FlowLayout>
</LinearLayout>
</ScrollView>
网友评论