original source : https://youtu.be/1OSuBFIbUcM

layoutparams 는 gridlayout 안에 itemview에 적용되는 layout params이다.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

original source : https://youtu.be/eRJ3SiexglY

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

layout_weight은 남은 여백을 어떤 비율로 나눌것인가에 대한 값이다. 실제 view의 크기 비율을 조절하고 싶다면 view의 크기값을 0으로 준다.

=========================================================

.

.

=========================================================

.

.

original source : https://youtu.be/hODuluSJZ0I

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

Window 

window는 불투명 사각형이다. application은 window manager에 요청해서 window를 얻을수 있다. 각 window는 하나의 surface를 가진다. application은 주어진 surface에 자기 원하는 것을 자유롭게 그릴수 있다.

Surface

surface는 screen을 구성할 pixel들을 가지고 있는 obj이다. 각각의 window (dialog, status bar, 개발자가 만든 full screen activity)는 각자의 surface를 가지고 있다. 보통 surface는 하나이상의 buffer를 가진다.(보통은 두개) 두개의 buffer를 가지고 있는 경우 SurfaceFliger가 현재화면을 조합해서 만드는 동안 다음 화면에 그려질 화면 모양을 예비 buffer에 보관함으로써 다음 화면 출력을 대비하게 된다.

SurfaceFlinger

SurfaceFlinger는 각각의 surface들를 최종적으로 올바른 z-order따라 합쳐그린다.

View

view는 window안에 있는 interactive UI element이다. window는 하나의 view hierarchy를 가진다. 언제든 window가 다시 그려져야 한다면 (예를 들어 어떤 view가 invalidate된 경우) surface는 locked 되고 canvas를 return한다. hierarchy를 따라 canvas는 각각의 view를 거치게 된다. view들은 각자 순서에 각자 필요한 부분을 canvas에 그리게 된다. (정확히 말하면 canvas를 이용해서 surface에 연결된 bitmap에 그린다.) 이 과정을 마치면 surface를 unlocked 그리고 posted 된다. 이렇게 완성된 buffer는 foreground와 swap되고 SurfaceFlinger에 의해 조합되서 출력된다. 

Bitmap

pixel data에 대한 interface이다. 여기서 말하는 pixel data는 Bitmap 자신이 가지고 있는 pixel data인 경우도 있지만 Bitmap가 가지고 있지 않는 다른 pixel data일수도 있다. drawing을 위해 surface와 canvas가 내부적을 연결된 경우가 그 예가 될수 있다.  (canvas는 surface에 직접 그리지 않는다. canvas는 bitmap 이나 open GL container에 그린다. bitmap이 만들어지고 current drawing buffer of the Surface에 연결되면 canvas는 bitmap에 그리게 된다.)

orginal source : https://programmer.help/blogs/android-custom-view-foundation-onmeasure-onlayout.html

Android Custom View Foundation onMeasure & onLayout

Official Guidelines: https://developer.android.com/guide/topics/ui/custom-components.html

Method introduction

  • onMeasure()   Used to measure the width and height of view
  • onLayout()   Used to control the position of subviews

onMeasure

In this method, the width of the view is measured and then the height of the view is determined. It should be noted here that the width of the sub-view is measured, not its own.

The complete method is like this.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

Two parameters are passed in, which are the measurements of the size of the current View by the parent layout. It contains wide and high values and measurement modes, which can be obtained using the View.MeasureSpec class.

int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);

It goes without saying that size is px. There are three measurement modes, as shown in the table below.

Measurement mode

  • MeasureSpec.EXACTLY Precise size, parent layout has given a clear size, such as match_parent or 50dp, all of which are precise.
  • MeasureSpec.AT_MOST Adaptive, the parent layout gives a maximum, and the child view adapts itself to the size, but cannot exceed the maximum, such as setting the width to wrap_content
  • MeasureSpec.UNSPECIFIED There is no clear size, the parent layout does not give any value, and the child view is free to play! uuuuuuuuuuu It should be used in a layout like a list adapter

Well, knowing the meaning of this parameter, we can then measure the width of the self-view. In general, if you need to measure subviews, you must inherit ViewGroup or its subclasses.

Several methods are provided in ViewGroup to facilitate simple measurement operations:

  • measureChild()
    Measure the self-view according to the width and height measurements given by the parent layout
  • measureChildWithMargins()
    Measure the self-view according to the given parent layout width and height measurement data and the occupied width and height values, and consider the outer margin of the sub-view. (Margin Layout Params also needs to be implemented if this measurement method is used)

Or you can set the measurements using the measure method of the subview.

Here’s a simple example, inheriting ViewGroup

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    for (int i = 0, count = getChildCount(); i < count; i++){
        final View child = getChildAt(i);
        if (child.getVisibility() != GONE){
            //Measurement Subview
            measureChild(child, widthMeasureSpec,heightMeasureSpec);
        }
    }
    //In onMeasure, this method must be called to set the final measurement width and height.
    setMeasuredDimension(
                MeasureSpec.getSize(widthMeasureSpec),
                MeasureSpec.getSize(heightMeasureSpec));
}

onLayout

This method is called after onMeasure, where the position of the child view is set. The layout() method is called once for all the subviews, and the task is completed.

The simplest example is to stack the layout from the top corner without considering any other factors.

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    for (int i = 0, count = getChildCount(); i < count; i++){
        final View child = getChildAt(i);
        if (child.getVisibility() != GONE){
            child.layout(0,0,child.getMeasuredWidth(),child.getMeasuredHeight());
        }
    }
}

Example

Combining the above two methods gives rise to a view that looks like FrameLayout (there’s still a big gap in detail! )

public class CustomFrameLayout extends ViewGroup {

    public CustomFrameLayout(Context context) {
        super(context);
    }

    public CustomFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        for (int i = 0, count = getChildCount(); i < count; i++){
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE){
                measureChild(child, widthMeasureSpec,heightMeasureSpec);
            }
        }

        setMeasuredDimension(
                MeasureSpec.getSize(widthMeasureSpec),
                MeasureSpec.getSize(heightMeasureSpec));
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        for (int i = 0, count = getChildCount(); i < count; i++){
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE){
                child.layout(0,0, child.getMeasuredWidth(),child.getMeasuredHeight());
            }
        }
    }
}

Of course, the official FrameLayout is far more complicated than the examples I wrote, because there are many other things to consider, such as the margin problem, the size of the outlook, gravity of sub-views, left-right swaps to consider when internationalizing, and so on. So when you can’t fully grasp the customized view, don’t easily inherit ViewGroup directly. You can find a suitable subclass to inherit and make a little modification. It will be much easier!

original source : https://youtu.be/p4vCK93gOZQ

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

아래그림에서 DiscretePathEffect가 아닌 DashPathEffect이다.

=========================================================

.

.

ComposeShader는 여러개의 Shader를 혼합한 형태이다.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

original source : https://youtu.be/iNOltfj_40Y

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.

=========================================================

.

.