https://youtu.be/zBO_0_7huVA tacademy 동영상를 보다가 이해가 부족하여 다른 자료를 찾게 되었다. 

original source : https://www.tutorialspoint.com/android/android_clipboard.htm

Android provides the clipboard framework for copying and pasting different types of data. The data could be text, images, binary stream data or other complex data types.

Android provides the library of ClipboardManager and ClipData and ClipData.item to use the copying and pasting framework.In order to use clipboard framework, you need to put data into clip object, and then put that object into system wide clipboard.

In order to use clipboard , you need to instantiate an object of ClipboardManager by calling the getSystemService() method. Its syntax is given below −

ClipboardManager myClipboard;
myClipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);

Copying data

The next thing you need to do is to instantiate the ClipData object by calling the respective type of data method of the ClipData class. In case of text data , the newPlainText method will be called. After that you have to set that data as the clip of the Clipboard Manager object.Its syntax is given below −

ClipData myClip;
String text = "hello world";
myClip = ClipData.newPlainText("text", text);
myClipboard.setPrimaryClip(myClip);

The ClipData object can take these three form and following functions are used to create those forms.

Pasting data

In order to paste the data, we will first get the clip by calling the getPrimaryClip() method. And from that click we will get the item in ClipData.Item object. And from the object we will get the data. Its syntax is given below −

ClipData abc = myClipboard.getPrimaryClip();
ClipData.Item item = abc.getItemAt(0);
String text = item.getText().toString();

Apart from the these methods , there are other methods provided by the ClipboardManager class for managing clipboard framework. These methods are listed below −

original source : https://www.includehelp.com/android/use-clipboardmanager-to-clipdata.aspx

초간단 ClipboardManager와 ClipData 구현 예시

original source : https://stackoverflow.com/a/4577249

Here are some definitions:

  • A Surface is an object holding pixels that are being composited to the screen. Every window you see on the screen (a dialog, your full-screen activity, the status bar) has its own surface that it draws in to, and Surface Flinger renders these to the final display in their correct Z-order. A surface typically has more than one buffer (usually two) to do double-buffered rendering: the application can be drawing its next UI state while the surface flinger is compositing the screen using the last buffer, without needing to wait for the application to finish drawing.
  • A window is basically like you think of a window on the desktop. It has a single Surface in which the contents of the window is rendered. An application interacts with the Window Manager to create windows; the Window Manager creates a Surface for each window and gives it to the application for drawing. The application can draw whatever it wants in the Surface; to the Window Manager it is just an opaque rectangle.
  • A View is an interactive UI element inside of a window. A window has a single view hierarchy attached to it, which provides all of the behavior of the window. Whenever the window needs to be redrawn (such as because a view has invalidated itself), this is done into the window’s Surface. The Surface is locked, which returns a Canvas that can be used to draw into it. A draw traversal is done down the hierarchy, handing the Canvas down for each view to draw its part of the UI. Once done, the Surface is unlocked and posted so that the just drawn buffer is swapped to the foreground to then be composited to the screen by Surface Flinger.
  • A SurfaceView is a special implementation of View that also creates its own dedicated Surface for the application to directly draw into (outside of the normal view hierarchy, which otherwise must share the single Surface for the window). The way this works is simpler than you may expect – all SurfaceView does is ask the window manager to create a new window, telling it to Z-order that window either immediately behind or in front of the SurfaceView’s window, and positioning it to match where the SurfaceView appears in the containing window. If the surface is being placed behind the main window (in Z order), SurfaceView also fills its part of the main window with transparency so that the surface can be seen.
  • A Bitmap is just an interface to some pixel data. The pixels may be allocated by Bitmap itself when you are directly creating one, or it may be pointing to pixels it doesn’t own such as what internally happens to hook a Canvas up to a Surface for drawing. (A Bitmap is created and pointed to the current drawing buffer of the Surface.)

