Android中View绘制各种状态的背景图片原理深入分析以及StateListDrawable使用

Android中View绘制各种状态的背景图片原理深入分析以及StateListDrawable使用,android音频 下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。我们用到的知识点也就这么多吧。 阅读详情

 1、View的几种不同状态属性

           android背景选择器selector用法汇总


        对Android开发者来说,<selector>节点的使用一定很熟悉,该节点的作用就是定义一组状态资源图片,使其能够

  在不同的状态下更换某个View的背景图片。例如hello_selection.xml文件定义:

<span style="white-space:pre">	</span><?xml version="1.0" encoding="utf-8" ?>   
<span style="white-space:pre">	</span><selector xmlns:android="http://schemas.android.com/apk/res/android"> 
  <span style="white-space:pre">		</span><!-- 触摸时并且当前窗口处于交互状态 -->  
  <span style="white-space:pre">		</span><item android:state_pressed="true" android:state_window_focused="true" android:drawable= "@drawable/pic1" />
  <span style="white-space:pre">		</span><!--  触摸时并且没有获得焦点状态 -->  
  <span style="white-space:pre">		</span><item android:state_pressed="true" android:state_focused="false" android:drawable="@drawable/pic2" />  
  <span style="white-space:pre">		</span><!--选中时的图片背景-->  
  <span style="white-space:pre">		</span><item android:state_selected="true" android:drawable="@drawable/pic3" />   
  <span style="white-space:pre">		</span><!--获得焦点时的图片背景-->  
  <span style="white-space:pre">		</span><item android:state_focused="true" android:drawable="@drawable/pic4" />  
  <span style="white-space:pre">		</span><!-- 窗口没有处于交互时的背景图片 -->  
  <span style="white-space:pre">		</span><item android:drawable="@drawable/pic5" /> 
<span style="white-space:pre">	</span></selector>

       其实,这里的Seletor的xml文件,最终会被Android框架解析成StateListDrawable类对象。

 

 

知识点一:StateListDrawable类介绍


    类功能说明:该类定义了不同状态值下与之对应的图片资源,即我们可以利用该类保存多种状态值,多种图片资源。

    常用方法为:

       public void addState (int[] stateSet, Drawable drawable)

       功能: 给特定的状态集合设置相应drawable图片资源

       使用方式:参考前面的hello_selection.xml文件,可以使用代码构建一个相同的StateListDrawable类对象,如下:

<span style="white-space:pre">	</span>//初始化一个空对象
<span style="white-space:pre">	</span>StateListDrawable stalistDrawable = new StateListDrawable();
<span style="white-space:pre">	</span>//获取对应的属性值 Android框架自带的属性 attr
<span style="white-space:pre">	</span>int pressed = android.R.attr.state_pressed;
<span style="white-space:pre">	</span>int window_focused = android.R.attr.state_window_focused;
<span style="white-space:pre">	</span>int focused = android.R.attr.state_focused;
<span style="white-space:pre">	</span>int selected = android.R.attr.state_selected;

