导航:首页 > 源码编译 > android的自定义控件源码

android的自定义控件源码

发布时间:2023-01-12 22:29:30

android自定义控件总结

每个view的坐标系原点为左上角那个点,水平方向为x轴,右正左负,竖直方向为y轴,下正上负。

canvas.drawColor //绘制区域涂上颜色(设置底色/蒙层)

canvas.drawCircle(float centerX(圆心X坐标),float centerY(圆心Y坐标),float radius(圆的半径,单位像素),Paint paint)

canvas.drawBitmap

canvas.drawRect(float left,float top,float right,float bottom,Paint paint) //画矩形

canvas.drawRect(RecF rect,Paint paint)

canvas.drawRect(Rect rect,Paint paint)

canvas.drawPoint(float x(点X轴坐标),float y(点Y轴坐标),Paint paint)//画点

点的大小 ->paint.setStrokeWidth(width)

点的形状 ->paint.setStrokeCap(cap)

ROUND(圆形),BUTT(平头),SQUARE(方头)

canvas.drawPoints()//批量画点

canvas.drawOval(float left(左边界点),float top(上边界点),float right(右边界点),float bottom(下边界点),Paint paint) //画椭圆

canvas.drawLine(float startX(起点X轴坐标),float startY(起点Y轴坐标),float stopX(终点X轴坐标),float stopY(终点X轴坐标),Paint paint) (setStyle对直线没有影响)

canvas.drawLines(批量画线)

canvas.drawRoundRect(float left,float top,float right,float bottom,float rx(圆角的横向半径),float ry(圆角的纵向坐标),Paint paint)//画圆角矩形

canvas.drawRoundRect(RectF rect,float rx, float ry,Paint paint)

canvas.drawArc(float left, float top, float right, float bottom, float startAngle(起始角度,顺时针为正,逆时针为负), float sweepAngle(弧形划过角度), boolean useCenter(是否连接到圆心), Paint paint) //绘制弧形或扇形 根据弧形所在椭圆进行绘制

canvas.drawPath() //通过描述路径的方式来绘制图形

path.addXxx() —添加子图形

path.addCircle(x,y,radius,dir(路径方向:顺时针/逆时针))

path.xxxTo —画线

path.lineTo()

path.rLineTo()

path.close() —封闭当前图形

path.setFillType(Path.FillType ft) //设置填充模式

canvas.drawBitmap(Bitmap bitmap,float left,float top,Paint paint);//画bitmap

canvas.drawBitmap(Bitmap bitmap,Rect src,RectF dst,Paint paint)

canvas.drawBitmap(Bitmap bitmap,Rect src,Rect dst,Paint paint)

canvas.drawBitmap(Bitmap bitmap,Matrix matrix,Paint paint)

canvas.drawText(String text,float x(起点x坐标),float y(起点y坐标),Paint paint) //绘制文字

Paint.setStyle //设置绘制模式

FILL 填充模式(默认)

STROKE 画线模式

FILL_AND_STROKE 既画线又填充

Paint.setStrokeWidth //设置线条宽度 (仅在style:Stroke、FILL_AND_STROLE下有效)

Paint.setTextSize //设置文字大小

Paint.setAntiAlias //设置抗锯齿开关

Paint.setTextSize(float textSize)//设置文字大小

Paint.setStrokeJoin(Paint.Join join) //设置拐角的形状

MITER//尖角(默认)

BEVEL//平角

ROUND//圆角

Paint.setStokeMiter(float miter)//设置MITER型拐角的延长线的最大值

设置颜色

直接设置颜色

Paint.setColor(int color)

Paint.setARGB(int a,int r,int g,int b)

Paint.setShader(Shader shader) //设置shader

LinearGradient 线性渐变

RadialGradient 辐射渐变

SweepGradient 扫描渐变

BitmapShader 用bitmap的像素来作为图形或文字的填充

ComposeShader 混合着色器,多个shader混合使用

Paint.setColorFilter(ColorFilter colorFilter) //设置颜色过滤

Paint.setXfermode(Xfermode xfermode) //以要绘制的内容为源图像,以View中已有内容作为目标图像,选取一个PorterDuff.Mode作为绘制内容的颜色处理方案。

色彩优化

Paint.setDither(boolean dither) //设置抖动来优化色彩深度降低时的绘制效果

Paint.setFilterBitmap(boolean filter) //设置双线性过滤优化Bitmap放大绘制的效果