Also please keep in mind that, as this implies, a SurfaceView is a pretty heavy-weight object. If you have multiple SurfaceViews in a particular UI, stop and think about whether this is really needed. If you have more than two, you almost certainly have too many.

original source : https://stackoverflow.com/a/38496500

image

original source : https://stackoverflow.com/a/38496500

In one sentence, A Window is a rectangular area which has one view hierarchy. Colored rectangles in below image are windows.

image

As you can see, there can be multiple windows in one screen, and WindowManager manages them. 

According to Android Developer Documentation,

“Each activity is given a window in which to draw its user interface.”

and, Dianne Hackborn, who is a Android framework engineer, gave some definitions here. (1시간 분량) She said,

A window is basically like you think of a window on the desktop. It has a single Surface in which the contents of the window is rendered. An application interacts with the Window Manager to create windows; the Window Manager creates a Surface for each window and gives it to the application for drawing. The application can draw whatever it wants in the Surface; to the Window Manager it is just an opaque rectangle.

A Surface is an object holding pixels that are being composited to the screen. Every window you see on the screen (a dialog, your full-screen activity, the status bar) has its own surface that it draws in to, and Surface Flinger renders these to the final display in their correct Z-order. A surface typically has more than one buffer (usually two) to do double-buffered rendering: the application can be drawing its next UI state while the surface flinger is compositing the screen using the last buffer, without needing to wait for the application to finish drawing.

A View is an interactive UI element inside of a window. A window has a single view hierarchy attached to it, which provides all of the behavior of the window. Whenever the window needs to be redrawn (such as because a view has invalidated itself), this is done into the window’s Surface. The Surface is locked, which returns a Canvas that can be used to draw into it. A draw traversal is done down the hierarchy, handing the Canvas down for each view to draw its part of the UI. Once done, the Surface is unlocked and posted so that the just drawn buffer is swapped to the foreground to then be composited to the screen by Surface Flinger.

Also, I found some other info from Romain Guy’s presentation(You can watch his talk at San Francisco Android user group from here, and download full slides from here)

So, in a nutshell:

  • An Activity has a window (in which it draws its user interface),
  • a Window has a single Surface and a single view hierarchy attached to it,
  • a Surface include ViewGroup which holds views.

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

The Android Canvas, bitmap, paint에 관한 설명 1:00 부터 보면된다.

original source : https://stackoverflow.com/questions/9586032/android-difference-between-onintercepttouchevent-and-dispatchtouchevent

#1 answer

dispatchTouchEvent is actually defined on Activity, View and ViewGroup. Think of it as a controller which decides how to route the touch events.

For example, the simplest case is that of View.dispatchTouchEvent which will route the touch event to either OnTouchListener.onTouch if it’s defined or to the extension method onTouchEvent.

View, ViewGroup, Activity에 연결된 listener(위의 예시에서 OnTouchListener.onTouch)나 그 element내부에 가지고 있는 handler(위의 예시에서onTouchEvent)를 이용해 처리할수있는데 dispatchTouchEvent를 통해 어느 element가 처리할지가 결정되지 전까지 계속 이동하게(route) 된다.

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

참조사항) https://stackoverflow.com/a/12646163

The basic difference is that event handlers let the originating object itself do something in response to the event, whereas event listeners let other objects do something in response to events originating in the object.

For example: your activity has a button. If you want your activity to handle when someone touches the button, you use an event listener (by doing btn.setOnTouchListener(…)). BUT, if you want to create a specialized button (e.g. one that looks like a dog and barks when touched), you can create a subclass of Button and implement its event handler, onTouchEvent(…). In this latter case, the button itself will handle its touch event.

setOnTouchListener 를 통해 이벤트를 처리할 listener를 연결할수 있는데 이벤트를 처리할 listener가 view 그자체에 있지 않고 다른 element에 있을수 있다. 즉 element내에서 직접처리하지 않고 외부에 있는 경우 listener라고 한다. element내부에서 처리할수 있는 경우는이를 handler라고 하고 onTouchEvent()가 그 예시가 될수 있다. 

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

