属性动画、事件分发和自定义控件

android自定义view底部可上拉页面 最近有需求,要写一个隐藏在底部,但是支持上下拉的菜单框,于是自己写了一个模型,刚好可以复习一下自定义view、事件分发及属性动画的知识。废话不多说,先上效果图:界面很简单,但是有几个难点(大神请略过): 触摸区域处理; 子控件手势拦截; 配合属性动画的使用; 先看一下布局:<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr 阅读详情

这里写了三个大的方面希望记录一下。当然,最大的收获是发现Aige的博客专栏,自定义控件其实很简单。在那里弄懂了很多,也同样看到了自己的距离。但这些可能并不是意识到就能够有变化的。我的观点观点和他的一样,自定义控件,首先要会画,要能画当然要掌握基本的方法。而往往,看到一大堆的方法,好似懂了一两个用法,就不愿去耐心尝试下其它的用法致手上的工具不足。而Aige讲解的控件的测量方面,也是获益匪浅,但其中的ViewGroup部分还留待去消,导化实践。

先从最简单的记起,事件分发。事件分发是从ViewGroup开始传递的。首先是从 ViewGroup#dispatchTouchEvent 方法开始的,也就是事件分发。如果其中 ViewGroup#onInterceptTouchEvent 方法返回true,就把事件在这里拦截,不再去寻找对应的子控件,而是直接在自己ViewGroup的 super#dispatchTouchEvent 中进行处理。onInterceptTouchEvent() 方法是ViewGroup独有的,它的作用是对事件进行拦截,默认返回false。如果ViewGroup#onInterceptTouchEvent 返回false,那么在接下来的代码实现中,就会去寻找对应的子控件,然后进入到该控件的View#dispatchTouchEvent。那么当找到子控件或者ViewGroup自己处理,最后都是到了View#dispatchTouchEVent 方法中。该方法首先调用onTouch()方法,如果有注册触摸事件监听的话。如果onTouch 方法返回true,那么事件分发就结束了。如果返回的不是true,那么就会执行onTouchEvent 方法。onTouchEvent 方法中对ACTION_DOWN、ACTION_UP,等事件进行处理,并在ACTION_UP中进行一段的逻辑判断后,执行 performClick() 方法,也就是执行我们注册的 onClick() 方法。

属性动画之前也认真的学过,结果前一两天要写时,却忘记得较干脆。之前在ToggleButton中也提到过rebound库可能和插值器这部分密切相关,这次重新学习时,发现正是其中的机制。先看基本的使用,主要是ObjectAnmator 类,例如:

		ValueAnimator anim = ObjectAnimator.ofInt(mImageView, "translationY", mHeight);
				anim.setDuration(5000)
					.setInterpolator(new AccelerateDecelerateInterpolator());
				anim.setRepeatCount(4);
				anim.setRepeatMode(ValueAnimator.REVERSE);
				anim.addListener(new Animator.AnimatorListener(){

					@Override
					public void onAnimationStart(Animator animation) {
						// TODO Auto-generated method stub
						
					}

					@Override
					public void onAnimationEnd(Animator animation) {
						// TODO Auto-generated method stub
						
					}

					@Override
					public void onAnimationCancel(Animator animation) {
						// TODO Auto-generated method stub
						
					}

					@Override
					public void onAnimationRepeat(Animator animation) {
						// TODO Auto-generated method stub
						
					}
					
				});			
			anim.start();

如果要对动画一起播放,顺序播放,可以使用AnimatorSet 类的相关方法。同样,也可以在xml中定义动画。在参考博文中有说明举例。

接下来看ValueAnimator的用法,属性动画的原理是对数值进行变化,然后用该变化的数值对控件的属性进行设置更新。ValueAnimator类中的有个注册监听方法:

 public void addUpdateListener(AnimatorUpdateListener listener) 
它的参数是个接口,在接口的回调方法中,

    public static interface AnimatorUpdateListener {
        /**
         * <p>Notifies the occurrence of another frame of the animation.</p>
         *
         * @param animation The animation which was repeated.
         */
        void onAnimationUpdate(ValueAnimator animation);

    }