可以理解为 由马赛克变成模糊状态

Paint.setPathEffect(PathEffect effect)//使用PathEffect设置形状的轮廓效果

CornerPathEffect//把所有的拐角变成圆角

DiscretePathEffect//把线条进行随机的偏离

DashPathEffect//使用虚线

PathDashPathEffect//使用一个Path来绘制虚线

SumPathEffect//组合效果

ComposePathEffect//组合效果,组合有先后顺序

Paint.setShadowLayer(float radius,float dx,float dy,int shadowColor)//添加阴影

Paint.setMaskFilter(MaskFilter maskfilter)//在绘制层上方的附加效果

BlurMaskFilter //模糊效果

new BlurMaskFilter(float radius(模糊范围),BlurMaskFilter.Blur style(模糊类型))

EmbossMaskFilter//浮雕效果

new EmbossMaskFilter(float[] direction(光源的方向),float ambient(环境光强度),float specular(炫光系数),float blurRadius(光线范围))

获取绘制的Path

getFillPath(Path src,Path dst)//实际path

getTextPath(Stirng text,int start,int end,float x,float y,Path)/getTextPath(char[] text,int index,int count,float x,float y,Path path)//文字的path

drawTextOnPath()//沿一条Path来绘制文字

StaticLayout //绘制文字,支持换行

paint.setFakeBoldText(booleab fakeBoldText)//是否使用伪粗体

paint.setStrikeThruText()//是否加删除线

paint.setUnderLineText(boolean underlineText)//是否加下划线

paint.setTextSkewX(float skewX)//设置文字横向错切角度

paint.setTextScaleX(float scaleX)//设置文字横向放缩

paint.setLetterSpacing(float letterSpacing)//设置字符间距,默认为0

paint.setTextAlign(Paint.Align align)//LEFT、CENTER、RIGHT默认为LEFT

paint.setTextLocale(Locale locale)/paint.setTextLocales(LocaleList locales) //设置绘制所用的地域

paint.setHinting(int mode)//是否启用字体微调

测量文字尺寸类:

paint.getFontSpacing();//获取推荐的行距

paint.getFontMetrics();//获取point的FontMetrics

baseline:基准线

ascent/descent:普通字符的顶部和底部范围

top/bottom:限制字型的顶部和底部

leading:行的额外间距,即上一行字的bottm与下一行字的top距离

paint.getTextBounds(String text(测量的文字),int start(文字的起始位置),int end(文字的结束位置),Rect bounds(文字显示范围的对象))//获取文字的显示范围

paint.measureText(String text)//测量文字占用的宽度

measureText()>getTextBounds()

paint.getTextWidths(String text,float[] widths)//获取字符串中每个字符的宽度,并把结果填入参数widths

paint.breakText(String text((要测量的文字),boolean measureForwards(测量的方向),float maxWidth(宽度上限(超出上限会截断文字)),float[] measuredWidth(用于接受数据))//测量完成后会把文字宽度赋给measureWidth[0]

paint.getRunAdvance(CharSequence text,int start(文字的起始坐标),int end(文字的结束坐标),int contextStart(上下文的起始坐标),int ContextEnd(上下文的结束坐标),boolean isRtl(文字的方向),int offset(字数的偏移))//计算某个字符处光标的x坐标

paint.getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)//计算出文字中最接近这个位置的字符偏移量

paint.hasGlyph(String s)//检查指定的字符串是否是一个单独的字型

canvas.clipRect()//范围裁剪

canvas.clipPath()//根据范围裁剪

canvas.translate(float dx,float dy)//位移

canvas.rotate(float degrees,float px,float py)//旋转

canvas.scale(float sx(横向缩放倍数),float sy(纵向缩放倍数),float px,float py)//缩放

canvas.skew(float sx(x轴的错切系数),float sy(y轴的错切系数))//错切

canvas.setMatrix(matrix)//用Matrix直接替换Canvas当前的变换矩阵

canvas.concat(matrix)//用Canvas当前的变换矩阵和Matrix相乘

Camera.rotate*()//三维旋转

1、super.draw()//总调度方法

2、super.onDraw()

3、dispatchDraw()//绘制子View的方法

绘制顺序:

draw()总调度方法,view的绘制过程都发生在draw()方法里

1、背景(drawBackground()不能重写)-------android:background:/View.setBackgroundXxx()

