Android控件全解手册 - 任意View缩放平移工具-实现思路和讲解

news2024/11/26 19:28:22
Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总
游戏脚本-辅助自动化Android控件全解手册再战Android系列
Scratch编程案例软考全系列Unity3D学习专栏
蓝桥系列ChatGPT和AIGC

👉关于作者

专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎底部卡片私我,交流让学习不再孤单

在这里插入图片描述

👉实践过程

使用方式很简单:

GestureViewBinder.bind(this, groupView, targetView);

如果你想让view充满group且大小不能小于group

gestureViewBinder.setFullGroup(true)

这里写图片描述 这里写图片描述


公司的一个项目需要给自定义控件加上缩放平移功能,前人写的代码之写了缩放…那个这个功能填坑的功能就只能交给我了。

首先,这个功能肯定需要监听用户的手势,我本来想的是直接重新控件的onTouchEvent方法的,不过前人用了一个GestureDetector这个类及其子类和一些相关监听。这个以前确实没用到过,简单看了一下后,这是个好东西啊,缩放,平移手势全帮你写好了,还是系统自带的方法,有了这个神器,实现平移缩放还不是分分钟的事!


好了,首先我们先列出一些需求。

  1. 控件能够随双指手势放大缩小相应比例。
  2. 放大超过最大边界后,控件能够平移以显示全部。
  3. 平移之后缩小控件,控件会在逐渐接近边界大小时慢慢居中。
  4. 控件小于等于最小尺寸时自动回弹到默认大小。
  5. 工具最好能够让任意开发者拿来就用,侵入性低。

接下来我们就根据需求,一点一点推进我们的工具吧!


  • 缩放手势基本用法
  • 平移手势基本用法
  • 移动边界计算
  • 点击事件处理

缩放手势基本用法

首先,最简单的就是控件的缩放。我们只需写一个全局变量

private ScaleGestureDetector scaleGestureDetector;

然后实例化这个类,里面传入系统提功能手势回调接口

scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.OnScaleGestureListener() {
  @Override
  public boolean onScale(ScaleGestureDetector detector) {
  Log.i("Gesture", detector.getCurrentSpan() + "---" + detector.getPreviousSpan());
  Log.i("Gesture", String.valueOf(detector.getScaleFactor()));
     return false;
  }

  @Override
  public boolean onScaleBegin(ScaleGestureDetector detector) {
     //这里改成true,在手势开始时拦截掉事件,交给这个接口处理
     return true;
  }

  @Override
  public void onScaleEnd(ScaleGestureDetector detector) {
  }
});

最后,再相应的控件中重写它的onTouchEvent方法(这里是监听了整个Avtivity的手势)。

@Override
public boolean onTouchEvent(MotionEvent event) {
    return scaleGestureDetector.onTouchEvent(event);
}

在重写的onScale方法中打印一下detector.getScaleFactor()返回的值,我们发现,进行缩放手势的时候,这里已经能够成功的得到我们想要的缩放比例了。

如果让某个控件支持缩放手势操作,我们只需重写控件的onTouchEvent方法,然后在里面返回scaleGestureDetector的onTouchEvent方法就可以了。

这里有几点需要注意的地方

  1. 在缩放的同时获取detector.getScaleFactor()的值,由于控件大小不停在改变,所以该值会出现误差导致比例出现异常,因为缩放平移肯定需要有一个边界,所以目前我通过外面包裹ViewGroup,通过给ViewGruop设置手势的方式解决这个问题。因为外面的ViewGroup大小是不会改变的,所以系统计算的比例不会出现问题。有一个ViewGruop也符合我们的需求。
  2. 如果View为可点击的View(Button)或我们给它设置了点击事件,这时View是没办法再监听缩放手势的,我们需要额外处理一下,在缩放手势执行前屏蔽点击事件,在结束后再设置允许点击。
  3. detector.getScaleFactor()得到的缩放比例都是相对于目前view的大小进行计算的,而我们缩放view时,view的比例都是从原始大小开始的,所以我们必须记录上次缩放的比例,下次开始缩放时,从上次的比例大小开始缩放。

简单梳理了一下坑的地方后,我们简单的封装一下,继承ScaleGestureDetector和实现OnScaleGestureListener,把需要进行手势操作的view和对应ViewGroup当作参数传入。直接在我们的方法内部进行重写等一系列操作,这里就不多做赘述了。直接贴出伪代码。(点击事件的处理我们需要在写平移操作的时候进行优化)