我们可以通过animation#getAnimatedValue() 获取到变化的对象(可能是整型值,可能是任何其它对象)。那么它的变化规律是在哪里如何控制的呢?它是在一个实现TypeEvaluator的接口的类中传递过去的。TypeEvaluator 类型估值器只有一个方法:

public interface TypeEvaluator<T> {
    public T evaluate(float fraction, T startValue, T endValue);

}

我们在这里的返回值,就是在监听接口用 getAnimatorValue 方法得到的值。参数fraction,范围在0到1,表示的动画的进度百分比;参数startValue和嗯对Value表示的传进来起止对象(不一定是数值对象),从哪里传进来呢,后面的例子中可以明显看到。那么在这里我们就可以做映射处理。那么还有个问题,就是fraction是以怎样的规律传进来呢?这里就涉及到另一个概念,就是插值器Interpolator的使用。系统有默认的实现和配置。这些类的共同点都是实现了 TimeInterpolator接口。可以在Eclispe中直接查看或查找文档。 TimeInterpolator 接口:

public interface TimeInterpolator {

    float getInterpolation(float input);
}

只有一个接口方法,input是匀速的时间流逝比例。返回值就是我们的fraction值。在这里我们可以实现各种不同的数率变化,比如简单的匀速变化:

/**
 * An interpolator where the rate of change is constant
 *
 */
public class LinearInterpolator implements Interpolator {

    public LinearInterpolator() {
    }
    
    public LinearInterpolator(Context context, AttributeSet attrs) {
    }
    
    public float getInterpolation(float input) {
        return input;
    }
}

或者其它很复杂的模型。

参考博文中,给出了一个例子,这里我也自己实现了,贴下相关的代码:

		BallPoint endBallPoint = new BallPoint(mWidth/2, mHeight-mRadius, Color.RED);
		BallPoint startBallPoint = new BallPoint(mWidth/2, mRadius, Color.BLUE);
		mCurrentBallPoint = startBallPoint;
		ofObject = ValueAnimator.ofObject(new BallPointEvaluator(), startBallPoint, endBallPoint);
		ofObject.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
			

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				BallPoint animatedValue = (BallPoint) animation.getAnimatedValue();
				mCurrentBallPoint = animatedValue;
				mBallPointPaint.setColor(mCurrentBallPoint.getColor());
				log("F", "mcurrentBallPoint:" + mCurrentBallPoint.toString());
				invalidate();
			}
		});
		ofObject.setDuration(3000);
		ofObject.setRepeatCount(3);
		ofObject.setRepeatMode(ValueAnimator.RESTART);
//		ofObject.setInterpolator(new BounceInterpolator());
		ofObject.setInterpolator(new MyInterpolator());
		ofObject.start();

	
	private class BallPointEvaluator implements TypeEvaluator<BallPoint> {

		@Override
		public BallPoint evaluate(float fraction, BallPoint startValue,
				BallPoint endValue) {
			int x = (int) (startValue.getX() + fraction * (endValue.getX() - startValue.getX()));
			int y = (int) (startValue.getY() + fraction * (endValue.getY() - startValue.getY()));
			
			int oriColor = startValue.getColor();
			int dstColor = endValue.getColor();
			int or = Color.red(oriColor);
			int og = Color.green(oriColor);
			int ob = Color.blue(oriColor);
			
			int dr = Color.red(dstColor);
			int dg = Color.green(dstColor);
			int db = Color.blue(dstColor);
			
			
			
			int diffr = (int) (or + fraction * (dr - or));
			int diffg = (int) (og + fraction * (dg - og));
			int diffb = (int) (ob + fraction * (db - ob));
			int diffColor = Color.rgb(diffr, diffg, diffb);
			
			BallPoint ballPoint = new BallPoint(x, y, diffColor);
			
			return ballPoint;
		}
		
	}
	

	
	private class MyInterpolator implements TimeInterpolator {

		@Override
		public float getInterpolation(float input) {
			float f = input * input;
			return f;
		}
		
	}