<span style="white-space:pre">	</span>stalistDrawable.addState(new int []{pressed , window_focused}, getResources().getDrawable(R.drawable.pic1));
<span style="white-space:pre">	</span>stalistDrawable.addState(new int []{pressed , -focused}, getResources().getDrawable(R.drawable.pic2);
<span style="white-space:pre">	</span>stalistDrawable.addState(new int []{selected }, getResources().getDrawable(R.drawable.pic3);
<span style="white-space:pre">	</span>stalistDrawable.addState(new int []{focused }, getResources().getDrawable(R.drawable.pic4);
<span style="white-space:pre">	</span>//没有任何状态时显示的图片,我们给它设置我空集合
<span style="white-space:pre">	</span>stalistDrawable.addState(new int []{}, getResources().getDrawable(R.drawable.pic5);

        上面的“—”负号表示对应的属性值为false, 当我们为某个View使用其作为背景色时,会根据状态进行背景图的转换。


      public boolean isStateful ()

     功能: 表明该状态改变了,对应的drawable图片是否会改变。

     注:在StateListDrawable类中,该方法返回为true,显然状态改变后,我们的图片会跟着改变。

 


知识点二:View的五种状态值

 

       一般来说,Android框架为View定义了四种不同的状态,这些状态值的改变会引发View相关操作,例如:更换背景图片、是否

   触发点击事件等;视

      视图几种不同状态含义见下图:

enable  :View是否可以响应事件,比如点击,触摸等。

focused:是否有焦点状态。

pressed:是否处于按下状态。

selected:是否处于选中状态。

                window_focused:视图所在窗口是否是处在交互窗口的状态。

   2、一个窗口只能有一个视图获得焦点(focus),而一个窗口可以有多个视图处于”selected”状态中。

 

      总结:focused状态一般是由按键操作引起的;

                pressed状态是由触摸消息引起的;

                selected则完全是由应用程序主动调用setSelected()进行控制。

 

      例如:当我们触摸某个控件时,会导致pressed状态改变;获得焦点时,会导致focus状态变化。于是,我们可以通过这种

   更新后状态值去更新我们对应的Drawable对象了。

 


2、如何根据不同状态去切换我们的背景图片。

       当View任何状态值发生改变时,都会调用refreshDrawableList()方法去更新对应的背景Drawable对象。

       其整体调用流程如下: View.java类中(//路径:\frameworks\base\core\java\android\view\View.java)

    /* Call this to force a view to update its drawable state. This will cause
     * drawableStateChanged to be called on this view. Views that are interested
     * in the new state should call getDrawableState.
     */ 
    //主要功能是根据当前的状态值去更换对应的背景Drawable对象
    public void refreshDrawableState() {
        mPrivateFlags |= DRAWABLE_STATE_DIRTY;
        //所有功能在这个函数里去完成
        drawableStateChanged();
        ...
    }
    /* This function is called whenever the state of the view changes in such
     * a way that it impacts the state of drawables being shown.
     */
    // 获得当前的状态属性--- 整型集合 ; 调用Drawable类的setState方法去获取资源。
    protected void drawableStateChanged() {
    	//该视图对应的Drawable对象,通常对应于StateListDrawable类对象
        Drawable d = mBGDrawable;   
        if (d != null && d.isStateful()) {  //通常都是成立的
        	//getDrawableState()方法主要功能:会根据当前View的状态属性值,将其转换为一个整型集合
        	//setState()方法主要功能:根据当前的获取到的状态,更新对应状态下的Drawable对象。
            d.setState(getDrawableState());
        }
    }
    /*Return an array of resource IDs of the drawable states representing the
     * current state of the view.
     */
    public final int[] getDrawableState() {
        if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) {
            return mDrawableState;
        } else {
        	//根据当前View的状态属性值,将其转换为一个整型集合,并返回
            mDrawableState = onCreateDrawableState(0);
            mPrivateFlags &= ~DRAWABLE_STATE_DIRTY;
            return mDrawableState;
        }
    }


       通过这段代码我们可以明白View内部是如何获取更细后的状态值以及动态获取对应的背景Drawable对象----setState()方法

去完成的。这儿我简单的分析下Drawable类里的setState()方法的功能,把流程给走一下:

    

         Step 1 、 setState()函数原型 ,

             函数位于:frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中


    //如果状态态值发生了改变,就回调onStateChange()方法。
    public boolean setState(final int[] stateSet) {
        if (!Arrays.equals(mStateSet, stateSet)) {
            mStateSet = stateSet;
            return onStateChange(stateSet);
        }
        return false;
    }

           该函数的主要功能: 判断状态值是否发生了变化,如果发生了变化,就调用onStateChange()方法进一步处理。

    

       Step 2 、onStateChange()函数原型:

            该函数位于 frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中


    //状态值发生了改变,我们需要找出第一个吻合的当前状态的Drawable对象
    protected boolean onStateChange(int[] stateSet) {
    	//要找出第一个吻合的当前状态的Drawable对象所在的索引位置, 具体匹配算法请自己深入源码看看
        int idx = mStateListState.indexOfStateSet(stateSet);
        ...
        //获取对应索引位置的Drawable对象
        if (selectDrawable(idx)) {
            return true;
        }
        ...
    }

          该函数的主要功能: 根据新的状态值,从StateListDrawable实例对象中,找到第一个完全吻合该新状态值的索引下标处 ;

   继而,调用selectDrawable()方法去获取索引下标的当前Drawable对象。

         具体查找算法在 mStateListState.indexOfStateSet(stateSet) 里实现了。基本思路是:查找第一个能完全吻合该新状态值

   的索引下标,如果找到了,则立即返回。 具体实现过程,只好看看源码咯。

  

       Step 3 、selectDrawable()函数原型:

            该函数位于 frameworks\base\graphics\java\android\graphics\drawable\StateListDrawable.java 类中

    public boolean selectDrawable(int idx)
    {
        if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
        	//获取对应索引位置的Drawable对象
            Drawable d = mDrawableContainerState.mDrawables[idx];
            ...
            mCurrDrawable = d; //mCurrDrawable即使当前Drawable对象
            mCurIndex = idx;
            ...
        } else {
           ...
        }
        //请求该View刷新自己,这个方法我们稍后讲解。
        invalidateSelf();
        return true;
    }

             该函数的主要功能是选择当前索引下标处的Drawable对象,并保存在mCurrDrawable中。



知识点三: 关于Drawable.Callback接口

   

    该接口定义了如下三个函数:     

    //该函数位于 frameworks\base\graphics\java\android\graphics\drawable\Drawable.java 类中
    public static interface Callback {
    	//如果Drawable对象的状态发生了变化,会请求View重新绘制,
    	//因此我们对应于该View的背景Drawable对象能够”绘制出来”.
        public void invalidateDrawable(Drawable who);
        //
        public void scheduleDrawable(Drawable who, Runnable what, long when);
         //
        public void unscheduleDrawable(Drawable who, Runnable what);
    }

其中比较重要的函数为:


      public voidinvalidateDrawable(Drawable who)

        函数功能:如果Drawable对象的状态发生了变化,会请求View重新绘制,因此我们对应于该View的背景Drawable对象

   能够重新”绘制“出来。


    Android框架View类继承了该接口,同时实现了这三个函数的默认处理方式,其中invalidateDrawable()方法如下:

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource 
{
	...
	//Invalidates the specified Drawable.
    //默认实现,重新绘制该视图本身
    public void invalidateDrawable(Drawable drawable) {
        if (verifyDrawable(drawable)) { //是否是同一个Drawable对象,通常为真
            final Rect dirty = drawable.getBounds();
            final int scrollX = mScrollX;
            final int scrollY = mScrollY;
            //重新请求绘制该View,即重新调用该View的draw()方法  ...
            invalidate(dirty.left + scrollX, dirty.top + scrollY,
                    dirty.right + scrollX, dirty.bottom + scrollY);
        }
    }
	...
}


   因此,我们的Drawable类对象必须将View设置为回调对象,否则,即使改变了状态,也不会显示对应的背景图。 如下:

            Drawable d  ;                // 图片资源                        

            d.setCallback(View v) ;  // 视图v的背景资源为 d 对象


 

知识点四:View绘制背景图片过程


      在前面的博客中《Android中View绘制流程以及invalidate()等相关方法分析》,我们知道了一个视图的背景绘制过程时在

  View类里的draw()方法里完成的,我们这儿在回顾下draw()的流程,同时重点讲解下绘制背景的操作。


//方法所在路径:frameworks\base\core\java\android\view\View.java
//draw()绘制过程
private void draw(Canvas canvas){  
//该方法会做如下事情  
  //1 、绘制该View的背景  
    //其中背景图片绘制过程如下:
	//是否透明, 视图通常是透明的 , 为true
	 if (!dirtyOpaque) {
	   //开始绘制视图的背景
       final Drawable background = mBGDrawable;
       if (background != null) {
           final int scrollX = mScrollX;  //获取偏移值
           final int scrollY = mScrollY;
           //视图的布局坐标是否发生了改变, 即是否重新layout了。
           if (mBackgroundSizeChanged) {
          	 //如果是,我们的Drawable对象需要重新设置大小了,即填充该View。
               background.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
               mBackgroundSizeChanged = false;
           }
           //View没有发生偏移
           if ((scrollX | scrollY) == 0) {
               background.draw(canvas); //OK, 该方法会绘制当前StateListDrawable的当前背景Drawable
           } else {
          	 //View发生偏移,由于背景图片值显示在布局坐标中,即背景图片不会发生偏移,只有视图内容onDraw()会发生偏移
          	 //我们调整canvas对象的绘制区域,绘制完成后对canvas对象属性调整回来
               canvas.translate(scrollX, scrollY);
               background.draw(canvas); //OK, 该方法会绘制当前StateListDrawable的当前背景Drawable
               canvas.translate(-scrollX, -scrollY);
           }
       }
   }
	...
 //2、为绘制渐变框做一些准备操作  
 //3、调用onDraw()方法绘制视图本身  
 //4、调用dispatchDraw()方法绘制每个子视图,dispatchDraw()已经在Android框架中实现了,在ViewGroup方法中。  
 //5、绘制渐变框    
}  


      That's all ! 我们用到的知识点也就这么多吧。 如果大家有丝丝不明白的话,可以去看下源代码,具体去分析下这些流程到底

  是怎么走下来的。

      我们从宏观的角度分析了View绘制不同状态背景的原理,View框架就是这么做的。为了易于理解性,

  下面我们通过一个小Demo来演示前面种种流程。

   

 Demo 说明:


          我们参照View框架中绘制不同背景图的实现原理,自定义一个View类,通过给它设定StateListDrawable对象,使其能够在

   不同状态时能动态"绘制"背景图片。 基本流程方法和View.java类实现过程一模一样。

    截图如下:


                      


                 初始背景图                                                            触摸后显示的背景图(pressed)


  一、主文件MainActivity.java如下:

/**
 * 
 * @author http://http://blog.youkuaiyun.com/qinjuning
 */
public class MainActivity extends Activity
{

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);    

        LinearLayout ll  =  new LinearLayout(MainActivity.this);
        CustomView customView = new CustomView(MainActivity.this); 
        //简单设置为 width 200px - height 100px吧 
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(200 , 100);
        customView.setLayoutParams(lp);
        //需要将该View设置为可点击/触摸状态,否则触摸该View没有效果。
        customView.setClickable(true);
        
        ll.addView(customView);
        setContentView(ll); 
    }
}

   功能很简单,为Activity设置了视图 。


二、 自定义View如下 , CustomView.java :

/** 
 * @author http://http://blog.youkuaiyun.com/qinjuning
 */
//自定义View
public class CustomView extends View   /*extends Button*/
{
    private static String TAG = "TackTextView";
    
    private Context mContext = null;
    private Drawable mBackground = null;
    private boolean mBGSizeChanged = true;;   //视图View布局(layout)大小是否发生变化
    
    public CustomView(Context context)
    {
        super(context);
        mContext = context;       
        initStateListDrawable(); // 初始化图片资源
    }

    // 初始化图片资源
    private void initStateListDrawable()
    {
        //有两种方式获取我们的StateListDrawable对象:
        // 获取方式一、手动构建一个StateListDrawable对象
        StateListDrawable statelistDrawable = new StateListDrawable();
        
        int pressed = android.R.attr.state_pressed;
        int windowfocused = android.R.attr.state_window_focused;
        int enabled = android.R.attr.state_enabled;
        int stateFoucesd = android.R.attr.state_focused;
        //匹配状态时,是一种优先包含的关系。
        // "-"号表示该状态值为false .即不匹配
        statelistDrawable.addState(new int[] { pressed, windowfocused }, 
        		mContext.getResources().getDrawable(R.drawable.btn_power_on_pressed));
        statelistDrawable.addState(new int[]{ -pressed, windowfocused }, 
        		mContext.getResources().getDrawable(R.drawable.btn_power_on_nor));    
               
        mBackground = statelistDrawable;
        
        //必须设置回调,当改变状态时,会回掉该View进行invalidate()刷新操作.
        mBackground.setCallback(this);       
        //取消默认的背景图片,因为我们设置了自己的背景图片了,否则可能造成背景图片重叠。
        this.setBackgroundDrawable(null);
        
        // 获取方式二、、使用XML获取StateListDrawable对象
        // mBackground = mContext.getResources().getDrawable(R.drawable.tv_background);
    }
    
    protected void drawableStateChanged()
    {
        Log.i(TAG, "drawableStateChanged");
        Drawable d = mBackground;
        if (d != null && d.isStateful())
        {
            d.setState(getDrawableState());
            Log.i(TAG, "drawableStateChanged  and is 111");
        }

       Log.i(TAG, "drawableStateChanged  and is 222");
       super.drawableStateChanged();
    }
    //验证图片是否相等 , 在invalidateDrawable()会调用此方法,我们需要重写该方法。
    protected boolean verifyDrawable(Drawable who)
    {
        return who == mBackground || super.verifyDrawable(who);
    }
    //draw()过程,绘制背景图片...
    public void draw(Canvas canvas)
    {
        Log.i(TAG, " draw -----");
        if (mBackground != null)
        {
            if(mBGSizeChanged)
            {
                //设置边界范围
                mBackground.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
                mBGSizeChanged = false ;
            }
            if ((getScrollX() | getScrollY()) == 0)  //是否偏移
            {
                mBackground.draw(canvas); //绘制当前状态对应的图片
            }
            else
            {
                canvas.translate(getScrollX(), getScrollY());
                mBackground.draw(canvas); //绘制当前状态对应的图片
                canvas.translate(-getScrollX(), -getScrollY());
            }
        }
        super.draw(canvas);
    }
    public void onDraw(Canvas canvas) {    
        ...
    }
}


   将该View设置的背景图片转换为节点xml,形式如下:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true" 
        android:state_window_focused="true" 
        android:drawable="@drawable/btn_power_on_pressed"></item>
  <item android:state_pressed="false" 
        android:state_window_focused="true"  
        android:drawable="@drawable/btn_power_on_nor"></item>    
      
</selector>

          基本上所有功能都在这儿显示出来了, 和我们前面说的一模一样吧。

          当然了,如果你想偷懒,大可用系统定义好的一套工具 , 即直接使用setBackgroundXXX()或者在设置对应的属性,但是,

     万变不离其宗,掌握了绘制原理,可以潇洒走江湖了。

     


        示例Demo下载地址: http://download.youkuaiyun.com/detail/qinjuning/4237298

Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解 其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。【Android思维脑图(技能树)】知识不体系? 阅读详情

相关推荐

TP4054芯片实战:手把手教你设计USB锂电充电电路(附PCB散热优化技巧)

本文以TP4054芯片为核心,手把手教你设计稳定可靠的USB锂电池充电电路。文章详细解析了芯片的恒流恒压工作模式、关键外围元件选型计算,并重点分享了PCB布局与散热优化的实战技巧,帮助工程师从“能工作”提升到“工作得好”,确保充电效率与系统稳定性。

1a2s3d4f5g的博客 467

Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解...

本文原创,转载请注明出处:http://blog.youkuaiyun.com/qinjuning 今天继续给大家分享下View的相关知识,重点有一下两点: 1、View的几种不同状态属性 2、如何根据不同状态去切...

tansitongba 334

ESP-IDF下载配合MQTT协议接入云平台实例

通过ESP-IDF下载环境搭建,结合MQTT协议实现设备与云平台通信,详解从配置到连接的完整流程,助力物联网应用开发。重点涵盖espidf下载和MQTT集成关键步骤。

weixin_28913879的博客 454

透明背景View绘制Bitmap,背景变为黑色

Bitmap.Config.RGB_565导致透明背景变为黑色

WXYDX的博客 1489

安卓ai自动化脚本 Yyds.Auto实现 示例 纯ai图像识别自动点击脚本

纯ai识别实现自动化脚本

专注安卓前沿科技 4780

智能车竞赛走马观碑组:如何高效识别目标板并优化绕行策略(附实战代码)

本文深入探讨了智能车竞赛走马观碑组中,如何构建从图像识别到路径决策的全栈优化方案。针对目标板识别与绕行策略的核心难点,文章详细解析了基于MobileNetV2的高效识别流水线、结合预瞄点与纯追踪算法的平滑路径规划,以及横向与纵向协同控制策略,并提供了实战代码与调试指南,旨在全面提升小车的比赛表现。

o5p6q的博客 884

如何在MapView上画一个透明的背景

<br />Android教程1: MapView (Google Map)上的透明面板(直线样式)在这个教程中,我们将会告诉他家怎样创建一个透明面板。我们将展示怎样在一个Google Map中使用透明面板,你可以使用相同的技巧应用到其他的view中。 <br />从这一点上来说,这就是我们今天将要开发的东西——只在Android MapView的底部显示单一按钮的透明面板。 <br /><br /> <br /><br />我们将假设你已经知道Android编程的基本点,只会提到这些“高级的”话题: <b

ghd2000的专栏 3229

使用GitLab的VS Code插件 GitLab Workflow 来进行项目的DevOps管理,助力研发效能

使用VS Code的GitLab Workflow插件,进行项目的DevOps管理,将效率提升到MAX。直接在VScode中管理流水线,一键跳转到创建 Issues,MR

知无涯 5290

Android view不同状态下切换不同背景

一般是通过设置background为drawable资源实现不同状态不同背景。 代码如下: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:stat...

孙先森的博客 1085

倍福CX9020(WINCE 7)控制器使用方法和操作

CX9020系列是倍福控制器中较为经济的,操作系统为Windows Embedded Compact 7(简称WINCE7或WINEC7),相对高端控制器(WINES7以上系统),操作系统古老而简洁,上位机软件的编写困难很多,本文是笔者在使用过程中摸索的流程,旨在为CX9020系列的新用户提供参考,也可供其他CE系统的控制器参考。本文中大部分截图采用倍福中国的培训文档,这是由于笔者是在流程走通后再写这篇文章,不想再恢复出厂设置走一遍截图。因笔者在写这篇文章时使用倍福控制器经验并不丰富,难免有纰漏,请读者批评

weixin_41883890的博客 4287

YOLO26改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型

本文记录的是基于MobileNet V4的YOLO26目标检测轻量化改进方法研究。主要用于轻量化应用部署,相关轻量化改进与其整体架构非常适配。通过整合、以及优化的,能够在在不降低性能指标的前提下,降低计算成本。本文配置了原论文中、、、和五种模型,以满足不同的需求。MobileNetV4: Universal Models for the Mobile Ecosystem是一系列适用于移动生态系统的通用高效模型。以下将详细介绍其轻量化设计的出发点、原理、结构和优势:的实现代码如下: 四、修改步骤 4.1 修

Limiiiing的博客 827

android 常见drawable状态的使用

项目中经常会用到自定义主题的功能,就很需要灵活的编写drawable来进行相应的配置。 选中效果图 未选中效果图 以下2中方式设置效果都是一样的 背景色更换:tab_left_bg.xml,选中是填充蓝色左边圆弧,未选中是蓝色描边的左边圆弧 颜色更换:tab_text_color_selector.xml (2)利用代码来自定义选中样式 2.关于coloe颜色的一些常用方法 color字符串转int color转成 R,G,B,A 十进制值 获取Color 的R,G,B,A 十六进制值 获取更深颜色

weixin_45407364的博客 607

【短距离通信】【WiFi】精讲802.11n/ac/ax mpdu和ampdu最大长度

在 Wi-Fi 标准(802.11n、802.11ac 和 802.11ax)中,和是数据传输的核心概念。理解它们各自的作用以及不同标准下的最大长度限制,有助于深入了解 Wi-Fi 的性能优化机制。以下是对802.11n802.11ac和802.11ax中MPDU和A-MPDU最大长度的详细技术分析和对比。1. MPDU 和 A-MPDU 的基本概念MPDU 是经过 MAC 层处理后的数据单元,主要由MAC层数据帧和物理层的传输头部(PHY headers)组成。

风云说通信 1108
上一篇: android Touch事件流程
下一篇: Android 绘图和shape圆形
cding1818
博客等级 码龄17年 963粉丝 154原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值