在Android与屏幕有关的知识点(一)中,我们对屏幕有关的一些常用概念、基本用法、单位之间转化、截屏等知识点进行了学习.本文将进一步对屏幕有关知识进行学习.

在学习本文前,建议先阅读 Android与屏幕有关的知识点(一)


说明:
(1)本文中涉及测试机的地方,若无特别说明:测试机A指的是分辨率:10802160手机、测试机B指的是分辨率:7201280.

(2)由于笔者所在公司要求不同分辨率手机上,TextView的字体大小、控件宽高相同,并非不同的分辨率手机采用不同的dp、sp.所以在代码设置、自定义属性默认值过程中,都是采用固定数值.如果大家项目中要求适配,请注意修改相应部分.

一.xml与代码中数据的关系

我们先在xml中写一个原生的TextView.设置字体大小为40sp.代码如下:

<?xml version="1.0" encoding="utf-8"?>        

然后在代码中获取字体大小,代码如下:

@Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_dptext);        mTvXml = (TextView) findViewById(R.id.tv_xml);        float textSize = mTvXml.getTextSize();    }

进行断点测试,在测试机A上,mTvXmlTextSize的值为110.0 ;测试机B上,mTvXmlTextSize的值为80.0.

另外,需要补充说明的事:

(1)xml中使用40sp,修改手机系统设置字体,在测试机上的结果不再是110.0、80.0.而是随着系统设置字体的改变而改变.

(2)如果将xml中的40sp换成40dp,在测试机上的结果同样为110.0、80.0.(并且修改手机系统设置 字体大小,都是110.0、80.0)

二. 关于xml、代码中、自定义属性中使用屏幕相关知识

我们在刚才的基础上,再添加2个textView控件. id为tv_code的TextView(第23行)采用原生TextView.我们在代码中设置字体大小、边距.id为tv_custom的TextView(第33行)是继承原生TextView的自定义控件.

xml代码如下:

<?xml version="1.0" encoding="utf-8"?>                        

为了测试的准确性,我们只改变textView字体的大小、textview距离layout_marginTop.
其中,com.mfc.countdowntimerutils.TestTextView 属于继承系统TextView的控件.自定义控件不属于本文谈论范围,对自定义控件不熟或者感兴趣的同学,可以自行谷歌.

com.mfc.countdowntimerutils.TestTextView的属性代码如下(valuse/arrts下):

                          

自定义TestTextView的代码如下:

