本文参考了博客 https://www.zybuluo.com/TryLoveCatch/note/722664
// todo: 这里画个图,解释各个方法
View 的setTranslationX()和setTranslationY()会改变translationX和translationY的值,但不会改变margin的值,所以,getLeft()和getTop()不会改变,setTranslationX(0)会恢复translationX的值。
这里可以得出结论,View的宽高由left, top, right和bottom这几个参数决定,而X, Y, translationX和translationY则影响View的位置,如果想要实现更加平滑的View移动效果,可以使用属性动画,直接修改View的属性值。
一般情况下,我们通过getWidth()方法和getMeasuredWidth()方法得到的View宽度是一样的,但其实,这两个方法从字面意思上理解,再结合源码分析,发现measuredWidth值是在View的measure阶段决定的,由方法setMeasuredWidthDimension()方法赋值,而width是在View的layout阶段,由layout()方法决定的。通常layout()方法在parent中被调用,来确定child views在父容器中的位置,一般在自定义ViewGroup的onLayout()方法中调用。
需要注意的是,通常View的width和height是由View本身和parent容器共同决定的,比如,View通过自身measure()方法向parent的请求100*100的宽高,那么这个宽高就是measuredWidth和measuredHeight的值,但是,在parent的onLayout()方法中,通过调用childView.layout()方法只分配给childView50*50的宽高,那么这个50*50就是childView实际绘制并显示到屏幕的宽高,也就是width和height的值。
举个栗子:
import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.os.Bundle; import android.support.annotation.Nullable; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; public class LearnViewWidthActivity extends Activity{ private LinearLayout mLayout; private TextView mView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mLayout = new MyLinearLayout(this); mLayout.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); mView = new MyTextView(this); mLayout.addView(mView); setContentView(mLayout); } private class MyLinearLayout extends LinearLayout{ public MyLinearLayout(Context context) { super(context); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); View v = getChildAt(0); v.layout(0,0,50,50); } } private class MyTextView extends android.support.v7.widget.AppCompatTextView{ public MyTextView(Context context) { super(context); setText("test"); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); measure(0,0); Log.i("===>","width="+getWidth()+",height="+getHeight()); Log.i("===>","measuredWidth="+getMeasuredWidth()+",measuredHeight="+getMeasuredHeight()); } } }Log输出:
width=50,height=50 measuredWidth=214,measuredHeight=38再看size与mode的关系:
public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; }所以measure(0,0)返回的就是mMinWidth, 或者mBackground.getMinimumWidth().