代码都很简单,或者在上面都解释过了。

自定义控件,首先要画一个漂亮的控件。如果作画时以设计的角度去思考如何实现,可能会更简单一些。Paint,画笔。可以设置各种属性,比如 setColorFilter,对图片的颜色的处理,可以变化成各种风格,比如怀旧老照片,变暗,色彩增强等;比如 setXfermode,对两张图片进行各种混合处理,通过Alpha通道合成,它的各种模式都注释有计算公式。通过 setXfermode 可以实现多种效果;比如 setMaskFilter,可以设置过滤的效果,比如边缘的模糊处理;比如 setPathEffect,可以设置路径的连接方式;比如 setShader,可以设置画笔的遮罩模式,可以实现探照灯、圆形头像提取;等等等。Canvas,画布的容器,图形的承载者。可以缩放,平移,分层。

有些累,不写了。其中跟着Aige实现了大部分,这里贴两个图,一个是图标连接,另一个是模拟水杯的效果;这个用高阶贝塞尔曲线来完成的,和360的内存球的效果很类似。有空要练习,可以考虑实现360的内存球效果。

①


	
	private void init() {
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG);
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeWidth(mCircleWidth);
		
		mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
		mTextPaint.setTextSize(18);
		mTextPaint.setColor(Color.WHITE);
		mTextPaint.setTextAlign(Paint.Align.CENTER);
		
		mArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
		mArcPaint.setStyle(Paint.Style.FILL);
		mArcPaint.setColor(0x65ec6941);
		mArcPaint.setStrokeWidth(mCircleWidth);
		
		FontMetrics fontMetrics = mTextPaint.getFontMetrics();
//		mTextAlignOffestY = (fontMetrics.descent - fontMetrics.ascent ) / 4; 	//这里怎么会是除以4呢?!,错误
		mTextAlignOffestY = Math.abs(fontMetrics.ascent) / 2 - fontMetrics.descent /2 ;		//正确
		
		
		
		log("ascent:" + mTextPaint.getFontMetrics().ascent);
		log("descent:" + mTextPaint.getFontMetrics().descent );
		log("mTextAlignOffestY:" + mTextAlignOffestY);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawColor(Color.parseColor("#FF8C00"));
		mPaint.setColor(Color.WHITE);
		
		//中间的圆
		canvas.drawCircle(mWidth/2, mHeight/2+mRadius, mRadius, mPaint);
		canvas.drawText("AigeStudio", mWidth/2, mHeight/2+mRadius+mTextAlignOffestY, mTextPaint);
		