@SuppressLint("AppCompatCustomView")public class TestTextView extends TextView implements ViewTreeObserver.OnGlobalLayoutListener {    private Context    mContext;    int marginTop;    public TestTextView(Context context) {        super(context);    }    public TestTextView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        this.mContext = context;        init(context, attrs);    }    public TestTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    private void init(Context context, AttributeSet attrs) {        mContext = context;        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable                .TestTextView);        if (typedArray != null) {           //①如果xml中使用了TestTextView_testTextSize属性,typedArray.getDimensionPixelOffset            //会根据xml中使用的单位进行内部转化(比如xml中都是使用40sp,不同分辨率手机得到的initTextSize值不同).                        //②如果xml中没有使用TestTextView_testTextSize属性,typedArray.getDimensionPixelOffset会直接            //使用默认的值(它不知道单位的,默认值也没有单位)            int initTextSize = typedArray.getDimensionPixelOffset(R.styleable                    .TestTextView_testTextSize, DisplayUtils.sp2px(mContext, 40));            setTextSize(TypedValue.COMPLEX_UNIT_PX,initTextSize);            //TestTextView_testTextMarginTop的道理同上述的TestTextView_testTextSize            marginTop = typedArray.getDimensionPixelOffset(R.styleable                    .TestTextView_testTextMarginTop, DisplayUtils.dip2px(mContext,20));            typedArray.recycle();          post(() -> {                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();                Log.e("测试元素", "init: " + this);                lp.leftMargin = 0;                lp.rightMargin = 0;                //数据是px                lp.topMargin = marginTop;                lp.bottomMargin = 0;                setLayoutParams(lp);            });        }    }    @Override    public void onGlobalLayout() {        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();        Log.e("测试元素", "init: " + this);        lp.leftMargin = 0;        lp.rightMargin = 0;        //数据是px        lp.topMargin = marginTop;        lp.bottomMargin = 0;        setLayoutParams(lp);    }//    @Override//    protected void onFinishInflate() {//        super.onFinishInflate();//        getViewTreeObserver().addOnGlobalLayoutListener(this);//    }}

上述代码中,关于view的绘制使用了 重写onFinishInflate()方法,或者post()方法.如果直接使用的话,就会报空指针.这部分不属于本文谈论的范畴,不再赘述.

另外需要说明2点:
1.查看setTextSize() 方法方法的源码我们可知,该方法有接收一个参数的,即setTextSize(float size)
相关部分源码如下:

/**     * Set the default text size to the given value, interpreted as "scaled     * pixel" units.  This size is adjusted based on the current density and     * user font size preference.     *     * 

Note: if this TextView has the auto-size feature enabled than this function is no-op. * * @param size The scaled pixel size. * * @attr ref android.R.styleable#TextView_textSize */ @android.view.RemotableViewMethod public void setTextSize(float size) { setTextSize(TypedValue.COMPLEX_UNIT_SP, size); }

从第14行源码可知,如果只传了一个参数,系统会自动加TypedValue.COMPLEX_UNIT_SP 变成2个参数的.

第一个参数是干嘛用的呢,我们继续点这个方法继续看源码.源码如下:

/**     * Set the default text size to a given unit and value. See {@link     * TypedValue} for the possible dimension units.     *     * 

Note: if this TextView has the auto-size feature enabled than this function is no-op. * * @param unit The desired dimension unit. * @param size The desired size in the given units. * * @attr ref android.R.styleable#TextView_textSize */ public void setTextSize(int unit, float size) { if (!isAutoSizeEnabled()) { setTextSizeInternal(unit, size, true /* shouldRequestLayout */); } }

从第7行对unit参数的描述可知:unit是所需的尺寸单位. 往上看TextView对TypedValue.COMPLEX_UNIT_SP常量的描述,这个常量指的就是sp.也就是说.我们setTextSize(14) 就是14sp.很容易误以为是px.

同样的,我们可以设置第一个参数为dp或sp.当然,后面的值也需要对应更换.还是以实现40sp效果为例.如果使用px,代码如下:

mTvCode.setTextSize(TypedValue.COMPLEX_UNIT_PX,DisplayUtils.sp2px(this,40));

2.关于set的padding或者margin方法,或者计算view的宽高等,单位 则是 px.如果你在xml中使用了TestTextView_testTextMarginTop属性,系统在调用typedArray.getDimensionPixelOffset(R.styleable.TestTextView_testTextMarginTop,value)值时,就根据屏幕的分辨率、xml中自定义属性值,自动转化/

3.在使用最原始的textView时,我们在xml中,分别设置

android:textSize="40sp"android:layout_marginTop="20dp"

为了实现同样的效果,我们使用setTextSize和setMargin的方式也是如何实现的呢:
(1)先看原生的textView但使用代码设置的 方式:

public class TestActivity extends AppCompatActivity {    private TextView mTvXml, mTvCode, mTvCutom;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test);        mTvXml = (TextView) findViewById(R.id.tv_xml);        mTvCode = (TextView) findViewById(R.id.tv_code);        mTvCutom = (TextView) findViewById(R.id.tv_custom);        //这里的40等同于40sp        mTvCode.setTextSize(40);        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mTvCode.getLayoutParams();        lp.leftMargin = 0;        lp.rightMargin = 0;        //数据是px        int temptopMargin = DisplayUtils.dip2px(this, 20);        lp.topMargin = temptopMargin;        lp.bottomMargin = 0;        mTvCode.setLayoutParams(lp);            }}

刚刚已经说过了,setTextSize() 中的 如果是一个参数,数值的单位就是sp.所以直接写 setTextSize(40)即可.
如果想使用2个参数的,写成:

mTvCode.setTextSize(TypedValue.COMPLEX_UNIT_PX,DisplayUtils.sp2px(this,40));

而setMargin的方式,因为赋值的单位是px,而我们一开始的 20dp.所以需要 dp转px后再赋值,即:

 int temptopMargin = DisplayUtils.dip2px(this, 20); lp.topMargin = temptopMargin;

这是手机A断点测试的数据.(分辨率: 1080*2160)
Android与屏幕有关的知识点(二)_第1张图片

这是手机B断点测试的数据.(分辨率: 720*1280)
Android与屏幕有关的知识点(二)_第2张图片

(2)使用自定义控件的 方式(上述TestTextView.class 代码片段):

①设置字体大小

      int initTextSize = typedArray.getDimensionPixelOffset(R.styleable.TestTextView_testTextSize, DisplayUtils.sp2px(mContext, 40));            setTextSize(TypedValue.COMPLEX_UNIT_PX,initTextSize);

②设置间距

marginTop = typedArray.getDimensionPixelOffset(R.styleable.TestTextView_testTextMarginTop, DisplayUtils.dip2px(mContext,20));          
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();Log.e("测试元素", "init: " + this);lp.leftMargin = 0;lp.rightMargin = 0;//数据是pxlp.topMargin = marginTop;lp.bottomMargin = 0;setLayoutParams(lp);

同样的, typedArray.getDimensionPixelOffset获取到的值 的单位是px.而setMargin 需要的值的单位也是px.所以直接使用即可.不需要(也不能转换)

这是手机A断点测试的数据
Android与屏幕有关的知识点(二)_第3张图片

这是手机B断点测试的数据
Android与屏幕有关的知识点(二)_第4张图片

尤其是7201280的手机B数据就一目了然( 7201280分辨率手机: 1dp=2px)

功能运行后,

在手机A上的效果如下

Android与屏幕有关的知识点(二)_第5张图片

在手机B上的效果如下
Android与屏幕有关的知识点(二)_第6张图片

可以发现,三种结果无论是那一张,字体大小, 控件与上边的间距是一样的.从而验证了上述方法的可行性.

更多相关文章

  1. android代码示例讲解--专题视频课程
  2. 使用Android Studio手把手教你将应用打包+代码混淆
  3. Flutter与Android原生代码交互
  4. Android 单元测试实战(1)—— 调研与选型
  5. [置顶] android自动化测试之Benckmark
  6. 安卓系统的开发与测试
  7. Android开发之核心特性SearchView的开发使用(源代码分享)
  8. Android studio怎么使用代码检查工具Analyze?

随机推荐

  1. 限制EditText输入类型与长度
  2. Android布局中margin,padding,align的用
  3. 【eoe Android特刊】第二十四期 Android(
  4. Android(安卓)CTS 测试研究
  5. Android原生(Native)C开发之一:环境搭建篇
  6. 在程序中用Java代码设置android:gravity,
  7. android style & theme
  8. Android漏洞,WebView漏洞,Web漏洞与Web安全
  9. Android(安卓)Binder -什么是binder
  10. Android图片加载与缓存开源框架:Android(