For ViewGroup.dispatchTouchEvent things are way more complicated. It needs to figure out which one of its child views should get the event (by calling child.dispatchTouchEvent). This is basically a hit testing algorithm where you figure out which child view’s bounding rectangle contains the touch point coordinates.

But before it can dispatch the event to the appropriate child view, the parent can spy and/or intercept the event all together. This is what onInterceptTouchEvent is there for. So it calls this method first before doing the hit testing and if the event was hijacked (by returning true from onInterceptTouchEvent) it sends a ACTION_CANCEL to the child views so they can abandon their touch event processing (from previous touch events) and from then onwards all touch events at the parent level are dispatched to onTouchListener.onTouch (if defined) or onTouchEvent(). Also in that case, onInterceptTouchEvent is never called again.

Would you even want to override [Activity|ViewGroup|View].dispatchTouchEvent? Unless you are doing some custom routing you probably should not.

The main extension methods are ViewGroup.onInterceptTouchEvent if you want to spy and/or intercept touch event at the parent level and View.onTouchListener/View.onTouchEvent for main event handling.

All in all its overly complicated design imo but android apis lean more towards flexibility than simplicity.

#2 answer

Because this is the first result on Google. I want to share with you a great Talk by Dave Smith on Youtube: Mastering the Android Touch System (이 동영상은 1시간분량)and the slides are available here. It gave me a good deep understanding about the Android Touch System:

How the Activity handles touch:

  • Activity.dispatchTouchEvent()
  • Always first to be called
  • Sends event to root view attached to Window
  • onTouchEvent()
  • Called if no views consume the event
  • Always last to be called

How the View handles touch:

  • View.dispatchTouchEvent()
  • Sends event to listener first, if exists
  • If not consumed, processes the touch itself
  • View.OnTouchListener.onTouch()
  • View.onTouchEvent()

How a ViewGroup handles touch:

  • ViewGroup.dispatchTouchEvent()
  • Intercepted events jump over the child step
  • onInterceptTouchEvent()
  • For each child view (in reverse order they were added)
  • If no children handles the event, the listener gets a chance
  • If there is no listener, or its not handled
  • Check if it should supersede children
  • Passes ACTION_CANCEL to active child
  • If it returns true once, the ViewGroup consumes all subsequent events
  • If touch is relevant (inside view), child.dispatchTouchEvent()
  • If it is not handled by a previous, dispatch to next view
  • OnTouchListener.onTouch()
  • onTouchEvent()

He also provides example code of custom touch on github.com/devunwired/.

Answer: Basically the dispatchTouchEvent() is called on every View layer to determine if a View is interested in an ongoing gesture. In a ViewGroup the ViewGroup has the ability to steal the touch events in his dispatchTouchEvent()-method, before it would call dispatchTouchEvent() on the children. The ViewGroup would only stop the dispatching if the ViewGroup onInterceptTouchEvent()-method returns true. The difference is that dispatchTouchEvent()is dispatching MotionEvents and onInterceptTouchEvent tells if it should intercept (not dispatching the MotionEvent to children) or not (dispatching to children).

You could imagine the code of a ViewGroup doing more-or-less this (very simplified):

public boolean dispatchTouchEvent(MotionEvent ev) {
    if(!onInterceptTouchEvent()){
        for(View child : children){
            if(child.dispatchTouchEvent(ev))
                return true;
        }
    }
    return super.dispatchTouchEvent(ev);
}

#3 answer 

image

original source : https://stackoverflow.com/a/26692768

The app namespace is not specific to a library, but it is used for all attributes defined in your app, whether by your code or by libraries you import, effectively making a single global namespace for custom attributes – i.e., attributes not defined by the android system.In this case, the appcompat-v7 library uses custom attributes mirroring the android: namespace ones to support prior versions of android (for example: android:showAsAction was only added in API11, but app:showAsAction (being provided as part of your application) works on all API levels your app does) – obviously using the android:showAsAction wouldn’t work on API levels where that attribute is not defined.