//		canvas.drawLine(0, mHeight/2+mRadius, mWidth, mHeight/2+mRadius, mPaint);
//		canvas.drawLine(0, mHeight/2+mRadius+mTextAlignOffestY, mWidth, mHeight/2+mRadius+mTextAlignOffestY, mPaint);
		
		//画左上角的两个圆
		canvas.save();
		canvas.rotate(mDegrees, mWidth/2, mHeight/2+mRadius);
		canvas.drawLine(mWidth/2, mHeight/2, mWidth/2, mHeight/2-mLineLength, mPaint);
		canvas.drawCircle(mWidth/2, mHeight/2-mLineLength-mRadius, mRadius, mPaint);
		canvas.drawText("loveever", mWidth/2, mHeight/2-mLineLength-mRadius+mTextAlignOffestY, mTextPaint);
		canvas.drawLine(mWidth/2, mHeight/2-mLineLength-2*mRadius, mWidth/2, mHeight/2-mLineLength-2*mRadius-mLineLength, mPaint);
		canvas.drawCircle(mWidth/2, mHeight/2-mLineLength-2*mRadius-mLineLength-mRadius, mRadius, mPaint);
		canvas.drawText("mylife", mWidth/2, mHeight/2-mLineLength-2*mRadius-mLineLength-mRadius+mTextAlignOffestY, mTextPaint);
		canvas.restore();
		
		
		//画右上角的圆
		canvas.save();
		canvas.rotate(-mDegrees, mWidth/2, mHeight/2+mRadius);
		canvas.drawLine(mWidth/2, mHeight/2, mWidth/2, mHeight/2-mLineLength, mPaint);
		canvas.drawCircle(mWidth/2, mHeight/2-mLineLength-mRadius, mRadius, mPaint);
		canvas.drawText("somethings", mWidth/2, mHeight/2-mLineLength-mRadius+mTextAlignOffestY, mTextPaint);
		
		float rectOffestXY = mRadius + mRadius/2;
		RectF oval = new RectF(mWidth/2-rectOffestXY, mHeight/2-mLineLength-mRadius-rectOffestXY, mWidth/2+rectOffestXY, mHeight/2-mLineLength-mRadius+rectOffestXY);
		canvas.drawArc(oval, -150f, 120f, true, mArcPaint);
		mArcPaint.setColor(Color.WHITE);
		mArcPaint.setStyle(Paint.Style.STROKE);
		canvas.drawArc(oval, -150f, 120f, false, mArcPaint);
		
		float baseArc = 120 / 3;
		float offestArc = 30;
		float centerX = mWidth/2;
		float centerY = mHeight/2-mLineLength-mRadius;
		drawArcText(canvas, "Milk", rectOffestXY, offestArc, -1, centerX, centerY);
		drawArcText(canvas, "FFFFF", rectOffestXY, offestArc+baseArc, -1, centerX, centerY);
		drawArcText(canvas, "Yes", rectOffestXY, offestArc, 1, centerX, centerY);
		drawArcText(canvas, "Love", rectOffestXY, offestArc+offestArc, 1, centerX, centerY);
		
		canvas.restore();
		
		//画左边的圆
		canvas.save();
		canvas.rotate(mDegrees+(2*mDegrees)+mDegrees*0.5f, mWidth/2, mHeight/2+mRadius);
		canvas.drawLine(mWidth/2, mHeight/2-mMarginSpace, mWidth/2, mHeight/2-mLineLength-mMarginSpace, mPaint);
		canvas.drawCircle(mWidth/2, mHeight/2-mLineLength-mRadiusSmall-mMarginSpace*2, mRadiusSmall, mPaint);
		canvas.drawText("Apple", mWidth/2, mHeight/2-mLineLength-mRadiusSmall-mMarginSpace*2+mTextAlignOffestY, mTextPaint);
		canvas.restore();
		
		//画下边的圆
		canvas.save();
		canvas.rotate(6*mDegrees, mWidth/2, mHeight/2+mRadius);
		canvas.drawLine(mWidth/2, mHeight/2-mMarginSpace, mWidth/2, mHeight/2-mLineLength-mMarginSpace, mPaint);
		canvas.drawCircle(mWidth/2, mHeight/2-mLineLength-mRadiusSmall-mMarginSpace*2, mRadiusSmall, mPaint);
		
		canvas.drawText("Pear", mWidth/2, mHeight/2-mLineLength-mRadiusSmall-mMarginSpace*2+mTextAlignOffestY, mTextPaint);
		
		canvas.restore();
		
		//画右边的圆
		canvas.save();
		canvas.rotate(-mDegrees-(2*mDegrees)-mDegrees*0.5f, mWidth/2, mHeight/2+mRadius);
		canvas.drawLine(mWidth/2, mHeight/2-mMarginSpace, mWidth/2, mHeight/2-mLineLength-mMarginSpace, mPaint);
		canvas.drawCircle(mWidth/2, mHeight/2-mLineLength-mRadiusSmall-mMarginSpace*2, mRadiusSmall, mPaint);
		canvas.drawText("Orange", mWidth/2, mHeight/2-mLineLength-mRadiusSmall-mMarginSpace*2+mTextAlignOffestY, mTextPaint);
		canvas.restore();
		
		
		
	}

	private void drawArcText(Canvas canvas, String string, float radius, float degress, int flag, float centerX, float centerY) {
		
		log("String:" + string + ", out radius:" + radius + ", degress:" + degress + ", flag: " + flag + ", centerX:" + centerX + ", centerY" + centerY);
		
		float disX = (float) (Math.cos(degress*Math.PI/180)*radius);
		float disY = (float) (Math.sin(degress*Math.PI/180)*radius) + 10;
		
		float x = (float) (disX * flag + centerX);
		float y = (float) (-disY + centerY);
		canvas.drawText(string, x, y, mTextPaint);
		
		log("disX:" + disX + ", disY:" + disY);
	}