//ScaleGestureListener.class
public class ScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {

    private View targetView;
    private float scaleTemp = 1;

    ScaleGestureListener(View targetView) {
        this.targetView = targetView;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float scale = detector.getScaleFactor();
        scale = scaleTemp * scale;
        return false;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        scaleTemp = scale;
    }
}

//ScaleGestureBinder.class
public class ScaleGestureBinder extends ScaleGestureDetector {

    public static ScaleGestureBinder bindView(Context context, View targetView, ViewGroup group) {
        return new ScaleGestureBinder(context, targetView, group);
    }

    private ScaleGestureBinder(Context context, View targetView, ViewGroup group) {
        super(context, new ScaleGestureListener(targetView));
        group.setOnTouchListener(new View.OnTouchListener() {
            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return onTouchEvent(event);
            }
        });
    }
}

//MainActivity.class
scaleGestureBinder = ScaleGestureBinder.bindView(this, tvTarget, rlGroup);

接下来就是根据手势回调得到的缩放比例,来对控件进行操作了。我们用view中自带的setScaleX()和setScaleY()方法就可以缩放控件了。

@Override
public boolean onScale(ScaleGestureDetector detector) {
    scale = detector.getScaleFactor();
    scale = scaleTemp * scale;
    targetView.setScaleX(scale);
    targetView.setScaleY(scale);
    return false;
}

实际使用展示

平移手势基本用法

缩放写完后,就该写平移了,缩放其实非常简单,需要计算的工作几乎全在平移里,我们再归纳一下需要注意的点:

  1. view大小是不能小于viewGroup的大小的,小于group会回弹到充满viewGroup(后面改成了可选设置)。
  2. view小于group大小时需要居中显示。并且缩放时,如果view不在中心,需要虽然比例慢慢回到中心。
  3. 放大平移时,不能移出group边界。

归纳好需求,我们再根据需求一点一点的实现。

首先我们先试用一下GestureDetector,写一个最简单的方法来试试这个类的基本用法。

GestureDetector里其实有好多写好的手势监听,因为需要平移,我们需要实现onScroll方法,看了一下GestureDetector里面的一些接口,我们发现可以继承SimpleOnGestureListener。

public class ScrollGestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return super.onScroll(e1, e2, distanceX, distanceY);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        //这里需要拦截手势,也就是将手势交给我们处理,不然有些情况会被别的事件拦截消费掉。
        return true;
    }
}

打印一下各个参数,我们不难发现onScroll方法里各个参数的含义。

e1为滑动前的MotionEvent,e2为滑动中或者说每一小段滑动后的MotionEvent,distanceX为X轴起始滑动坐标减去结束滑动坐标得到的距离,这种方式计算的话,向右滑为负数,向左滑为正数,这里需要注意一下,distanceY为Y轴滑动距离,特点和distanceX一样。

使用时,这个类作为参数传入GestureDetector,然后再onTouchEvent方法中,返回GestureDetector中的onTouchEvent方法即可。

    gestureDetector = new GestureDetector(this, new ScrollGestureListener());

@Override
public boolean onTouchEvent(MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
}

知道了基本用法,我们再简单的封装一下,并且将缩放和平移的手势整合到一起。这里还有一个需要注意的点:

  • 滑动和缩放的手势会起冲突,无法同时监听。所以在控件的onTouchEvent方法中,我们需要自己处理一下,我这里是通过判断按在屏幕上的手指数量,来返回不同手势回调的。一根手指按下,则为滑动手势,两根手指,则为缩放手势。

封装了一下,变成了这样:

//GestureViewBinder.class
private GestureViewBinder(Context context, ViewGroup viewGroup, View targetView) {
    scaleGestureListener = new ScaleGestureListener(targetView,viewGroup);
    scrollGestureListener = new ScrollGestureListener(targetView,viewGroup);
    scaleGestureBinder = new ScaleGestureBinder(context, scaleGestureListener);
    scrollGestureBinder = new ScrollGestureBinder(context, scrollGestureListener);
    viewGroup.setOnTouchListener(new View.OnTouchListener() {
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.i("Gesture", "pointer count : " + event.getPointerCount());
            if (event.getPointerCount() == 1) {
                return scrollGestureBinder.onTouchEvent(event);
            } else if (event.getPointerCount() == 2) {
                scrollGestureListener.setScale(scaleGestureListener.getScale());
                return scaleGestureBinder.onTouchEvent(event);
            }
            return false;
        }
    });
}