2、主体(onDraw())

3、子View(dispatchDraw())

4、滑动边缘渐变和滑动条(onDrawForeground())-------android:scrollbarXxx/View.setXXXScrollBarXXX()

5、前景(onDrawForeground())-------android:foreground/View.setForeground()

view.animate().translationX()//x轴偏移

1、如果是自定义控件,需要添加setter、getter方法

2、ObjectAnimator.ofXXX()创建ObjectAnimator对象

3、用start()方法执行动画

setDuration(int ration)//设置动画时长

setInterpolator(Interpolator interpolator)//设置插值器

ViewPropertyAnimator.setListener()/ObjectAnimator.addListener()

ViewPropertyAnimator.setUpdateListener()/ObjectAnimator.addUpdateListener()

ObjectAnimator.addPauseListener()

ViewPropertyAnimator.withStartAction/EndAction()

ArgbEvaluator//颜色渐变动画

PropertyValuesHolder//同一个动画中改变多个属性

PropertyValuesHolders.ofKeyframe()//把同一个属性拆分

AnimatorSet//多个动画配合执行

targetSdkVersion>=14,硬件加速默认开启

view.setLayerType()

LAYER_TYPE_SOFTWARE:使用软件来绘制View Layer,绘制到Bitmap,并顺便关闭硬件加速

LAYER_TYPE_HARDWARE:使用GPU来绘制View Layer,绘制到OpenGL texture(如果硬件加速关闭,那么行为和LAYER_TYPE_SOFTWARE一致)

LAYER_TYPE_NONE:关闭View Layer

View Layer可以加速无invalidate()(例如动画)时的刷新效率,但对于需要调用invalidate()的刷新无法加速

硬件加速并不支持所有的绘制操作

1、测量(measure)

View:View在onMeasuer中会计算自己的尺寸然后保存

ViewGroup:ViewGroup在onMeasure中会调用所有子View的measure让它们进行自我测量,并根据子View

计算出的期望尺寸来计算他们的事迹尺寸和位置然后保存。

2、布局(layout)

View:无子View所以onLayout不做任何处理

ViewGroup:ViewGroup在onLayout中会调用自己所有子View的layout方法,把他们的尺寸、位置传给他们, 让他们完成自我布局。

MeasureSpec = mode + size :父类传递过来给当前View的一个建议值

MeasureSpec.getMode(int spec)//获取模式

MeasureSpec.getSize(int spec)//获取数值

限制分类:

UNSPECIFIED(不限制)

AT_MOST(限制上限)->wrap_content

EXACTLY(限制固定值)->match_parent/具体值

1、重写onMeasure来修改已有的View尺寸

(1)、重写onMeasure方法,调用super.onMeasure触发原有的自我测量。

(2)、在super.onMeasure下用getMeasureWidth与getMeasureHeigh获取之前测量的结果,使用自己的算法计算新结果。

(3)、调用setMeasureDimension保存新结果。

2、重写onMeasure来全新定制自定义View的尺寸

与1区别,保证计算的同时,保证结果满足父View给出的尺寸限制

(1)重写onMeasure,计算出View的尺寸

(2)使用resolve让子View的计算结果符合父View的限制,也可不使用该方法自己定义

3、重写onMeasure和onLayout来全新定制自定义ViewGroup的内部布局

两个注意点:

子控件间的margin值

1、重写generateLayoutParams()和generateDefaultLayoutParams()

2、获取margin值 MarginLayoutParams lp = (MarginLayoutParams )child.getLayoutParams()

子控件间的padding值

1、测量后直接getPaddingLeft、getPaddingTop、getPaddingRight、getPaddingBottom

重写onMeasure来计算内部布局

(1)调用每个子View的measure来计算子View的尺寸

结合layout_xxx和自己可用空间

(2)计算子View的位置并保存子View的尺寸和位置

(3)计算自己的尺寸并用setMeasureDimension保存

重写onLayout来摆放子View

(1)调用每个子View的layout,让他们保存自己的位置和尺寸

view工作原理

触摸事件

1、ACTION_DOWN:手指刚接触屏幕,按下去的那一瞬间

2、ACTION_MOVE:手指在屏幕上移动

3、ACTION_UP:手指从屏幕上松开的瞬间

事件序列:从ACTION_DOWN -> ACTION_UP