②



	@Override
	protected void init() {
		mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
		mPathPaint.setColor(Color.GREEN);
		mPathPaint.setStyle(Paint.Style.FILL);
		
		mPath = new Path();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawColor(Color.LTGRAY);
		mPath.reset();
		
		mPath.moveTo(-mWidth /4, mCurrentY);
		mPath.quadTo(mCurrentX, mCurrentY-mWaterHeightOffset, mWidth+mWidth/4, mCurrentY);
		mPath.lineTo(mWidth+mWidth/4, mHeight);
		mPath.lineTo(-mWidth/4, mHeight);
		mPath.close();
		
		mCurrentY = mInitY + mIncY++;
		
		if (mCurrentY >= mHeight ) {
			mIncY = (int) 1;
		}
		
		if (mCurrentX >= mWidth ) {
			isRight = false;
		} else if (mCurrentX <= 0 ) {
			isRight = true;
		}
		
		mCurrentX = isRight ? mCurrentX+40 : mCurrentX-40;
		
		canvas.drawPath(mPath, mPathPaint);
		
//		log("F", "mCurrentX:" + mCurrentX + ", mCurrentY:" + mCurrentY);
		
		invalidate();
	}

其中, 该博文中对View的测量的流程,以及为什么要这样做,讲解的非常清楚。


参考博文:

1. Android 事件分发机制详解

2. Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

3. Android属性动画深入分析:让你成为动画牛人

4.  Android属性动画完全解析(上),初识属性动画的基本用法

5. android动画(一)Interpolator

6. Android自定义控件其实很简单






第四章 自定义组件、动画 第三章 自定义组件、动画 (一)自定义View 1.1) onMeasure:对当前View的尺寸进行测量 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) widthMeasureSpec和heightMeasureSpec包含测量模式和尺寸大小 int widthMode = MeasureSpec.... 阅读详情

相关推荐

Android View体系(十)自定义组合控件

上一篇我们讲到了自定义View,接着我们来讲讲常用的自定义组合控件,自定义组合控件就是多个控件组合起来成为一个新的控件,主要用来解决多次重复的使用同一类型的布局。比如我们应用的顶部的标题栏,还有弹出的固定样式的dialog,这些都是常用的,所以把他们所需要的控件组合起来重新定义成一个新的控件。

Android进阶三部曲 - 刘望舒 2万+

android之View和ViewGroup事件分发机制分析(一)(View的事件分发机制)

要把安卓学好,自定义View,事件分发机制,自定义动画之类的是必须掌握的,如果不想弄得那么高级来自定义,也可以不学。当初自己也是看了很多相关的书籍和博客文章,理了很久的思路。现在事件分发机制的分析已经理清楚了,而且记在笔记本上也不好,所以就提到博客上来了,对于事件分发机制,什么是事件分发机制呢?这个事件指的就是触摸事件,你手指放在手机上就是触摸事件;分发就是指触摸事件的处理分给谁来处理,怎么处理;

gsw333的博客 1555

一篇文章彻底理解自定义View

对应标签。容易引起oom继承系统的TextView,实现在文字中间加一条横线}}}}) {canvas?}}可以看见文字中间是有一条横线的①.简单实现一个矩形的绘制}}}}) {canvas?}}添加自定义属性,添加自定义背景色先在values目录下面创建attrs.xml,添加自定义属性然后在代码中获取自定义属性,注意获取的资源要回收}//获取自定义属性对应的组名称//获取自定义属性//注意资源需要回收}}}