//ScaleGestureBinder.class
ScaleGestureBinder(Context context, ScaleGestureListener scaleGestureListener) {
    super(context, scaleGestureListener);
}

//ScrollGestureBinder.class
ScrollGestureBinder(Context context, ScrollGestureListener scrollGestureListener) {
    super(context, scrollGestureListener);
}

运行试了一下,缩放可以正常使用,平移也走了相应的方法,接下来就是纯计算的步骤了。
移动和缩放一样,都是从控件的原始大小开始计算的,所以我们需要保存一个全局变量来记录上次移动的距离位置。然后调用view的setTranslation方法即可。


private float distanceXTemp = 1;
private float distanceYTemp = 1;

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    distanceX = -distanceX;
    distanceY = -distanceY;
    distanceXTemp += distanceX;
    distanceYTemp += distanceY;
    targetView.setTranslationX(distanceXTemp);
    targetView.setTranslationY(distanceYTemp);
    return super.onScroll(e1, e2, distanceX, distanceY);
}

现在,我们的控件已经既可以滑动又可以缩放了!

平移

移动边界计算

接下来就是计算边界,我们先不考虑缩放的情况,只考虑控件本身可移动的大小。能够移动的距离分别为控件距左、上、右、下的距离。也就是,如果控件向左移动,则判断控件距离左边的距离是否大于0,如果大于0,才允许向左移动。以此类推上、右和下。

还有一个思路就是,判断进入这个页面时,控件距离左边的长度,因为我们存了全局的,移动总长度的变量,如果总的移动距离小于可移动的距离,则可以移动。

这里写图片描述

图画的有点水,但是能看出来,左侧最大移动距离应为getLeft,右侧为viewGrouop的宽减去getRight,上面为getTop,下面为viewGroup的高度减去getBottom。

直接上计算后的代码

//计算能移动的最大距离
maxTranslationLeft = targetView.getLeft();
maxTranslationTop = targetView.getTop();
maxTranslationRight = viewGroup.getWidth()-targetView.getRight();
maxTranslationBottom = viewGroup.getHeight()-targetView.getBottom();


distanceX = -distanceX;
distanceY = -distanceY;
//计算边界
//最大移动距离全部为正数,所以需要通过判断distanceX的正负,来判断是向左移动还是向右移动,
// 然后通过取distanceX的绝对值来和相应移动方向的最大移动距离比较
if ((distanceX < 0 && Math.abs(distanceXTemp + distanceX) < maxTranslationLeft)
        || (distanceX > 0 && distanceXTemp + distanceX < maxTranslationRight)) {
    distanceXTemp += distanceX;
    targetView.setTranslationX(distanceXTemp);
//如果超出边界,就移动到最大距离,防止边界有剩余量
} else if ((distanceX < 0 && Math.abs(distanceXTemp + distanceX) > maxTranslationLeft)) {
    distanceXTemp = -maxTranslationLeft;
    targetView.setTranslationX(-maxTranslationLeft);
} else if ((distanceX > 0 && distanceXTemp + distanceX > maxTranslationRight)) {
    distanceXTemp = maxTranslationRight;
    targetView.setTranslationX(maxTranslationRight);
}

if ((distanceY < 0 && Math.abs(distanceYTemp + distanceY) < maxTranslationTop)
        || (distanceY > 0 && distanceYTemp + distanceY < maxTranslationBottom)) {
    distanceYTemp += distanceY;
    targetView.setTranslationY(distanceYTemp);
//如果超出边界,就移动到最大距离,防止边界有剩余量
} else if ((distanceY < 0 && Math.abs(distanceYTemp + distanceY) > maxTranslationTop)) {
    distanceYTemp = -maxTranslationTop;
    targetView.setTranslationY(-maxTranslationTop);
} else if ((distanceY > 0 && distanceYTemp + distanceY > maxTranslationBottom)) {
    distanceYTemp = maxTranslationBottom;
    targetView.setTranslationY(maxTranslationBottom);
}

通过这几行代码,我们已经能够控制控件一直位于viewGroup中了。

这里写图片描述

然后是和缩放的联动。因为缩放时我们需要在ScrollGesture手势中计算可移动的距离,所以我们需要在缩放时给ScrollGesture传递一个缩放比例的参数,然后在实例化两者的时候传递。

//ScaleGestureListener.class
float getScale() {
    return scale;
}