ViewGroup:
DispatchTouchEvent
• return true:表示该View内部消化掉了所有事件
• return false:表示事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费
• return super.dispatchTouchEvent(ev):默认事件将分发给本层的事件拦截onInterceptTouchEvent方法 进行处理
OnInterceptTouchEvent
• return true:表示将事件进行拦截,并将拦截到的事件交由本层控件的onTouchEvent进行处理
• return false:表示不对事件进行拦截,事件得以成功分发到子View
• return super.onInterceptTouchEvent(ev):默认表示不拦截该事件,并将事件传递给下一层View的 dispatchTouchEvent
OnTouchEvent 默认false
• return true:表示onTouchEvent处理完事件后消费了此次事件
• return fasle:表示不响应事件,那么该事件将会不断向上层View的onTouchEvent方法传递,直到某个View的 onTouchEvent方法返回true
• return super.dispatchTouchEvent(ev):表示不响应事件,结果与return false一样
子View不存在分发:
• DispatchTouchEvent 事件分发
• OnTouchEvent 默认true

如下图为事件分发流程图:

---------------------- 以上总结部分源自Hencoder教程 ------------------------------

❷ Android 红包雨效果自定义控件

思路:利用Path绘制动画轨迹,再使用PathMeasure获取轨迹中的坐标位置实时改变view的坐标完成红包动画。

封装一个红包容器view用于管理大量红包view的显示、动画、消失、回收利用

单个红包view动画轨迹设置

适配器:用于定义红包view的样式、轨迹路线、动画属性、数据

使用方式,在布局中添加view

在界面中定义适配器,添加红包数据

源码地址: https://github.com/LucasDevelop/CustomView 。中的(Falling)部分

❸ 如何打造Android自定义的下拉列表框控件

一、概述
Android中的有个原生的下拉列表控件Spinner,但是这个控件有时候不符合我们自己的要求,
比如有时候我们需要类似windows 或者web网页中常见的那种下拉列表控件,类似下图这样的:

这个时候只有自己动手写一个了。其实实现起来不算很难,
本文实现的方案是采用TextView +ImageView+PopupWindow的组合方案。
先来看看我们的自己写的控件效果图吧:(源码在文章下面最后给出哈!)

二、自定义下拉列表框控件的实现
1. 自定义控件用到的布局文件和资源:
结果框的布局页面:dropdownlist_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/compound"
android:background="@drawable/dropdown_bg_selector" >

<TextView
android:id="@+id/text"
android:layout_width="250dp"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:text="文本文字"
android:gravity="center_vertical"
android:textSize="14sp"
android:padding="5dp"
android:singleLine="true" />
<ImageView
android:id="@+id/btn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_toRightOf="@+id/text"
android:src="@drawable/dropdown"
android:padding="5dp"
android:layout_centerVertical="true"
android:gravity="center"/>
</RelativeLayout>

下拉弹窗列表布局页面:dropdownlist_popupwindow.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<ListView
android:id="@+id/listView"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:divider="#666666"
android:dividerHeight="1dp"
></ListView>

</LinearLayout>

selector资源文件:
dropdown_list_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/dropdownlist_item_press"/>
<item android:drawable="@color/dropdownlist_item"/>
</selector>

dropdown_bg_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/dropdownlist_press"/>
<item android:drawable="@color/dropdownlist_bg"/>
</selector>

2. 自定义下拉列表框控件类的实现:
我们采用了TextView+ImageView+PopupWindow的组合方案,所以我的自定义控件需要重写ViewGroup,由于我们已经知道了,布局方向为竖直方向,所以这里,
我直接继承LinearLayout来写这个控件。具体实现代码如下:
package com.czm.xcdropdownlistview;

import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

@SuppressLint("NewApi")
/**
* 下拉列表框控件
* @author caiming
*
*/
public class XCDropDownListView extends LinearLayout{

private TextView editText;
private ImageView imageView;
private PopupWindow popupWindow = null;
private ArrayList<String> dataList = new ArrayList<String>();
private View mView;
public XCDropDownListView(Context context) {
this(context,null);
// TODO Auto-generated constructor stub
}
public XCDropDownListView(Context context, AttributeSet attrs) {
this(context, attrs,0);
// TODO Auto-generated constructor stub
}
public XCDropDownListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
initView();
}