龚礼鹏的博客 2151

Android 自定义View合集

http://blog.youkuaiyun.com/u011507982/article/details/51199644 自定义控件学习  https://github.com/GcsSloop/AndroidNote/tree/master/CustomView  小良自定义控件合集  https://github.com/Mr-XiaoLiang  自定义控件三部曲  ht

hjh200507609的专栏 2005

Android 360度自定义摇杆控件的实现

自定义View在Android开发中是增强用户界面交互体验的关键手段。在这一章节中,我们将逐步深入了解自定义View的基本概念和创建流程。首先,我们会探讨什么是自定义View以及它在Android UI框架中的重要性。接着,我们将介绍自定义View的三种主要形式:View,ViewGroup和自定义控件,以及它们各自的应用场景。然后,我们将详细说明自定义View的生命周期,以及如何正确地覆盖和重写关键方法,比如onDrawonMeasure和onLayout。

weixin_42524864的博客 1234

Android自定义控件--3(刷新动画)

NULL 博文链接:https://1136051009.iteye.com/blog/2022604

一篇文章带你走近Android自定义view

系列文章目录 一篇文章带你走近Android自定义view 文章目录系列文章目录前言一、为什么要自定义view二、先看看一个超级简单的自定义view(三个构造函数)三、了解手机的坐标系四、使用Canvas画一个折线图(重写onDraw()方法)五、如何自定义属性,且在view中获取到属性的值(小提,在六中会有案例)六、绘制图案以及加入设置简单的动画(案例讲解很详细)七、自定义view的实现分类以及自定义组合控件的案例八、简单测量以及自定义接口实例来控制动画的更新计算表达式(onMeasure,TypeE

计蒙不吃鱼的博客 6026

SDN:使用Postman控制ODL查看和下发流表

所谓,其实可被视作是SDN对网络设备的数据转发功能的一种抽象。在传统网络设备中,交换机和路由器的数据转发需要依赖设备中保存的二层MAC地址转发表或者三层的IP地址路由表,SDN交换机中使用的流表也是如此,不过在它的表项中整合了网络中各个层次的网络配置信息,从而在进行数据转发时可以使用更丰富的规则。其流表中的每个表项结果如下图所示:OpenFlow1.3流表的每个表项由6部分组成:1、匹配域:匹配域即OpenFlow1.0流表中的包头域,用于对交换机接收到的数据包的包头内容进行匹配。Ehter Des。

lyhaoyuhangyuan的博客 2535

《Android自定义控件入门到精通》--文章目录

Android自定义控件入门到精通 自定义控件的流程(扫盲) 一、基础绘图 Point点 Line线 几何图形 Path路径 Region区域 Text文字 Paint画笔 Paint基础知识点 Paint.setPathEffect Paint.setShader Paint.setXfermode Paint.setColorFilter Canvas画布 二、绘图、测量、布局流程 View树的绘制流程 View树的测量流程 View树的布局流程 三、动画 帧动画FrameAnimati

Jhone_csdn的专栏 740

【CubeMX】STM32G474 HRTIM 死区时间与互补PWM实战解析

本文深入解析STM32G474的HRTIM高分辨率定时器在互补PWM生成与死区时间配置中的应用。通过CubeMX工具详细演示时钟配置、单路PWM基础、互补输出与死区时间设置,并结合逆变器等电力电子实战案例,帮助开发者避免直通风险,优化系统性能。

efc12345678的博客 746

告别Vivado自带编辑器!手把手教你用Sublime Text 4 + Icarus Verilog搭建FPGA开发环境(Windows 10/11)

本文详细介绍如何在Windows 10/11系统下,使用Sublime Text 4和Icarus Verilog搭建高效的FPGA开发环境,替代Vivado自带编辑器。通过配置语法检查、代码高亮和智能补全等功能,提升Verilog开发效率,实现专业级工作流。

weixin_30684743的博客 427

View和动画

View是所有控件的基类,布局控件继承自ViewGroup,ViewGroup是所有View和ViewGroup的集合。ViewGroup也是继承自View。 Android坐标系:以屏幕左上方为原点,触控事件getRawX(),getRawY()得到的就是Android坐标。 View坐标系 :和Android坐标系共同存在,如图: 根据图,获取自身高度可以通过getBottom()-getT...

weixin_43330321的博客 227

【RDMA】13. RDMA之用户态与内核态交互

原文:https://zhuanlan.zhihu.com/p/346708569 在“RDMA之Verbs”一文中我们说道,Verbs API分为用户态和内核态,分别以ibv_和ib_作为前缀。RDMA技术的最大的优势就在于用户态可以绕过内核,直接控制硬件收发数据,减少了系统调用和内存拷贝次数,所以大部分的RDMA应用都是用户态应用,即使用以ibv_为前缀的用户态Verbs API。 但是并非所有的用户态Verbs API都可以完全绕开内核,本文中我来讲解一下哪些API依赖于内核RDMA子系统(包括驱

我的笔记本 4285

View体系

View体系简图 1.View的滑动 1.1实现View滑动的六种方法 1.layout() 2.offsetLeftAndRight()与offsetTopAndBottom() 3.LayoutParams(改变布局参数) 4.动画 5.scollTo与scollBy 6.Scroller ...

Baek_的博客 331

从零构建:如何在VSCode中为HBuilderX迁移的UniApp项目搭建TypeScript支持环境

本文详细指导如何将HBuilderX中的UniApp项目迁移至VSCode并搭建TypeScript支持环境。通过pnpm包管理器初始化项目、配置tsconfig.json和vite.config.ts文件,实现工程化迁移与TypeScript深度集成,提升开发效率和代码质量。

book8的博客 1050

【DeepSeek开发入门】DeepSeek API 开发初体验

在人工智能蓬勃发展的时代,DeepSeek作为一款功能强大的AI大模型,为开发者提供了丰富的接口和便捷的开发体验。本文将基于DeepSeek的几个关键接口,带你快速入门,开启DeepSeek开发的探索之旅。通过本文,你已经初步了解了DeepSeek开发中几个重要接口的使用方法,包括列出模型、对话补全和查询余额接口,以及开发过程中的常见问题及解决办法。这是你踏入DeepSeek开发领域的第一步。在后续的学习中,你可以深入研究模型的参数调优,探索不同模型在各种场景下的应用,如利用模型实现更复杂的推理对话功能。

寻道AI,探索AI无限可能! 2755

ListView弹性下拉效果

开源项目地址:https://github.com/chiemy/PullSeparateListView 通过属性动画和事件分发机制实现的。 只分析实现原理: 1.自定义一个View继承ListView 2.复写ListView的dispatchTouchEvent方法 3.在dispatchTouchEvent的通过判断检测滑动到底部和顶部,遍历每一个item来执行属性动画

csm_qz的专栏 1446

手把手教你完成基于cnn的手写数字识别系统MATLAB语言

手写数字识别是经典的 CNN 分类应用之一,常用的数据集就是 MNIST 手写数字数据集,包含 0~9 这 10 个数字的手写图片,每个数字都由 6 万幅训练图像和 1 万幅测试图像构成。为了便于直观分析,这里选择 MATLAB 工具箱提供的 DigitDataset 进行训练识别,读者也可以直接利用 MNIST 数据集或者自己设计的数据集进行实验。其中,数据集文件夹 db 如图 所示。在数据集文件夹 db 里面对每个数字都建立了子文件夹,各自包含 1000 幅 28×28 大小的二维灰度图像。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1368

Android自定义View完全精通:从绘制、事件到动画

实现独特UI效果:创建标准控件库中没有的、具有独特外观和交互的组件(如仪表盘、雷达图、自定义图表)。优化复杂布局:将一个复杂的、由多个View组合而成的布局封装成一个单一的、高性能的自定义View。完全控制交互逻辑:实现标准控件无法提供的特殊触摸反馈和手势。为了让你的自定义View能在XML布局文件中配置,你需要定义自定义属性。三步走流程在下创建attrs.xml文件,并定义属性。在View的构造函数中读取属性值。// Kotlininit {try {// 回收TypedArray,非常重要!

m0_65382359的博客 732

12、知识图谱数据处理与推理全解析

本文深入解析了知识图谱中的数据处理与推理技术,涵盖SHACL的多种约束类型(如值约束、范围约束、字符串约束、逻辑约束等)及其在数据质量控制中的应用,并介绍了常用的SHACL工具与实际案例。文章对比了SPARQL与SHACL的特点,探讨了RDF(S)的局限性,引出表达能力更强的OWL和OWL2语言及其在语义网和生物医学等领域的应用。此外,还阐述了规则在知识表示中的作用,包括产生式规则和Datalog规则,并总结了知识图谱中推理的重要性与典型流程,为构建高质量、可推理的知识图谱提供了全面的技术指导。

zz67890的博客 135

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

属性动画和补间动画的原理及区别

一、结论: 属性动画:所见即所得,最终的显示位置变了,坐标也变了; 补间动画:所见并非所得,虽然最终的显示位置变了,但是坐标还是之前的。 https://www.jianshu.com/p/5d0899dca46e 二、属性动画和补间动画的基本编写方式 我一度在论坛上看到人使用了 TranslateAnimation 对控件做了移动操作,然后发现在 View 的新位置点击并没有响应自己的点击事件,反倒是之前的位置能够响应。实际上,补间动画仅仅是对 View 在视觉效果上做了移动、缩放、旋转和淡入淡出

王温暖的博客 1749

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

每日一问:到底为什么属性动画后 View 在新位置还能响应事件

在 Android 开发中,我们难免会使用动画来处理各种各样的动画效果,以满足 UI 的高逼格设计。对于比较复杂的动画效果,我们通常会采用著名的开源库:lottie-android,或许你会对 lottie 的原理充满好奇,但这并不在我们这篇文章的讨论范围,感兴趣的自行 Google 吧~ 属性动画和补间动画的基本编写方式 我一度在论坛上看到人使用了TranslateAnimation对控...

yanwenyuan0304的专栏 1565

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

3 步装好 iOS 侧载工具 iloader:5 分钟跑通 SideStore 安装

iloader 是一款免费开源的 iOS 侧载工具,把证书导入、签名、配对文件放置这些最繁琐的步骤打包成向导界面。读完本文,5 分钟内你可以把 SideStore 装进 iPhone,或者把任意 IPA 侧载到设备上。 ## 准备清单:4 样东西提前备好 这一步帮你确认"缺什么",避免装到一半卡住。 - **iPhone / iPad + 能传数据的线**(只充电的线会"连不上") - **

gitblog_00708的博客 738

View体系和自定义View:

需要注意的是,凡事都要有度,自定义View毕竟不是规范的控件,如果设计不好、不考虑性能,则反而会适得其反;另外,其适配起来可能也会产生问题。如果能用系统控件的情况还是应尽量用系统控件。自定义View分为三大类,第一种是自定义View,第二种是自定义ViewGroup,第三种是自定义组合控件。其中,自定义View又分为继承系统控件(比如 TextView)和继承View两种情况。

weixin_74399377的博客 1020

38、自定义控件(三)--事件分发和滑动机制

一、View的分发机制 应用场景一 Down:TextView默认是不能获得焦点的,所以它的TouchEvent返回的肯定是false,那么会继续递归到上层交由Activity的TouchEvent消费掉。 UP/Mve:而UP或Move的时候,直接就不会向下走逻辑的,直接在Activity的touchEvent中消费掉。UP和Move是根据Down之后的情况来确定的。 应用场...

weixin_33819479的博客 171
上一篇: ToggleButton自定义View学习
下一篇: Help to memory sth.
xiongmaozhijin
博客等级 码龄15年 4粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值