original source : https://stackoverflow.com/a/38493589

Xmlns stands for ‘XML Namespace’

  • The part after ’:’ is the prefix for the Namespace
  • The part after ’=’ is the Namespace URI (the correct name for his part is actually “Namespace name”).

(For further details see https://en.wikipedia.org/wiki/XML_namespace)

The namespace ‘schemas.android.com/tools’ is for specifying options to build the app by Android Studio, and are not included in the final app package

The namespace ‘schemas.android.com/apk/res-auto’ is used for all custom attributes – defined in libraries or in code. See this answer for details.

Note that any prefix can be used for a namespace, it is not mandatory to use ‘app’ for schemas.android.com/apk/res-auto. But the same prefix must be used when defining the custom attributes in the document, otherwise an error will be shown.

So, because met_maxCharacters is a custom attribute, it is shown when the ‘schemas.android.com/apk/res-auto’ namespace is used, and not with
‘schemas.android.com/tools’

original source : https://stackoverflow.com/a/22442702

The Android WindowManager is a system service, which is responsible for managing the z-ordered list of windows, which windows are visible, and how they are laid out on screen. Among other things, it automatically performs window transitions and animations when opening or closing an app or rotating the screen.

Every activity has a Window that is used to display its content on the screen. When you call setContentView on an activity, it attaches that view to the activity’s default window. The default window fills the screen, so that your activity’s window hides any other activities – the WindowManager will display whichever window is on top. So normally you don’t need to worry about windows – you just create an activity and Android will do the rest for you.

But you need to interact with the WindowManager if you want to do something unusual like create floating windows that don’t fill the screen. If you want to create a floating window that is visible in front of other applications, you can’t use an activity because your activity will stop when another app comes to the foreground, and its window will be hidden or destroyed. Instead you need to display a window from a background service. For example:

https://youtu.be/kRSIWh4WlMc?t=365

DrawerLayout 

의 사용예시를 보여준다.  DrawerLayout은 화면 양 옆에서 서랍처럼 등장하는 추가 layout을 만들수 있게 해준다. 이는 단순히 layout의 구조만을 만든다. 양쪽에서 등장하는 내용과는 무관하다. 이 서랍에 해당하는 부분에 NavigationView를 만들어 넣으면 아래와 같이 만들수 있다.  

NavigationView

는 menu xml화일을 이용해서 navigation menu를 생성한다. 

Navigation drawer template

은 아래 그림과 같이 android studio에서 주어지는 template이다.이를 통해 NavigationView, DrawerLayout 를 종합으로 사용한 구조를 만들수 있게 된다.

original source : https://ranyalbegwein.silvrback.com/transforming-image-behavior

참고자료 ) https://www.androidauthority.com/using-coordinatorlayout-android-apps-703720/

coordinatorlayout을 이용해서 구현가능한 작업 예시

1. Intro

A CoordinatorLayout is this thing:

public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent {
    ... 
}

from the support library ( compile 'com.android.support:design:25.3.1' ), which seems at first like an innocent old FrameLayout, until you discover its real powers – Behaviors!

CoordinatorLayout는 기본적으로 FrameLayout이다. 

A Behavior is an object attached to a child of a CoordinatorLayout, which defines its interaction with another View, ( a dependency) within the same layout.

CoordinatorLayout 아래에 있는 한 element가 다른 View(dependency라고 불리는) 의 변화에 따라 어떻게 변화할것인지를  정의하고 있는 object가 Behavior 이다. 상태변화가 관찰되어지는 View를 dependency라고 한다. 

So, a CoordinatorLayout monitors every movement of its children, and notifies the ones with attached Behaviors for a dependency change.

Something like this:

The SnackBar here is called a dependency – which makes sense, because the child depends on its movement in order to behave in a certain way specified by its attached Behavior.