public void initView(){
String infServie = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater layoutInflater;
layoutInflater = (LayoutInflater) getContext().getSystemService(infServie);
View view = layoutInflater.inflate(R.layout.dropdownlist_view, this,true);
editText= (TextView)findViewById(R.id.text);
imageView = (ImageView)findViewById(R.id.btn);
this.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(popupWindow == null ){
showPopWindow();
}else{
closePopWindow();
}
}
});
}
/**
* 打开下拉列表弹窗
*/
private void showPopWindow() {
// 加载popupWindow的布局文件
String infServie = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater layoutInflater;
layoutInflater = (LayoutInflater) getContext().getSystemService(infServie);
View contentView = layoutInflater.inflate(R.layout.dropdownlist_popupwindow, null,false);
ListView listView = (ListView)contentView.findViewById(R.id.listView);

listView.setAdapter(new XCDropDownListAdapter(getContext(), dataList));
popupWindow = new PopupWindow(contentView,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
popupWindow.setBackgroundDrawable(getResources().getDrawable(R.color.transparent));
popupWindow.setOutsideTouchable(true);
popupWindow.showAsDropDown(this);
}
/**
* 关闭下拉列表弹窗
*/
private void closePopWindow(){
popupWindow.dismiss();
popupWindow = null;
}
/**
* 设置数据
* @param list
*/
public void setItemsData(ArrayList<String> list){
dataList = list;
editText.setText(list.get(0).toString());
}
/**
* 数据适配器
* @author caiming
*
*/
class XCDropDownListAdapter extends BaseAdapter{

Context mContext;
ArrayList<String> mData;
LayoutInflater inflater;
public XCDropDownListAdapter(Context ctx,ArrayList<String> data){
mContext = ctx;
mData = data;
inflater = LayoutInflater.from(mContext);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mData.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
// 自定义视图
ListItemView listItemView = null;
if (convertView == null) {
// 获取list_item布局文件的视图
convertView = inflater.inflate(R.layout.dropdown_list_item, null);

listItemView = new ListItemView();
// 获取控件对象
listItemView.tv = (TextView) convertView
.findViewById(R.id.tv);

listItemView.layout = (LinearLayout) convertView.findViewById(R.id.layout_container);
// 设置控件集到convertView
convertView.setTag(listItemView);
} else {
listItemView = (ListItemView) convertView.getTag();
}

// 设置数据
listItemView.tv.setText(mData.get(position).toString());
final String text = mData.get(position).toString();
listItemView.layout.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
editText.setText(text);
closePopWindow();
}
});
return convertView;
}

}
private static class ListItemView{
TextView tv;
LinearLayout layout;
}

}

三、如何使用该自定义下拉列表框控件
使用该控件和使用普通的自带的控件一样,首先需要在布局文件中引用该控件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.czm.xcdropdownlistview.MainActivity"
tools:ignore="MergeRootFrame" >

<com.czm.xcdropdownlistview.XCDropDownListView
android:id="@+id/drop_down_list_view"
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true" />

</RelativeLayout>

其次,就是在代码中使用该控件:
package com.czm.xcdropdownlistview;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
/**
* 使用下拉列表框控件 示例
* @author caiming
*
*/
public class MainActivity extends Activity {

XCDropDownListView dropDownListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

dropDownListView = (XCDropDownListView)findViewById(R.id.drop_down_list_view);
ArrayList<String> list = new ArrayList<String>();
for(int i = 0;i< 6;i++){
list.add("下拉列表项"+(i+1));
}
dropDownListView.setItemsData(list);

}

}

对了,这个控件中,我没有实现点击item项回调接口,这个可能对有些写惯了回调的可能觉得少了写什么的感觉,有兴趣的你可以自己添加相关回调操作哈,这个大家应该都会把。

❹ android中自定义时间控件如何实现下面的时间,求源码

我这里有demo,你可以自己琢磨一下


❺ Android 自定义控件 layout

Android 绘制流程

View :View主要执行layout方法,使用 serFrame 方法来设置本身 View 的四个顶点的位置,确定View本身的位置。
ViewGroup :ViewGroup主要执行onLayout方法,递归遍历所有子View,确定子View的位置。

我们来看ViewRootImpl中的 performLayout() 方法

看到这里,那host.getMeasuredWidth() / host.getMeasuredHeight()是什么?它是直接调用View中的方法,其实就是经过measure后的DecorView的测量宽度和高度。在 Android 自定义控件 measure 中有说明。

2.3.2.1 我们先来看ViewGroup中的 layout() 方法

