精华内容
下载资源
问答
  • ImageView 宽度设定,高度按比例缩放
  • 从获取tabSelectedIndicator边界着手1.1 默认情况下的指示器宽度1.2 tabIndicatorFullWidth="false"时,指示器宽度1.3 使用反射修改TabView的宽度1.4 修改calculateTabViewContentBounds()方法2.从...

    前言

    TabLayout是一个遵循Material Design设计规范的官方控件,也是日常工作中最常用的控件之一,手机上随便打开一个APP,都能看到它的身影。TabLayout可以为一个多页面的布局提供页面指示器,使得一个Activity或者Fragment中能够展示更加丰富的内容。结合ViewPage使用更是可以实现丰富的页面切换效果,并能带来流畅的页面切换体验。

    TabLayout的功能强大,使用灵活,许多属性都支持使用者自由的定义,甚至可以直接给Tab指定一个布局。然而如此强大的控件却偏偏不支持修改底部指示器的宽度,不得不说,写这个控件的工程师的心思是真的难以捉摸啊!
    在这里插入图片描述
    看看这个效果,是不是有些难以直视。再看看主流的APP,几乎都会对这个指示器宽度做一定的修改。UI设计的时候,这里通常也会带有公司的风格。指示器的宽度这么长,再好看的指示器也会被拉伸到变形的。这里就给出几种常见的修改方案

    TabLayout的视图结构

    TabLayout继承自HorizontalScrollView,具有横向滚动的功能。它拥有ScrollView的特点,即内部只能有一个子布局。TabLayout初始化时,会调用一次addView()来添加这个布局。

    super.addView(slidingTabIndicator, 0, new HorizontalScrollView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
    

    同样我们也可以根据index = 0来获取这个布局

    View view = tabLayout.getChildAt(0);
    

    它是一个SlidingTabIndicator,继承自LinearLayout。翻译过来就是滑动标签指示器,也是TabView的直接父布局。你可能疑惑了,指示器不是指的TabView底部的横线么,怎么这个TabLayout的唯一子布局也叫指示器呢?

    简单理解来说,TabView底部的指示器是视觉上的指示器,其作用是给用户标识当前被选中的Tab。我们常说的改指示器宽度就是修改它的宽度,它并不是一个View,本质是SlidingTabIndicator绘制在特定位置的一个Drawable。

    而SlidingTabIndicator是数据上的指示器,其作用是给与TabLayout联动的视图,如ViewPager,标识出当前被选中的位置,以便于联动视图做出相应的操作。因此对于联动视图来讲,它也可以叫指示器。

    TabLayout持有一个Lis< Tab >来管理各个Tab,每个Tab会有属于自己的视图TabView。当TabLayout增加Tab时,会调用SlidingTabIndicator的addView方法,将Tab的TabView添加进来

    public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
        ...
        configureTab(tab, position);
        addTabView(tab);
        ...
    }
    
    private void addTabView(@NonNull Tab tab) {
        final TabView tabView = tab.view;
        tabView.setSelected(false);
        tabView.setActivated(false);
        slidingTabIndicator.addView(tabView, tab.getPosition(), createLayoutParamsForTabs());
    }
    

    因此TabLayout的视图结构应该如下图所示。其中指示器并不是一个控件,它是绘制在SlidingTabIndicator底部的一个Drawable。
    在这里插入图片描述

    TabLayout绘制指示器的过程

    前面提到,所谓的指示器其实只是一个TabLayout中的一个Drawable对象,TabLayout还为它提供了相应的getter和setter。

    @Nullable Drawable tabSelectedIndicator;
    

    当Tab切换时,对指示器的操作如下
    (1) 获取tabSelectedIndicator的边界
    (2) 调用tabSelectedIndicator的draw()方法,将tabSelectedIndicator绘制出来

    步骤已经明了,如此就可以通过修改某一步骤的过程来实现指示器宽度的修改。

    1.从获取tabSelectedIndicator边界着手

    1.1 默认情况下的指示器宽度

    默认情况下使用被选中TabView的宽度,即文章开始时图中看到的指示器充满整个TabView的情况。它使用当前TabView的宽度作为指示器宽度

    .....
    View selectedTitle = getChildAt(this.selectedPosition);
    int left;
    int right;
    if (selectedTitle != null && selectedTitle.getWidth() > 0) {
        // 使用当前选中项的边界作为指示器的边界
        left = selectedTitle.getLeft();
        right = selectedTitle.getRight();
        ......
    }
    // 设置指示器的左右边界
    setIndicatorPosition(left, right)
    
    1.2 tabIndicatorFullWidth="false"时,指示器宽度

    当设置了tabIndicatorFullWidth="false"时,遍历当前TabView的子控件,获取其中left的最小值作为指示器的左边界,right的最大值作为指示器的右边界。在大多数情况下文字才是一个Tab中宽度最大的,因此可以认为这种情况下指示器的宽度与文字宽度相同。

    ......
    if (!tabIndicatorFullWidth && selectedTitle instanceof TabView) {
          calculateTabViewContentBounds((TabView) selectedTitle, tabViewContentBounds);
          left = (int) tabViewContentBounds.left;
          right = (int) tabViewContentBounds.right;
    }
    ......
    
    /**
     * 获取tabView内容的边界
     */
    private void calculateTabViewContentBounds(
                    @NonNull TabView tabView, @NonNull RectF contentBounds) {
         // 获取tabView的内容宽度
        int tabViewContentWidth = tabView.getContentWidth();
        int minIndicatorWidth = (int) ViewUtils.dpToPx(getContext(), MIN_INDICATOR_WIDTH);
    
        if (tabViewContentWidth < minIndicatorWidth) {
            tabViewContentWidth = minIndicatorWidth;
        }
        // 边界设置
        int tabViewCenter = (tabView.getLeft() + tabView.getRight()) / 2;
        int contentLeftBounds = tabViewCenter - (tabViewContentWidth / 2);
        int contentRightBounds = tabViewCenter + (tabViewContentWidth / 2);
        contentBounds.set(contentLeftBounds, 0, contentRightBounds, 0);
    }
    

    看下效果,没有之前充满宽度那么夸张了,但还是难以满足复杂多变的效果,对于需要小于文字宽度的指示器就无能为力了。而且当Tab中的文字字数不同时,切换必然会引起指示器宽度的变化。
    在这里插入图片描述
    综上所述,官方对指示器的宽度定义,是基于TabView的宽度,或者其内容的最大宽度来定义的,使用上跟灵活定制完全不搭边。

    1.3 使用反射修改TabView的宽度

    原理:1.1中讲过,指示器的宽度在默认情况下是TabView的宽度。那么我们可以通过修改TabView的宽度来间接修改指示器的宽度。根据前面视图结构中所讲的,可以通过以下方法获取SlidingTabIndicator。

    LinearLayout mTabViews = (LinearLayout) getChildAt(0);
    

    遍历其子控件即可获取各个TabView,TabView默认左右拥有12dp的Padding,这个是在它的style里定义的。我们获取这个padding值,把这个值设置为margin,然后设置padding为0。即可在保证视觉效果的情况下,修改TabView的宽度,从而修改指示器的宽度效果。

    try {
        for (int i = 0; i < mTabViews.getChildCount(); i++) {
             View tabView = mTabViews.getChildAt(i);
             Field mTextView = getContext().getClassLoader().loadClass("com.google.android.material.tabs.TabLayout$TabView").getDeclaredField("textView");
             mTextView.setAccessible(true);
             TextView textView = (TextView) mTextView.get(tabView);
             int textWidth = textView.getMeasuredWidth();
             // 将Padding改为Margin
             LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)tabView.getLayoutParams();
             params.width = textWidth;
             params.leftMargin = (int) dpToPx(12);
             params.rightMargin = (int) dpToPx(12);
             tabView.setPadding(0, 0, 0, 0);
             tabView.setLayoutParams(params);
             tabView.invalidate();
        }
    } catch (Exception e) {
       e.printStackTrace();
    }
    

    效果如下
    在这里插入图片描述
    显然,这种方法是将指示器的宽度缩小到TabView的中TextView的宽度,指示器的最终的效果跟设置了tabIndicatorFullWidth="false"时是一致的,在有了tabIndicatorFullWidth="false"之后这种方法就可以丢弃了。而且由于TabView的宽度被缩小到了适应内容,各个TabView看上去将挤在一起,需要补充margin参数。点击效果也会显得不够饱满,margin处是没有点击效果的。这种方法已经过时,不推荐使用

    1.4 修改calculateTabViewContentBounds()方法

    1.2中提到,这个方法是tabIndicatorFullWidth="false"时给指示器设置边界时调用的,修改这个方法实现指示器的宽度修改。
    (1)在xml中新增下列属性

    <declare-styleable name="TabLayout">
        <attr name="tabIndicatorWidth" format="dimension"/>
    </declare-styleable>
    

    (2)复制TabLayout源码到自定义的TabLayout中,selectedIndicatorWidth新增仿照selectedIndicatorHeight的获取及设置,然后修改calculateTabViewContentBounds()方法如下

    private void calculateTabViewContentBounds(TabView tabView, RectF contentBounds) {
          if (selectedIndicatorWidth == 0) {
            selectedIndicatorWidth = tabView.getContentWidth();
          }
          int tabViewCenter = (tabView.getLeft() + tabView.getRight()) / 2;
          int contentLeftBounds = tabViewCenter - (selectedIndicatorWidth / 2);
          int contentRightBounds = tabViewCenter + (selectedIndicatorWidth / 2);
    
          contentBounds.set(contentLeftBounds, 0, contentRightBounds, 0);
        }
    

    (3)使用时即可自由定义指示器的宽度

       <com.example.view.TabLayout
            .....
            app:tabIndicatorFullWidth="false"
            app:tabIndicatorWidth="12dp"
            app:tabMode="scrollable" />
    

    在这里插入图片描述
    获取源码:https://github.com/material-components/material-components-android

    2.从tabSelectedIndicator的draw()方法着手

    2.1 重写Drawable的draw()方法

    原理:tabSelectedIndicator是一个Drawable,并且TabLayout有提供相应的设置方法setSelectedTabIndicator()。我们重新定义一个Drawable类,重写它的draw()方法。然后设置为tabSelectedIndicator即可。之后就可以在draw()中为所欲为了。

    public class IndicatorDrawable extends Drawable {
    
        private Paint mPaint;
        private float indicatorLeft;
        private float indicatorRight;
        private int indicatorWidth;
        private float indicatorHeight;
    
        public IndicatorDrawable() {
            this(0);
        }
    
        public IndicatorDrawable(int indicatorWidth) {
            mPaint = new Paint();
            this.indicatorWidth = indicatorWidth;
        }
    
    
        @Override
        public void draw(@NonNull Canvas canvas) {
            // 获取Drawable的真实边界,这个在调用draw之前TabLayout已经设置完毕
            indicatorLeft = getBounds().left;
            indicatorRight = getBounds().right;
            indicatorHeight = getBounds().bottom - getBounds().top;
            // 圆角半径
            float radius = indicatorHeight / 2f;
            // 默认充满
            if (indicatorWidth == 0) {
                indicatorWidth = (int) (indicatorRight - indicatorLeft);
            }
            // 指示器绘制中心
            float indicatorCenter = (indicatorRight + indicatorLeft) / 2f;
            if (indicatorLeft >= 0 && indicatorRight > indicatorLeft
                    && indicatorWidth <= indicatorRight - indicatorLeft) {
                RectF rectF = new RectF(indicatorCenter - indicatorWidth / 2f, getBounds().top,
                        indicatorCenter + indicatorWidth / 2f, getBounds().bottom);
                canvas.drawRoundRect(rectF, radius, radius, mPaint);
            }
        }
    
        @Override
        public void setAlpha(int alpha) {
    
        }
    
        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
    
        }
    
        @Override
        public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
            super.setColorFilter(color, mode);
            // 获取TabLayout传入的画笔颜色
            mPaint.setColor(color);
        }
    
        @Override
        public void setTint(int tintColor) {
            super.setTint(tintColor);
             // 获取TabLayout传入的画笔颜色
            mPaint.setColor(tintColor);
        }
    
        @Override
        public int getOpacity() {
            return PixelFormat.UNKNOWN;
        }
    }
    

    效果如下:
    在这里插入图片描述

    2.2 重写背景Drawable的draw()方法

    原理:在TabLayout中提到,SlidingTabIndicator本质上是一个LinearLayout,它的draw()方法不仅会调用2.1中指示器Drawable的draw()方法,还会在super.draw()中绘制背景。因此,我们可以屏蔽指示器,然后通过绘制背景来模拟指示器的效果。这个不细说,参考这位大佬的博客。
    史上最巧妙自定义tablayout指示器
    当然,我还是认为2.1中的方式原理更加简单,也不需要用反射技术。

    3.其他方式

    3.1 自定义TabView的布局模拟指示器

    原理:TabLayout允许给TabView指定一个自定义的布局customView。可以通过下列代码来指定这个布局。去掉TabLayout自带的指示器,然后在customView的底部放一个ImageView来模拟指示器的效果。这样使用的布局就比较灵活,每个TabView的样式都尽在掌握之中。
    这种方法的缺点是没有指示器切换的动画,尤其是结合ViewPager使用的时候,体验会比较差劲。

    for (i in 0 until tabLayout.tabCount) {
        tabLayout.getTabAt(i)?.setCustomView(R.layout.test)
    }
    
    3.2 使用矢量图作为指示器

    原理:在设置了 tabIndicatorFullWidth="false"时,指示器的宽度是跟TexiView的宽度相同的。准备一张宽度与文字一样宽的图片,图片两端留下一定比例的透明的部分,将TabLayout的指示器设置为这张图片,这样显示在屏幕上的效果就是一个比文字宽度小一些的指示器。

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="20dp"
        android:height="5dp"
        android:viewportWidth="300.0"
        android:viewportHeight="50.0"
        >
    
        <path android:name="indicator"
            android:strokeWidth="50.0"
            android:strokeColor="#FF8F3E"
            android:strokeLineCap="round"
            android:pathData="M 100 25 L 200 25"/>
    
    </vector>
    

    这样做就可以了吗?看下效果
    在这里插入图片描述
    怎么回事,设置的颜色明明是一个黄色,怎么成了黑色了。看下代码

    if (selectedIndicatorPaint != null) {
          if (VERSION.SDK_INT == VERSION_CODES.LOLLIPOP) {
            // Drawable doesn't implement setTint in API 21
            selectedIndicator.setColorFilter(selectedIndicatorPaint.getColor(), PorterDuff.Mode.SRC_IN);
          } else {
              DrawableCompat.setTint(selectedIndicator, selectedIndicatorPaint.getColor());
          }
    }
    

    在调用Drawable的draw方法之前,先通过图层混合过滤了颜色。这里真正取到的是矢量图的形状(PathData),颜色还是指示器画笔的颜色。因此使用的时候不要忘记指定tabIndicatorColor这个属性。

    方便一点,甚至可以直接找UI要一张图,连矢量图都不用绘制了。这种方法使用起来最为简单,但
    缺点是需要跟文字的宽度保持一定的比例,当文字变化时,显示的指示器宽度也会按比例变化。比较适用于文字字数固定的TabLayout中。

    3.3 使用.9图作为指示器

    3.2中提到,在使用矢量图的情况下,当文字变化时,显示的指示器宽度也会按比例变化,因为是整体进行拉伸的。看到这里是不是灵机一动:如果做一张.9图,不就可以保证指示器部分不变化,当拉伸的时候只让透明部分变化不就好了?想到这里赶紧去尝试一波。
    在这里插入图片描述
    首先声明一点,指示器的高度是5dp,上边是用一个80 * 10 px的png图片做成的.9图,其中指示器部分是40px,看下效果:
    在这里插入图片描述
    与预想中的不太一样,图片看上去是被拉伸地变形了。NinePatch当然只会拉伸我们指定的可拉伸区域,在NinePatch看来指示器部分就是这么长。既然宽度没有问题,那么两端圆角的变化会不会是高度被压缩了呢?Log显示Drawable的原始宽度是240px,高度是30px,刚好被扩大了3倍。终于真相浮出了水面!

    drawable文件夹与设备的关系
    (1) 设备根据自己的像素密度去加载对应文件夹的drawable文件。如xxhdpi的设备会首先加载drawable-xxhdpi中的图片。
    (2) 如果对应的文件夹中没有需要加载的文件,就遵循“先高后低”的顺序去别的像素密度下的drawable中寻找。加载图片会按照比例放大或者压缩图片尺寸,从而保证图片在不同像素密度的设备上看起来大小一致。
    (3) 例如,当前设备是xhdpi设备,在drawable中找到了需要的图片,就会放大2倍来使用。如果在drawable-xxhdpi中找到图片,会压缩到 2/3使用。

    此时可以解释图片变形的原因了。前面制作.9图的时候误将图片放在了drawable文件夹中。drawable中的文件,其px与dp的转换比例是1:1,因此它需要的高度就是10dp,而前面只给它指定了5dp,高度被压缩了一半,就出现了上图中图片被拉伸变形的假象。同时由于使用的手机是 xxhdpi。在这种情况下一个80 * 10 px的图片的尺寸也就变成了 240 * 30 px。

    在使用.9图来实现指示器宽度的时,需要首先做一下换算。比如UI图上需要一个20dp宽,5dp高的指示器,那么就应该做一张90 * 15 px的图片。其中指示器部分高度充满,宽度60px,两边各有15px的透明部分。然后做成.9图放在drawable-xxhdpi下,就可以实现需要的效果了。以刚才那张80 * 10的图片为例,把它放在drawable-xxhdpi下,它应该是一个宽26.6dp,高3.3dp的图片。

    注意:我们的设计图本身就来自UI,他们一般都已经有了原始切图,我们拿过来可以直接做.9图。UI使用的工具默认宽度是750px,而我们的Android宽度设备通常是1080px。因此想要保持二者的dp值一致,这种原始切图应该放在drawable-xhdpi。不过最好还是自己计算以下

    看下效果,完美解决:
    在这里插入图片描述

    展开全文
  • jQuery+js 实现Table表格可任意拖动调整列宽度大小 适用于列表页等表头拖动宽度设置,完美兼容IE,FireFox,Google Chrome浏览器。
  • 如何测量脉冲宽度

    万次阅读 2019-02-04 16:48:58
    对于脉冲宽度的测量,小编其实也很少有接触到,但是有一次项目量产时需要写一套自动化测试软件,刚好需要测量某个IO口输出的脉冲宽度。所以对一些需要测量的系统,这个操作还是挺常用。因此,小编接下来将介绍如何...

    前言

    对于脉冲宽度的测量,小编其实也很少有接触到,但是有一次项目量产时需要写一套自动化测试软件,刚好需要测量某个IO口输出的脉冲宽度。所以对一些需要测量的系统,这个操作还是挺常用。因此,小编接下来将介绍如何使用nrf52840实现这个功能。

    开发环境

    原理

    其实脉冲宽度的测量原理还是比较简单的,当发生边缘变化时就开始计时等到下一个边缘到来时,则用当前的时间减去上一次的时间,即可知道这个宽度的时间。但是,务必要使用位数长一点的计时器来保证精度和深度。为什么这么说呢?因为如果位数偏小,那么计时器就很容易溢出;如果精度不够,则计算出来的宽度时间则偏差较大。以下是小编的TIMER配置:

    • timer频率(1MHz)
    • timer位宽度(32Bit)

    从以上的配置我们可以知道,1us一个tick且拥有32bit的宽度,那么这就意味着这个timer溢出需要2^32us即1.2小时。这样的精度用来捕捉宽度已经足够了,因为刚好在1.2小时前后采集数据的概率会低很多。以下的diagram就演示整个采集的过程。

    [外链图片转存失败(img-1MLzh39D-1565883383672)(https://raw.githubusercontent.com/xiaolongba/HX_DK_FOR_NORDIC_52840_BLE/master/%E8%BD%AF%E4%BB%B6/%E7%BA%A2%E6%97%AD%E6%97%A0%E7%BA%BF%E5%BC%80%E5%8F%91%E6%9D%BF%E5%AE%9E%E6%88%98%E6%95%99%E7%A8%8B/nRF52840/the%20releated%20pics%20about%20tutorials/measure%20pulse%20width.svg?sanitize=true)]

    如上图所示,只要获取得到a,c,e三点的时间就可以知道整个脉冲的宽度了。

    如何使用

    就如上一篇什么是 PPI,它能干什么?所说的,脉冲宽度测量对实时性的要求比较高,因此我们这里就不得不又要用到PPI了。

    GPIOTE初始化

    /**
     * gpiote初始化函数
     * @param[in]   NULL
     * @retval      NULL
     * @par         修改日志
     *              Ver0.0.1:
                      Helon_Chan, 2018/07/28, 初始化版本\n
     */
    void user_gpiote_init(nrf_drv_gpiote_evt_handler_t evt_handler)
    {
      nrfx_err_t error_code;
      nrf_drv_gpiote_in_config_t m_nrf_drv_gpiote_in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
      /* 初始化gpiote */
      error_code = nrf_drv_gpiote_init();
      NRF_LOG_INFO("nrf_drv_gpiote_init is %d\n", error_code);
    
      /* gpiote输入初始化 */
      error_code = nrf_drv_gpiote_in_init(GPIOTE_IN_PIN,&m_nrf_drv_gpiote_in_config,evt_handler);
      NRF_LOG_INFO("nrf_drv_gpiote_in_init is %d\n", error_code);
    
      /* 使能gpiote输入事件 */
      nrf_drv_gpiote_in_event_enable(GPIOTE_IN_PIN,true);
    }
    

    从以上源码我们可以看出,设置一个GPIO口当有电平变化时产生一个Event并在相应的回调处理函数中进行下一步的处理,这里我们回调函数指的就是user_app_gpiote_in_evt_handler,我们的宽度测量就放在这个回调中处理了。

    PPI初始化

    /**
     * ppi初始化函数
     * @param[in]   eep:event的地址
     * @param[in]   tep:task的地址
     * @retval      NULL
     * @par         修改日志
     *              Ver0.0.1:
                      Helon_Chan, 2018/10/27, 初始化版本\n
     */
    void user_ppi_init(uint32_t eep, uint32_t tep)
    {
      ret_code_t error_code;
      /* 存放ppi通道 */
      nrf_ppi_channel_t m_nrf_ppi_channel;
      /* 初始化ppi */
      error_code = nrf_drv_ppi_init();
      NRF_LOG_INFO("nrf_drv_ppi_init is %d\n",error_code);
      /* 从未使用的ppi通道中分配一个通道 */
      error_code = nrf_drv_ppi_channel_alloc(&m_nrf_ppi_channel);
      NRF_LOG_INFO("nrf_drv_ppi_channel_alloc is %d\n",error_code);
    
      /* 将指定的event地址和task地址安排至分配到的ppi channel */
      error_code = nrf_drv_ppi_channel_assign(m_nrf_ppi_channel,eep,tep);
      NRF_LOG_INFO("nrf_drv_ppi_channel_assign is %d\n",error_code);
    
      /* 使能ppi channel */
      error_code = nrf_drv_ppi_channel_enable(m_nrf_ppi_channel);
      NRF_LOG_INFO("nrf_drv_ppi_channel_enable is %d\n",error_code);
    }
    

    以上的源码跟上几篇所说的初始化没有什么区别,基本上就是先初始化PPI模块->分配ppi通道->将event与task通过ppi通道相连接,最后使能这个ppi通道。套路都是一样的。

    Timer初始化

    /**
     * timer1初始化函数
     * @param[in]   p_instance:表示定时器的ID
     * @retval      NULL
     * @par         修改日志
     *              Ver0.0.1:
                      Helon_Chan, 2018/10/27, 初始化版本\n
     */
    void user_timer_init(nrfx_timer_t const * const  p_instance)
    {
      nrfx_err_t error_code;
      /* 默认的配置通过sdk_config.h中设置 */
      nrf_drv_timer_config_t m_nrf_drv_timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
      error_code = nrf_drv_timer_init(p_instance,&m_nrf_drv_timer_config,user_timer_event_dummy_handler);
      NRF_LOG_INFO("nrf_drv_timer_init is %d\n",error_code);
    
      /* 此时Timer1定时器就开始工作,每个时钟tick就加1 */
      nrf_drv_timer_enable(p_instance);
    }
    

    以上的源码同样跟上几篇所说的基本一致,无非就是设置相关的参数最后填充进初始化函数,然后再使能。

    PWM初始化

    这里主要是模拟一个脉冲,然后与上面的GPIOTE中所设置的GPIO相连接,PWM一启动那么与其相连的GPIO就会生成event,从而与event相连的task就会被自动鉵发。

    /**
     * pwm初始化函数
     * @param[in]   NULL
     * @retval      NULL
     * @par         修改日志
     *              Ver0.0.1:
                      Helon_Chan, 2018/07/28, 初始化版本\n
     */
    
    void user_pwm_init(void)
    {
      ret_code_t err_code;
      /* 使用默认的配置,配置PWM的周期为1K,PWM输出脚为BROAD_LED,其他3路不使用 */
      nrf_drv_pwm_config_t m_nrf_drv_pwm_config = NRF_DRV_PWM_DEFAULT_CONFIG;
    //  m_nrf_drv_pwm_config.output_pins[0] = NRF_DRV_PWM_PIN_INVERTED;
      m_nrf_drv_pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED;
      m_nrf_drv_pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED;
      m_nrf_drv_pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED;
    
      err_code = nrf_drv_pwm_init(&gs_m_nrf_drv_pwm, &m_nrf_drv_pwm_config, NULL);
      NRF_LOG_INFO("nrf_drv_pwm_init is %d\n", err_code);
    
      nrf_pwm_sequence_t const c_m_seq =
          {
              .values.p_common = duty_values,
              .length = NRF_PWM_VALUES_LENGTH(duty_values),
              .repeats = 0,
              .end_delay = 0};
      /* 重复3次duty_values中指定的占空比,最后保持最后一个占空比的值即100% */
      err_code = nrf_drv_pwm_simple_playback(&gs_m_nrf_drv_pwm, &c_m_seq, 3, 0);
      NRF_LOG_INFO("nrf_drv_pwm_simple_playback is %d\n", err_code);
    }
    

    总结

    脉冲宽度的测量主要由PPI,GPIOTE,PWM,TIMER四个部分组成,利用PPI实时性以及高精度的定时器来实现这个功能,从测试的效果看精度可达us级,这样的精度基本上能满足大部分的场景了。总得来说就是,GPIOTE产生event然后触发定时器1的task,此时定时器1的task就是记录当前跑了多少个tick.然后,我们可以利用前后的tick计算出高电平以及低电平的宽度,从而间接得到整个脉冲的宽度。

    最后

    小编于2019年大年三十含泪写下了这篇文章,祝各位同行2019年个个梦想成真,登上人生巅峰。?

    更多

    红旭无线Github
    红旭无线技术交流论坛
    微信公众号
    在这里插入图片描述

    展开全文
  • Vue ElementUi table宽度自适应 宽度计算

    千次阅读 2020-09-21 18:02:11
    { obj[header.indexKey] = [] }) // 数据为空时,只获取表头的宽度自适应 // 数据不为空,全部数据宽度自适应 tableHeaderData.forEach((head, headIndex) => { obj[headIndex + 1].push(head.description) }) if ...
      computed: {
        tableRange() {
          const { tableHeaderData, tableDataList } = this
          return {
            tableHeaderData,
            tableDataList
          }
        }
      },
      watch: {
        tableRange(val) {
          const _this = this
          const tableDataList = val.tableDataList.slice(0, 10)
          const tableHeaderData = val.tableHeaderData
          if (tableDataList.length === 0) return
          var header = []
          tableHeaderData.forEach((item, index) => {
            header.push({ indexKey: index + 1 })
          })
          var obj = {}
          header.forEach(header => {
            obj[header.indexKey] = []
          })
          // 数据为空时,只获取表头的宽度自适应 // 数据不为空,全部数据宽度自适应
          tableHeaderData.forEach((head, headIndex) => {
            obj[headIndex + 1].push(head.description)
          })
          if (tableDataList.length > 0) {
            tableDataList.forEach((row, rowIndex) => {
              row.forEach((col, colIndex) => {
                for (var key in obj) {
                  if (colIndex === Number(key)) {
                    obj[key].push(col.text)
                  }
                }
              })
            })
          }
          var totalWidth = 60
          tableHeaderData.forEach((value, index) => {
            const curWidth = _this.$getMaxLength(obj[index + 1])
            if (curWidth < 40) {
              value.width = 80
              totalWidth += 80
            } else if (curWidth >= 50 && curWidth < 80) {
              value.width = 130
              totalWidth += 130
            } else if (curWidth >= 80 && curWidth <= 100) {
              value.width = 150
              totalWidth += 150
            } else if (curWidth > 400) {
              value.width = 400
              totalWidth += 400
            } else {
              value.width = curWidth + 40
              totalWidth += curWidth + 40
            }
          })
          const TABLECONTENT = document.getElementById('TABLECONTENT')
          if (TABLECONTENT) {
            // 总宽度占不满整个table时,执行以下
            if (totalWidth < TABLECONTENT.offsetWidth) {
              _this.tableHeaderData.map(function(value) {
                value.width = 'auto'
              })
            }
          }
        }
      },

     html

    <el-table-column
          v-for="(header,columnIndex) in tableHeaderData"
          :key="columnIndex"
          ref="sortColumn"
          :render-header="$labelHead"
          :prop="header[`orderByColumnName`]"
          :label="header.description"
          // 重点在这里
          :width="header.width"
          show-overflow-tooltip
          align="left">
          <template slot-scope="scope">
            ...
          </template>
        </el-table-column>

    main.js  // 自适应table宽度,获取width

     $getMaxLength(arr) {
          if (arr) {
            return arr.reduce((acc, item) => {
              if (item) {
                const calcLen = this.$getTextWidth(item)
                if (acc < calcLen) {
                  acc = calcLen
                }
              }
              return acc
            }, 0)
          } else {
            return 0
          }
        },
    $getTextWidth(str) {
          let width = 0
          const html = document.createElement('span')
          html.innerText = str
          html.className = 'getTextWidth'
          document.querySelector('body').appendChild(html)
          width = document.querySelector('.getTextWidth').offsetWidth
          document.querySelector('.getTextWidth').remove()
          return width
        },

     

    展开全文
  • 宽度学习(BLS)网络的研究和应用

    千次阅读 2020-01-23 08:14:42
    宽度学习(BLS)网络的研究和应用  除了上述这几大AI学术研究要点之外,还有宽度学习(BLS)网络也值得重点关注。宽度学习(BLS)自2018年由我们(陈俊龙教授及其团队)首次在学术界提出,便迅速在科研机构(中科院)、...

    宽度学习(BLS)网络的研究和应用

     

      除了上述这几大AI学术研究要点之外,还有宽度学习(BLS)网络也值得重点关注。宽度学习(BLS)自2018年由我们(陈俊龙教授及其团队)首次在学术界提出,便迅速在科研机构(中科院)、国内知名高校及企业展开了较为广泛的研究与应用。

      虽然深度学习网络非常强大,但大多数网络都被极度耗时的训练过程所困扰。首先深度网络的结构复杂并且涉及到大量的超参数。另外,这种复杂性使得在理论上分析深层结构变得极其困难。另一方面,为了在应用中获得更高的精度,深度模型不得不持续地增加网络层数或者调整参数个数。为了克服这些问题, 宽度学习系统提供了一种深度学习网络的替代方法,同时,如果网络需要扩展,模型可以通过增量学习高效重建。

      宽度学习(BLS)在设计思路方面,首先,利用输入数据映射的特征作为网络的「特征节点」;其次,映射的特征被增强为随机生成权重的「增强节点」;最后,所有映射的特征和增强节点直接连接到输出端,对应的输出系数可以通过快递的伪逆得出(或者梯度下降方法)。BLS 最重要的特点在于它的单隐层结构,具有两个重要的优势,一个是「横向扩展」,另一个则为「增量学习」,与深度神经网络不同之处在于,BLS 不采用深度神经网络的结构,而是基于单隐层神经网络构建,可以用「易懂的数学推导来做增量学习」。

      直白来讲, 深度神经网络学习架构是在结构固定以后才开始学习,此后学习期间如果出现不准确情况,就要重新设计网络、再学习一次。而宽度学习则是设计好网络后,当面临学习不准确的情况,可以随时以横向的方式进行增量扩充,即通过增加神经元,以提高准确度。这种增量学习的模式也适用在数据实时的进入已训练成的神经网络模型当中,而不用重新对整个收集的数据再重新训练。

      在安防领域,宽度学习网络的应用主要表现在两个方面:一是 提升人工智能识别的可靠性。比如在人脸识别算法训练过程中,最好的数据当然是高清正脸无遮挡的干净人脸数据,但实际上测试推理过程中,很多的人脸数据并不完美,会出现被遮挡(墨镜、口罩)、模糊、非正脸角度的人脸照片。在做算法训练过程中,我们可以基于宽度学习网络架构,通过将干净人脸图片和缺陷人脸图片融合到一起做训练,甚至可以特意生成一些有缺陷的图片样本,由此来提高算法对缺陷图片的识别准确率,从而提升复杂场景下人脸识别算法的场景适应能力。二是 解决数据标注的问题,在人工智能算法训练过程中,数据的标注也非常重要,如果标注错误,那么不管算法有多精确,训练的结果也不会理想。通过宽度学习网络构建的算法模型,可以很好地解决算法标注错误的问题。

      通过研究团队的大量测试,可以看出宽度学习(BLS)以及它的各种变体和扩展结构具有良好的发展潜力,在实际应用中表现出其快速且高精度的优秀性能。目前宽度学习在很多技术领域都有展开应用,比如时间序列、高光谱分析、脑机信号分析、容错、基因鉴定与疾病检测、步态识别、3D打印以及智能交通等。随着人工智能技术研究的持续深入,宽度学习这种不需要深度结构的高效增量学习系统有望加速助推人工智能的发展。

    展开全文
  • 宽度优先搜索算法解决八数码问题

    千次阅读 多人点赞 2020-05-19 23:44:41
    宽度优先搜索算法解决八数码问题 实验原理 1、宽度优先搜索是指在一个搜索树中,搜索以同层邻近节点依次扩展节点。这种搜索是逐层进行的,在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点。 宽度优先...
  • 这篇博客主要介绍的是怎样自定义一个可以指定最大宽度,高度,以及宽高比的 Layout。原理其实很简单,就是通过重写 onMeasure 方法,重新制定 MeasureSpec。 使用说明 常用的自定义属性 &lt;attr name="ml...
  • 如图,请问各位如何实现这种布局:view跟在textview的右边,view宽度固定,textview自适应宽度,但textview 加view宽度刚好到达父view宽度时,如果textview内容还没显示完应该显示省略号;就是textview宽度自适应到...
  • 一般来说不需要设置柱形图宽度,不过如果实在是要设置也只能硬着头皮设置了。 修改series对应数组里面的barWidth属性即可设置柱形图宽度,当然还有最小宽,最大宽则是barMinWidth和barMaxWidth api地址:...
  • 宽度学习详解(Broad Learning System)

    万次阅读 多人点赞 2019-09-01 22:27:28
    宽度学习(Broad Learning System) 我也是最近才知道除了深度学习,还有一个神经网络叫宽度学习(下文统称BLS)。 宽度学习是澳门大学科技学院院长陈俊龙和其学生于2018年1月发表的文章提出的,文章名为《Broad ...
  • 文章目录一、前言二、网络深度的意义三、宽度的意义四、 网络宽度设计4.1 网络宽度的下限在哪?4.2 网络宽度对模型性能的影响4.3 网络宽度和深度谁更加重要?五、如何加有效地利用宽度?5.1 提高每一层通道的利用率...
  • 可以通过输入信号机信号的归一化信号,可以很轻易的计算出信号的主瓣宽度、积分旁瓣比、峰值旁瓣比的数值
  • html网页宽度自动适应手机屏幕宽度的方法 web项目中经常会出现html页面需要自适应手机屏幕的情况。 可以通过设置屏幕的缩放比例来实现: 一、使用meta标签,这也是普遍使用的方法,理论上讲使用这个标签是可以...
  • C#生成条形码 可设置高度、宽度等 非常简单 代码好
  • 表格注意点:如果表格单元width为数值,width表示的是content的宽度;如果表格单元width为百分比,width表示的是content + padding + border的宽度。表格border-collapse为collapse时,各列含border的列宽之和 &...
  • Latex表格宽度设置

    千次阅读 2020-08-12 12:25:23
    来源 写论文遇到复杂表头,... 另外最左上角单元格是垂直居中水平居中,而该列其他元素不是 附录 另一个列宽设置:latex表格大小宽度高度调整 表格控制参数:https://blog.csdn.net/yhl_leo/article/details/50066137
  • CSS | 盒模型的宽度计算规则

    千次阅读 2019-02-19 17:20:20
    ,CSS文档并未定义自适应宽度的具体算法,它大多数情况下表现为由子元素的最大指定宽度撑开,但忽略绝对定位子元素的宽度,考虑float元素的宽度。 示例: .container { float : left ; height : 200...
  • 关于PWM脉冲宽度调制的点滴总结

    千次阅读 多人点赞 2020-11-26 21:12:34
    PWM的全称是脉冲宽度调制(Pulse-width modulation),是通过将有效的电信号分散成离散形式从而来降低电信号所传递的平均功率的一种方式; 所以根据面积等效法则,可以通过对改变脉冲的时间宽度,来等效的获得所需要...
  • 经过笔者多次查阅、验证,笔者认为官方文档在计算列款存在误导,实际使用与文档不一致,详见第三部分,欢迎大家来指正本文在宽度计算的问题,谢谢。 一、高度计算 EXCEL的高度在文档记录是以磅为单位的,...
  • ul的宽度根据li的宽度自适应

    千次阅读 2019-09-04 09:01:03
    在项目中遇到ul中的li数量不定,但是还要给ul设置圆角和阴影,而ul默认的宽度是100%,上网查到一个简单的方法就是在ul中加属性 ul{ width: -moz-fit-content; width: fit-content; } 如果对浏览器要求不高,这种...
  • Flutter系列之设置Dialog的宽度

    千次阅读 2021-03-07 15:23:02
    举个栗子: showDialog( context: context, builder: (context) { return Dialog( child: Container( color: Colors.white, width: 50, height: 300, child: Center( child: Text( '测试dialog的宽度', ), ), ), );...
  • poi 操作word里表格,如设置表格宽度、行高、表格样式等。 1.表格或单元格宽度: 默认TblW的type属性为STTblWidth.AUTO,即自动伸缩。所以要调整为指定类型:STTblWidth.DXA 1)表格宽: CTTblPr tblPr = xtab2....
  • Flutter系列之Container宽度自适应

    万次阅读 2020-08-02 22:33:12
    } 如果把这个Container放到ListView中,这个MainAxisSize.min是不起作用的,依然是占满屏幕宽度,请看代码 Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Container自适应'...
  • 详解计算机中的数据宽度

    千次阅读 2020-10-27 14:56:57
    数学上的数字,是没有大小限制的,可以无限大。但是在计算机中,由于受到硬件的制约,数据是有长度限制的(我们称为数据宽度)。超过最多宽度的数据会被丢掉
  • 写TabLayout的时候,发现如果一个Tab中的字很少,它的宽度会是下图这样的:虽然字很短,但是和右边的Tab几乎是一样宽的。 但是我想要每个Tab的文字看起来是等间距的。如下图的样子。 这时因为TabLayout的最小宽度...
  • html响应式网页设计:自动适应屏幕宽度 ...PC的屏幕宽度,一般都在1000像素以上(目前主流宽度是1366×768),有的还达到了2000像素。同样的内容,要在大小迥异的屏幕上,都呈现出满意的效果,并不是一件容易的事。...
  • 宽度学习系统:一种不需要深度结构的高效增量学习系统 本文是对陈俊龙教授团队“Broad Learning System: An Effective and Efficient Incremental Learning System Without the Need for Deep Architecture”的...
  • 宽度优先遍历Or宽度优先搜索详解

    千次阅读 多人点赞 2018-08-13 17:51:10
    宽度优先搜索(BFS, Breadth First Search)是一个针对图和树的遍历算法。发明于上世纪50年代末60年代初,最初用于解决迷宫最短路径和网络路由等问题。 对于下面的树而言,BFS方法首先从根节点1开始,其搜索节点顺序...
  • } </style> 我定义了个最外层,蓝色边框,包含一个子元素灰色盒子,灰色盒子中包含一个子元素红色盒子, 我想要的效果,是灰色盒子的宽度由子元素决定,而不是继承与父元素的。 这时只需要在child上添加 display: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,015,355
精华内容 406,142
关键字:

宽度