//ScrollGestureListener
void setScale(float scale) {}

//GestureViewBinder.class
viewGroup.setOnTouchListener(new View.OnTouchListener() {
    scrollGestureListener.setScale(scaleGestureListener.getScale());
}

又是漫长的计算过程。分成view比group大和view比group小两种情况,每种情况又分几点需要考虑。先说一下view比group小时需要考虑的点。

view比group小的情况需要考虑两点(比group小时不需要考虑缩小,默认中心缩小即可):
1. 如果放大后view大小没有超过group边界。(view大小必定小于group)
2. 如果放大后view大小只有一面或相邻两面超过了group边界,但是总大小还是比group小(view大小必定小于group)

这里写图片描述

第一点比较简单,不用进行多余操作,只需要重新计算最大移动距离就行了。(这里只写了计算宽度的代码,高度计算是一样的。)
这里写图片描述

//放大时重新计算可移动距离
viewWidthReal = viewWidthNormal * scale;
viewHeightReal = viewHeightNormal * scale;
if (viewWidthReal < groupWidth) {
    maxTranslationLeft = targetView.getLeft() - (viewWidthReal - viewWidthNormal) / 2;
    maxTranslationRight = (viewGroup.getWidth() - targetView.getRight()) - (viewWidthReal - viewWidthNormal) / 2;
}
viewWidthRealTemp = viewWidthReal;
viewHeightRealTemp = viewHeightReal;
this.scale = scale;

第二点因为view仍然小于group的大小,所以我们让view超出边界时往里面移动。

这里写图片描述

这里需要注意的是,设置往里移动的过程中,我们刚刚用来记录手指滑动距离的参数也要做出相应改变。

//如果移动距离超过最大可移动距离(向左滑动)
if (scale > this.scale && distanceXTemp < 0 && -distanceXTemp > maxTranslationLeft) {
    float translate = (viewWidthReal - viewWidthRealTemp) / 2;
    targetView.setTranslationX(targetView.getTranslationX() + translate);
    distanceXTemp = distanceXTemp + translate;
    //如果移动距离超过最大可移动距离(向右滑动)
} else if (scale > this.scale && distanceXTemp > 0 && distanceXTemp > maxTranslationRight) {
    float translate = (viewWidthReal - viewWidthRealTemp) / 2;
    targetView.setTranslationX(targetView.getTranslationX() - translate);
    distanceXTemp = distanceXTemp - translate;
}

目前的效果:

这里写图片描述

第二种情况是view比group大的情况,可移动距离同样需要重新计算,因为可移动距离由限制view外侧不出边界,变成了限制内侧不出边界。所以这里的计算方式有些变化。可能有点乱,给大家画张图,大家结合实际情况感受一下:

这里写图片描述

if (viewWidthReal > groupWidth) {
    maxTranslationLeft = (viewWidthReal - viewWidthNormal) / 2 - (viewGroup.getWidth() - targetView.getRight());
    maxTranslationRight = (viewWidthReal - viewWidthNormal) / 2 - targetView.getLeft();
}

除了必要的计算边界,这里同样需要考虑缩小时边界问题,也就是,缩小时如果一边比group小,一边比group大的情况。这种情况,我们也需要让比group小的那一边紧贴group边界。这里同样需要大家根据实际情况和后面的gif图理解一下。

这里写图片描述

if (scale < this.scale && distanceXTemp < 0 && -distanceXTemp > maxTranslationLeft) {
    float translate = (viewWidthRealTemp - viewWidthReal) / 2;
    targetView.setTranslationX(targetView.getTranslationX() + translate);
    distanceXTemp = distanceXTemp + translate;
} else if (scale < this.scale && distanceXTemp > 0 && distanceXTemp > maxTranslationRight) {
    float translate = (viewWidthRealTemp - viewWidthReal) / 2;
    targetView.setTranslationX(targetView.getTranslationX() - translate);
    distanceXTemp = distanceXTemp - translate;
}

这里写图片描述

点击事件处理

因为view处理了点击事件后group就无法处理滑动缩放等手势了,所以我们把子view的点击事件屏蔽,交给group处理,这样才能避免冲突。

ScrollGestureListener正好有一个onSingleTapUp回调。我们在这里判断一下点击位置,如果点击位置在子view中,就让子view被点击。

//GestureViewBinder.class
targetView.setClickable(false);

//ScrollGestureListener.class
@Override
public boolean onSingleTapUp(MotionEvent e) {
    float left = viewWidthReal > groupWidth ? 0 : (targetView.getLeft() - ((viewWidthReal - viewWidthNormal) / 2));
    float top = viewHeightReal > groupHeight ? 0 : (targetView.getTop() - ((viewHeightReal - viewHeightNormal) / 2));
    float right = viewWidthReal > groupWidth ? groupWidth : viewGroup.getWidth() - ((viewGroup.getWidth() - targetView.getRight()) - (viewWidthReal - viewWidthNormal) / 2);
    float bottom = viewHeightReal > groupHeight ? groupHeight : viewGroup.getHeight() - ((viewGroup.getHeight() - targetView.getBottom()) - (viewHeightReal - viewHeightNormal) / 2);
    RectF rectF = new RectF(left, top, right, bottom);
    if (rectF.contains(e.getX(), e.getY())) {
        targetView.performClick();
    }
    return super.onSingleTapUp(e);
}

到这里,我们的工具就告一段落了,比如我这里加了一个是否充满group的选项。大家可以自己添加一些需要的小功能。就不在赘述了。

👉其他

📢作者:小空和小芝中的小空
📢转载说明-务必注明来源:https://zhima.blog.csdn.net/
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

温馨提示点击下方卡片获取更多意想不到的资源。
空名先生

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1264788.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

御云出海记|巴西市场,数字化转型与地区增长的新篇章

在11月的阳光下&#xff0c;巴西圣保罗的热情与活力成为了南半球市场的缩影&#xff0c;尤其是在华为云巴西峰会上。 云峰会亮点 11月22日&#xff0c;圣保罗举办的华为云巴西峰会成为了当地科技界的焦点。此次峰会聚集了数百位政府官员、行业领袖、专家学者&#xff0c;共同讨…

C++基础 -10- 类

类的格式 public:公共成员 类外可访问 protected:保护成员 类外不可访问 private:私有成员 类外不可访问 class base {public:int a;protected:int b;private:int c;};

Linux处理系统常见命令

目录 1 sudo 1.1 介绍 1.2 配合 2 ifconfig与ping 2.1 ifconfig 2.2 ping 3 kill 4 apt-get 4.1 介绍 4.2 配合 5 history 6 clear 7 env 1 sudo 1.1 介绍 给这条命令最高权限&#xff0c;比如 sudo cp something.txt /usr/bin/something.txt 1…

用C++和python混合编写数据采集程序?

之前看过一篇文章&#xff0c;主要阐述的就是多种语言混合编写爬虫程序&#xff0c;结合各种语言自身优势写一个爬虫代码是否行得通&#xff1f;觉得挺有意思的&#xff0c;带着这样的问题&#xff0c;我尝试着利用我毕生所学写了一段C和python混合爬虫程序&#xff0c;目前运行…

echarts点击事件

有这么个需求要点击叶片的时候跳转页面 代码&#xff1a;点击之后 报错了 解决办法 1、使用箭头函数&#xff08;箭头函数没有自己的 this&#xff0c;所以在箭头函数中使用 this 时&#xff0c;其指向与外层作用域相同。&#xff09;或者使用闭包来解决上下文的问题。 2、使…

Java抽象类:类的幕后黑手,提供继承和扩展的框架。

&#x1f451;专栏内容&#xff1a;Java⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、抽象类的概念二、注意事项三、抽象类的作用 一、抽象类的概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘…

【JavaSE学习专栏】第02篇 流程控制

文章目录 1 用户交互Scanner2 顺序结构3 选择结构3.1 if单选择结构3.1.1 语法结构3.1.2 案例 3.2 if双选择结构3.2.1 语法结构3.2.2 案例 3.3 if多选择结构3.3.1 语法结构3.3.2 案例 3.4 嵌套的if结构3.4.1 语法结构3.4.2 案例 3.5 switch多选择结构3.5.1 语法结构3.5.2 案例 4…

Opencv | 直方图均衡化

import cv2 #opencv 读取的格式是BGR import numpy as np import matplotlib.pyplot as plt #Matplotlib是RGB %matplotlib inline def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows() cv2.calcHist(images,channels,mask,histSize,ranges) - …

PAT-10道题

PAT算法刷题 1002 1002 一&#xff1a;对于每一的1到6都进行枚举&#xff0c;进行递归操作 二&#xff1a;如果位数到了指定的n的时候&#xff0c;递归的条件&#xff0c;进行判断是否可以整除操作 #include<iostream> #include<algorithm> using namespace std; l…

Programming Abstractions in C阅读笔记:p202-p234

《Programming Abstractions in C》学习第65天&#xff0c;p202-p234总结。 一、技术总结 完成第五章学习&#xff0c;第五章介绍递归在实际问题中的进一步应用&#xff0c;例如汉诺塔问题&#xff0c;数学中的排列问题&#xff0c;更有难度。使用递归解决问题时有时候需要借…

Element-ui合并table表格列方法

merageCell({ row, column, rowIndex, columnIndex }) {if (columnIndex 0 || columnIndex 1) {const property columnIndex 0 ? name : firstDeptName;// 获取当前行的property&#xff0c;这里看自己的需要&#xff0c;改成根据哪个去判断const currentPropertyVal row…

带残差连接的ResNet18

目录 1 模型构建 1.1 残差单元 1.2 残差网络的整体结构 2 没有残差连接的ResNet18 2.1 模型训练 2.2 模型评价 3 带残差连接的ResNet18 3.1 模型训练 3.2 模型评价 4 与高层API实现版本的对比实验 总结 残差网络&#xff08;Residual Network&#xff0c;ResNet&#xff09;…

C语言——数组转换

将的两行三列数组转换为三行两列的数组 #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int a[2][3]{{1,2,3},{4,5,6}};int b[3][2],i,j;for ( i 0; i <1; i){for ( j 0; j <2; j){printf("%5d",a[i][j]);b[j][i]a[i][j];}printf(&…

项目七 熟练使用Vim程序编辑器与shell

项目七 熟练使用Vim程序编辑器与shell #职业能力目标和要求 1&#xff0c;学会使用vim编辑器。 2&#xff0c;了解shell的强大功能和shell的命令解释过程。 3&#xff0c;学会使用重定向和管道的方法。 4&#xff0c;掌握正则表达式的使用方法。7.1 熟悉使用vim编辑器 7.1.1 …

【TC3xx芯片】TC3xx芯片的Clock System功能详解

目录 前言 正文 1.时钟源 1.1 有源晶振和无源晶振 1.1.1 无源晶振 1.1.2 有源晶振 1.1.3 有源晶振和无源晶振的区别 1.1 振荡器电路&#xff08;OSC&#xff09; 1.1.1外部输入时钟模式 1.1.2 外部晶体 / 陶瓷谐振器模式 1.1.3 OSC控制寄存器 1.1.4 配置OSC 1.1.5…

C语言常见算法

算法&#xff08;Algorithm&#xff09;&#xff1a;计算机解题的基本思想方法和步骤。算法的描述&#xff1a;是对要解决一个问题或要完成一项任务所采取的方法和步骤的描述&#xff0c;包括需要什么数据&#xff08;输入什么数据、输出什么结果&#xff09;、采用什么结构、使…

Vue3的transition标签以及animate.css使用详解

一&#xff1a;前言 在项目开发中&#xff0c;有一种特殊情况是使用动画过渡去完成某个效果。比如淡入淡出&#xff0c;或者在动画完成后执行某些操作等。在以前开发中我们通常会选择使用 CSS3 进行研发。但是这样会有很多不好的地方&#xff0c;比如最原始化的封装&#xff0c…

纵行科技获评“汽车物流行业优秀技术装备供应商”

近日&#xff0c;由中国物流与采购联合会主办&#xff0c;中物联汽车物流分会承办的“2023年全国汽车物流行业年会”在湖北十堰盛大召开。本次年会集合了汽车整车、零部件、售后备件、进出口物流企业和物流装备技术企业、科研机构及院校等&#xff0c;分享汽车物流行业现状、相…

使用STM32微控制器实现光电传感器的接口和数据处理

光电传感器在许多领域中被广泛应用&#xff0c;例如工业自动化、智能家居等。本文将介绍如何使用STM32微控制器实现光电传感器的接口和数据处理的方案&#xff0c;包括硬件设计、引脚配置、数据采集、滤波和阈值判断等关键步骤&#xff0c;并给出相应的代码示例。 一、引言 光…

ELK日志收集系统-filbeat

filebeat日志收集工具 elk&#xff1a;filebeat日志收集工具和logstash相同 filebeat是一个轻量级的日志收集工具&#xff0c;所使用的系统资源比logstash部署和启动时使用的资源要小的多 filebeat可以运行在非Java环境&#xff0c;它可以代理logstash在非java环境上收集日志…