ViewGroup里面的layout最终会调入到父类View中的layout,View的layout后面讲解。这里可以先告诉大家,最终会调用View的onLayout方法,而ViewGroup的onLayout是抽象方法,所以它的子类LinearLayout必须要实现。

2.3.2.2 我们再来看LinearLayout中的 onLayout() 方法。

2.3.2.3 挑一个纵向的吧,我们再来看LinearLayout中的 layoutVertical() 方法。

2.3.2.4 我们再来看LinearLayout中的 setChildFrame() 方法。

又一次回到了View的layout方法,接下来就看View分发的layout。

我们先来看View中的 layout() 方法。

我们先来看View中的 onLayout() 方法。

空空如也,其实View的布局由父容器决定,所以空实现是正常的,当然也可以在自定义View中进行更改。

《Android 视图模块 全家桶》

Android开发之自定义控件(二)---onLayout详解
自定义View Layout过程 - 最易懂的自定义View原理系列(3)

❻ Android自定义控件 | 小红点的三种实现(终结)

上一篇通过在父控件绘制前景的方式展示小红点,在布局文件中配置标记控件就能为任意子控件添加小红点。实现方案是”布局文件中配置带小红点控件 id,在父控件中获取它们的坐标,并在其右上角绘制圆圈“。但这个方案有一个漏洞,当子控件做动画,即子控件尺寸发生变化时,小红点不会联动。效果入下图:

在父控件的 draw() , dispatchDraw() , drawChild() 中打 log,子控件做动画时都未能捕获到联动的事件。

突然想起 androidx.coordinatorlayout.widget.CoordinatorLayout 中的 Behavior ,在 onDependentViewChanged() 中可以实时获得关联控件的属性变化。它是如何做到的?沿着调用链往上查找:

当关联子控件发生变化时,会遍历关联控件并将变换通过 onDependentViewChanged() 传递出去。沿着调用链再往上:

CoordinatorLayout 在 onAttachedToWindow() 时注册了 View 树观察者,子控件属性变化时必定会触发 View树重绘,这样就可以在 onPreDraw() 中监听到它们的属性变化。

将这套机制照搬到自定义容器控件 TreasureBox :

这样当需要绘制小红点的子控件属性发生变化时,标记控件就可以在 onPreDraw() 中收到通知:

每次 View 树重绘前都可以在 onPreDraw() 中实时获取子控件的宽高及坐标,为了避免过度重绘,只有当属性变化时,才触发父控件重绘。需要记忆上次重绘的属性,通过比较就能知道属性是否发生变更:

还需要变更下小红点绘制逻辑,之前的逻辑如下:

如果沿用这套绘制逻辑,即使父控件监听到子控件重绘,小红点也不会跟着联动。那是因为 View 的 getTop() 和 getRight() 不包含位移值:

而 getX() 和 getY() 则包含了位移值:

只需要将绘制逻辑中的 v.right 和 v.top 换成 v.x 和 v.y ,小红点就能和动画联动了。为控件添加位移和缩放动画,测试一下:

GG思密达~
。位移动画的确会联动,但缩放并没有~

打了 log 才发现,View 通过 setScale() 的方式进行动画时,它的宽高和坐标并不会发生变化。。。

但必然是有一个属性的值变化了,虽然暂且不知道它是啥?

只能打开 View 源码,遍历所有 get 开头的函数,然后把它们的值打印在 onPreDraw() 中。经过多次尝试,终于找到了一个函数,它的返回值和子控件缩放动画联动:

当子控件做缩小动画时,该函数返回的 Rect 中的 left 会变大而 right 会变小。

函数的返回值在 mLeft , mRight , mTop , mBottom 的基础上叠加了 matrix 的值。做动画的属性值最终都会反映到 matrix 上,这样一分析好像能自圆其说,即该函数会实时返回 view 因动画而改变的属性值。

如此一来,只需要记忆上一次的 Rect ,就能在下次重绘前通过比较得知子控件是否做了动画:

绘制小红点逻辑也要做响应改动:

大功告成,效果如下:

❼ 如何打造Android自定义的下拉列表框控件