Following Material Design guidelines, this behavior is the correct interaction between a SnackBar and a FloatingActionButton.

2. Let’s get started!

Everything should run in a context or under the supervision of a CoordinatorLayout, so let’s create a fresh Activity with a CoordinatorLayout as its content-view root element.

Create a new project, and add a new Activity by selecting the “Basic Activity” template:

Take a look at activity_main.xml, it should contain the following:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.rany.albeg.wein.behaviors.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

Since the default behavior of FloatingActionButton is to run away from the SnackBar like we wish to implement ourselves, take it off of the XML tree and insert something like an AppCompatButton:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout>

     ...

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/bt_click_me"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        android:text="Click me"/>

</android.support.design.widget.CoordinatorLayout>

Edit MainActivity accordingly, and modify onCreate():

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        AppCompatButton btn = (AppCompatButton) findViewById(R.id.bt_click_me);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Yeah buddy!", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

3. Implementation

To create a Behavior we’ll need to create a class that extends CoordinatorLayout.Behavior<V>where V is a type of a class which extends View and represents the type of the child – in our case it’ll be AppCompatButton:

public class CustomMoveUpBehavior extends 
                                  CoordinatorLayout.Behavior<AppCompatButton> {
    ...
}

We’re almost done! To complete programming our custom behavior and define the unique interaction between a child and a dependency, we’ll need to:

  • Override layoutDependsOn(...)

This method gets called ( at least once in response to a layout request ) by the parent CoordinatorLayout to determine whether the supplied child view has another specific sibling view as a layout dependency.
In other words, CoordinatorLayout sees the SnackBar and asks us :

“Hey, is this AppCompatButton depends on this SnackBar ?” and we should answer “Yes!” in order to further react in accordance to SnackBar’s movement:

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent,
                                   AppCompatButton child,
                                   View dependency) {

        return dependency instanceof Snackbar.SnackbarLayout;
    }

위의 코드를 설명하면 CoordinatorLayout내의 element 상태가 변화하면 CoordinatorLayout는 layoutDependsOn()를 통하여 View obj인 dependency가 Snackbar.SnackbarLayout instance인지 확인한다. 맞으면 true를 return한다. CoordinatorLayout는 자신의 모든 child element를 이 함수layoutDependsOn()에 넣어 해당 View가 dependency가 맞는지 아닌지 확인한다. 사실 layoutDependsOn()는 상태 변화에도 호출되지만 최초로 화면이 구성될때도 호출된다.

  • Override onDependentViewChanged(...)

This method gets called by the parent CoordinatorLayout after the relevant layoutDependsOn(...)returns true, in which we need to actually move stuff!

In our case, for the button to run away from the SnackBar, we’ll want to translate its Y position to be the difference between SnackBar’s current Y translation and its height!

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent,
                                          AppCompatButton child,
                                          View dependency) {

        float tY = dependency.getTranslationY() - dependency.getHeight();
        child.setTranslationY(tY);
        return true;
    }

위위의 코드 layoutDependsOn 의 과정을 거쳐 dependency의 변화가 관측되었다면 onDependentViewChanged()에 전달된 상태변화가 감지된 dependency와 그에 따라 조정이 필요한 child view를 함수내에서 조정한다.  

We return true to say: “Hey CoordinatorLayout! Our Behavior changed AppCompatButton’s position”

CustomMoveUpBehavior is done and ready to be attached!

There are several ways to attach a Behavior to View, and I’ll choose to go with the common way – via XML.

In order to attach CustomMoveUpBehavior to AppCompatButton via XML, add the following constructor first:

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

and now jump into activity_main.xml and just add the following attribute to AppCompatButton’s XML tag:

    <android.support.v7.widget.AppCompatButton
    ...
        app:layout_behavior="your.package.name.CustomMoveUpBehavior"
    ...
    />

replacing your.package.name as necessary.