一、概述
Android中的有个原生的下拉列表控件Spinner,但是这个控件有时候不符合我们自己的要求,
比如有时候我们需要类似windows
或者web网页中常见的那种下拉列表控件,类似下图这样的:
这个时候只有自己动手写一个了。其实实现起来不算很难,
本文实现的方案是采用TextView
+ImageView+PopupWindow的组合方案。
先来看看我们的自己写的控件效果图吧:(源码在文章下面最后给出哈!)
二、自定义下拉列表框控件的实现
1.
自定义控件用到的布局文件和资源:
结果框的布局页面:dropdownlist_view.xml:
<?xml
version="1.0"
encoding="utf-8"?>

❽ android自定义控件之文件选择

不多说,先上图:

列举当前目录下的所有文件,如果是选择目录,则不显示文件,如果是选择文件,则需要显示文件。

新建目录,就是在当前路径下新建目录,同时新建后的目录要能够及时显示在文件列表中。

需要读写权限,添加第三方权限请求库:

使用:

DialogFragment与Dialog有一些不同的地方,其中show方法需要传入FragmentManager

另外需在onCreateVie方法初始化布局,以及获取到控件

另外就是RecycleView,之所以采用RecycleView,是因为发现如果用ListView,内存会不断增加,很难降下来。

其中CommonAdapter继承自BaseAdapter,是通用的Adapter,兼容ListView:

这一部分逻辑有FileProvider类完成; 这里需要注意的是,有些手机不支持读取根目录,所以改为读取"/mnt/"作为根目录就行读取。

另外跳转目录都是改变当前路径,然后再刷新数据。

同时在其内部定义了FileData类:

文件选择,可以通过当前路径路径以及列表索引来唯一确定路径;都是,当跳转目录后,索引应该重置。

这里采用WeakReference记录选择的控件,但选择其他目录或者文件时,之前的控件需要重置一下状态。

https://github.com/xiaoyifan6/videocreator

该源码主要用于图片合成gif或者视频,其中文件选择弹窗是自己写的。感觉这个弹出应该有许多地方可以用到,所以写下这篇文章,方便以后参考查看。

❾ 如何打造Android自定义的下拉列表框控件

TextView +ImageView+PopupWindow的组合方案。
先来看看我们的自己写的控件效果图吧:(源码在文章下面最后给出哈!)

二、自定义下拉列表框控件的实现
1. 自定义控件用到的布局文件和资源:
结果框的布局页面:dropdownlist_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/compound"
android:background="@drawable/dropdown_bg_selector" >

<TextView
android:id="@+id/text"
android:layout_width="250dp"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:text="文本文字"
android:gravity="center_vertical"
android:textSize="14sp"
android:padding="5dp"
android:singleLine="true" />
<ImageView
android:id="@+id/btn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_toRightOf="@+id/text"
android:src="@drawable/dropdown"
android:padding="5dp"
android:layout_centerVertical="true"
android:gravity="center"/>
</RelativeLayout>

下拉弹窗列表布局页面:dropdownlist_popupwindow.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<ListView
android:id="@+id/listView"
android:layout_width="280dp"
android:layout_height="wrap_content"
android:divider="#666666"
android:dividerHeight="1dp"
></ListView>

</LinearLayout>

selector资源文件:
dropdown_list_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/dropdownlist_item_press"/>
<item android:drawable="@color/dropdownlist_item"/>
</selector>

dropdown_bg_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/dropdownlist_press"/>
<item android:drawable="@color/dropdownlist_bg"/>
</selector>

2. 自定义下拉列表框控件类的实现:
我们采用了TextView+ImageView+PopupWindow的组合方案,所以我的自定义控件需要重写ViewGroup,由于我们已经知道了,布局方向为竖直方向,所以这里,

阅读全文

与android的自定义控件源码相关的资料

热点内容
手机网站图片压缩 浏览:168
前端程序员干嘛 浏览:562
女权主义pdf 浏览:458
阿里云服务器低价续费 浏览:337
python监控日志脚本 浏览:134
云服务器实例是什么意思 浏览:710
小寻app是做什么的 浏览:649
c语言中编译和运行 浏览:1000
画流图找循环编译原理 浏览:155
oppo手机西瓜视频的文件夹 浏览:867
骑手一般用哪个app 浏览:610
程序员老板用什么手机 浏览:848
比心app头像不通过为什么 浏览:105
加密币市值前十走势 浏览:190
单片机学习推荐课程 浏览:473
对数ln的运算法则图片 浏览:735
仿微博app源码 浏览:781
怎么取消调用app 浏览:545
程序员去哪里求助 浏览:834
服务器里的端口是什么 浏览:975