I study Android in combination with the source code, which is more intuitive and very clear to see the effect. I think it's very good. Today's learning source code is the source code found online. Baidu search knows many places to download. The name of the online source code is Android drawer effect zip my blog is messy. If I don't understand this article,
Please read the previous article first. The addresses are:
Gesture recognition: http://blog.csdn.net/u014737138/article/details/40950431
Animation monitoring: http://blog.csdn.net/u014737138/article/details/40952373
onLayout function that needs to be overloaded to inherit LinearLayout class: http://blog.csdn.net/u014737138/article/details/40951087
The onFinishInflate function that needs to be overloaded to inherit the LinearLayout class: http://blog.csdn.net/u014737138/article/details/40951985
First of all, we need to talk about the whole process, that is, the principle of implementation. Before we talk about PPT, we should first tell the audience what to do next, what points to make, and what steps to follow?
First: we need to make it clear that to achieve the above drawer effect, we must first define a layout designed by ourselves,
The method we implement is to inherit the LinearLayout class
public class Panel extends LinearLayout {
Three things must be done to inherit this class:
1. The constructor needs to be rewritten:
Generally, when the function draw () and the function dispatch2 () are overloaded, they are used to draw images
3. Overload onLayout() function:
4. Overload onFinsihInflate() function:
1. Implementation of constructor:
public Panel(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel);//Load properties from the layout file into this array mDuration = a.getInteger(R.styleable.Panel_animationDuration, 750); //Animation time mPosition = a.getInteger(R.styleable.Panel_position, BOTTOM); //Drawer position mLinearFlying = a.getBoolean(R.styleable.Panel_linearFlying, false); mOpenedHandle = a.getDrawable(R.styleable.Panel_openedHandle);//Open background mClosedHandle = a.getDrawable(R.styleable.Panel_closedHandle);//Close background a.recycle();//Remember to recycle when the array is used up mOrientation = (mPosition == TOP || mPosition == BOTTOM) ? VERTICAL : HORIZONTAL;//Direction, according to the position obtained from the layout file, it should be the vertical direction setOrientation(mOrientation);//Then set the layout file to this direction mState = State.READY;//The current drawer status is ready mGestureListener = new PanelOnGestureListener();//Gesture monitoring object mGestureDetector = new GestureDetector(mGestureListener);//Initialization of gesture recognition object mGestureDetector.setIsLongpressEnabled(false);//Gesture recognition does not accept long press message status processing }
Analyze and write some codes in this:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel);
//Load properties from the layout file into this array
About r.styleable The knowledge point of panel is mentioned in the previous topic. It will not be introduced here. You can read my article
The address is: http://blog.csdn.net/u014737138/article/details/40789899
Here we need to pay attention to what is in this XML file:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Panel"> <!-- Defines panel animation duration in ms. --> <attr name="animationDuration" format="integer" /> <!-- Defines panel position on the screen. --> <attr name="position"> <!-- Panel placed at top of the screen. --> <enum name="top" value="0" /> <!-- Panel placed at bottom of the screen. --> <enum name="bottom" value="1" /> <!-- Panel placed at left of the screen. --> <enum name="left" value="2" /> <!-- Panel placed at right of the screen. --> <enum name="right" value="3" /> </attr> <!-- Defines if flying gesture forces linear interpolator in animation. --> <attr name="linearFlying" format="boolean" /> <!-- Defines opened handle (drawable/color). --> <attr name="openedHandle" format="reference|color" /> <!-- Defines closed handle (drawable/color). --> <attr name="closedHandle" format="reference|color" /> </declare-styleable> <declare-styleable name="SmoothButton"> <attr name="transitionDrawable" format="reference" /> <attr name="transitionDrawableLength" format="integer" /> <attr name="transitionTextColorUp" format="color" /> <attr name="transitionTextColorDown" format="color" /> </declare-styleable> </resources>
At attrs Two < declare styleable > tags are defined in the XML file:
1.<declare-styleable name="Panel">
2.<declare-styleable name="SmoothButton">
Both are automatically generated in the class of R.styleable, It should be noted that there is a knowledge point: when the TypedArray array is used up, remember to recycle it at any time
How many things does this constructor handle?
1. Load properties
2. Determine the direction of layout
3. Determine the status of the drawer
4. Processing of gesture recognition transactions
We'll talk about these four things later. Let's finish what must be done first, that is, the functions that must be overloaded when we inherit the LinearLayout class:
2. Overload draw() function:
@Override protected void dispatchDraw(Canvas canvas) { // String name = getResources().getResourceEntryName(getId()); // Log.d(TAG, name + " ispatchDraw " + mState); // this is why 'mState' was added: // avoid flicker before animation start if (mState == State.ABOUT_TO_ANIMATE && !mIsShrinking) { int delta = mOrientation == VERTICAL ? mContentHeight : mContentWidth; if (mPosition == LEFT || mPosition == TOP) { delta = -delta; } if (mOrientation == VERTICAL) { canvas.translate(0, delta); } else { canvas.translate(delta, 0); } } if (mState == State.TRACKING || mState == State.FLYING) { canvas.translate(mTrackX, mTrackY); } super.dispatchDraw(canvas); }
The first thing this code judges is the state: draw the drawer only when it is ready. When is it ready? It must be that the current view containing drawers is opened by the user, that is, it is visible. That is, you can open it only when you see the drawer. If you don't see it, do you still talk about opening it?
The variable mIsShrinking: represents whether the current component is hidden. The existence of this variable is mainly to prevent us from not knowing the size of the component and whether the component is visible on the interface shown to us. The second reason is whether the drawer is visible
canvas.translate(0, delta);
//The translate(float x,float y) function moves the entire canvas x horizontally and Y vertically. The function of scrolling can be realized through the translate function.
Knowing the function of this function, let's look at the variable of delta type int:
int delta = mOrientation == VERTICAL ? mContentHeight : mContentWidth; if (mPosition == LEFT || mPosition == TOP) { delta = -delta; }
If the drawer direction is vertical: delta is the height of the whole view
If the drawer direction is horizontal: delta is the width of the whole view
The next step is how to display the drawer on the canvas, also according to the direction:
if (mOrientation == VERTICAL) { canvas.translate(0, delta); } else { canvas.translate(delta, 0); }
If the drawer direction is vertical: the canvas moves horizontally by 0 pixels, that is, it does not move horizontally; The canvas moves the height of the view vertically, that is, the vertical direction is the same as the interface
If the drawer direction is horizontal: move the canvas horizontally by pixels, that is, the horizontal direction is the same width as the interface; Move 0 pixels in the vertical direction, that is, do not move in the vertical direction
At this point, the position of the drawer is very clear. The above is the layout position of the drawer in the initialization state. If I click the button with my finger, I will pull the "buckle"
The layout needs to be redrawn, and this function will be reloaded. Then we must update the view at any time according to the status of the drawer:
if (mState == State.TRACKING || mState == State.FLYING) { canvas.translate(mTrackX, mTrackY); }
When the drawer is open or closed, the process is like the process of scaling the canvas outside or inside,
Using code to handle this is the process of moving the canvas:
As for the coordinate at this time, it is the monitoring event in gesture recognition to process this coordinate
2. Overload onLayout() function:
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mContentWidth = mContent.getWidth(); mContentHeight = mContent.getHeight(); }
Set the custom layout, that is, the width and height of the drawer. You can see from the function that the width and height are determined by the parameter mConten and assigned to mContentWidth
So we need to care about the meaning of these variables. Let's put it here first,
3. Overload onFinsihInflate() function:
@Override protected void onFinishInflate() { super.onFinishInflate(); mHandle = findViewById(R.id.panelHandle); if (mHandle == null) { throw new RuntimeException( "Your Panel must have a View whose id attribute is 'R.id.panelHandle'"); } mHandle.setOnTouchListener(touchListener); mContent = findViewById(R.id.panelContent); if (mContent == null) { throw new RuntimeException( "Your Panel must have a View whose id attribute is 'R.id.panelContent'"); } // reposition children removeView(mHandle); removeView(mContent); if (mPosition == TOP || mPosition == LEFT) { addView(mContent); addView(mHandle); } else { addView(mHandle); addView(mContent); } if (mClosedHandle != null) { mHandle.setBackgroundDrawable(mClosedHandle); } mContent.setVisibility(GONE); }
This function is used to obtain the reference of the control on the drawer view,
Here are two IDS, which correspond to two components respectively. We need to see how this id is defined:
The first is in IDS Defined in XML:
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="panelHandle" type="id"/> <item name="panelContent" type="id"/> </resources>
2. Then main. In the main layout file These two IDs are required in XML:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:panel="http://schemas.android.com/apk/res/com.wust.slidingdrawfromleft" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#767c9b" android:orientation="vertical" > <com.wust.slidingdrawfromleft.activity.Panel android:id="@+id/leftPanel1" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_gravity="left" android:layout_weight="1" panel:closedHandle="@drawable/left_switcher_collapsed_background" panel:openedHandle="@drawable/left_switcher_expanded_background" panel:position="left" > <Button android:id="@id/panelHandle" android:layout_width="33dip" android:layout_height="fill_parent" /> <LinearLayout android:id="@id/panelContent" android:layout_width="wrap_content" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="fill_parent" android:background="#999932" android:gravity="center" android:padding="18dip" android:text="This" android:textColor="#eee" android:textSize="16dip" android:textStyle="bold" /> </LinearLayout> </com.wust.slidingdrawfromleft.activity.Panel> </LinearLayout>
You can see what two controls are used:
1. < button Android: id = "@ ID / panelhandle" means to click the button of the drawer, that is, the buckle like the real drawer
2. < LinearLayout Android: id = "@ ID / panelcontent" stands for the box of the drawer, that is, it is a rectangle with a large area like the real drawer, which can hold a lot of things
So let's take a look at the two controls shown on the rendering?
In other words, we know the role of two variables:
1.mHandle: represents the "buckle" of the drawer, that is, a button. When the user clicks, it can open the "drawer" and click again to close the "drawer"
2.mContent: represents the rectangle in the drawer, that is, a layout. Programmers can load their own layout style in it, and put many buttons, textviews, etc
Next, let's see what it does:
When the "buckle" button is found, monitor its monitoring events immediately:
mHandle.setOnTouchListener(touchListener);
Then there is the following rearrangement:
removeView(mHandle); removeView(mContent);
Delete this component first and reload it in the set direction:
If (mposition = = TOP | mposition = = LEFT) {/ / the direction is TOP or LEFT addView(mContent); addView(mHandle); }else {/ / the direction is BOTTOM or RIGHT addView(mHandle); addView(mContent); }
If the user doesn't click on the things in the front drawer, you can't show it to the user:
mContent.setVisibility(GONE);
At the same time, the background image of this drawer must be set
if (mClosedHandle != null) { mHandle.setBackgroundDrawable(mClosedHandle); }
After completing the above construction and necessary overloading, we will complete the implementation of the whole layout, that is, inherit LinearLayout. At least for now, we can show this effect,
What we need to deal with now is the listening event processing of the control, the calculation of the mouse, and so on
At this time, we first return to the Draw() function: there is a code that is the listening event of the button "buckle":
mHandle.setOnTouchListener(touchListener);// As mentioned above, this mhandle object represents the button of the buckle. Users can click it to close and open the drawer
The parameter is: touchListener. I won't repeat the monitoring events of the button here. Beginners can see my previous articles
Address: http://blog.csdn.net/u014737138/article/details/40478027
Here is the practice in this case: it mainly monitors whether the drawer is opened or closed
OnTouchListener touchListener = new OnTouchListener() { int initX; int initY; boolean setInitialPosition; public boolean onTouch(View v, MotionEvent event) { // Log.d(TAG, "state: " + mState + " x: " + event.getX() + " y: " + // event.getY()); int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { initX = 0; initY = 0; if (mContent.getVisibility() == GONE) { // since we may not know content dimensions we use factors // here if (mOrientation == VERTICAL) { initY = mPosition == TOP ? -1 : 1; } else { initX = mPosition == LEFT ? -1 : 1; } } setInitialPosition = true; } else { if (setInitialPosition) { // now we know content dimensions, so we multiply factors... initX *= mContentWidth; initY *= mContentHeight; // ... and set initial panel's position mGestureListener.setScroll(initX, initY); setInitialPosition = false; // for offsetLocation we have to invert values initX = -initX; initY = -initY; } // offset every ACTION_MOVE & ACTION_UP event event.offsetLocation(initX, initY); } if (!mGestureDetector.onTouchEvent(event)) { if (action == MotionEvent.ACTION_UP) { // tup up after scrolling post(startAnimation); } } return false; } };
Event handling of OnTouchListener for gesture recognition: We can get the type of Touch event through getAction() method of MotionEvent, including ACTION_DOWN, ACTION_MOVE (move the force point after pressing the Touch screen), ACTION_UP (release the Touch screen)
Variables of this function: boolean setInitialPosition// If we click the direction, this variable represents opening the drawer. If we click again, this variable represents closing
if (mContent.getVisibility() == GONE) { // since we may not know content dimensions we use factors // here if (mOrientation == VERTICAL) { initY = mPosition == TOP ? -1 : 1; } else { initX = mPosition == LEFT ? -1 : 1; } }
//If the current view is not visible, the main worry is: we don't know the size of the current response control. Need to make a judgment
When the drawer cannot be seen, we need to set the X and Y coordinates of the drawer canvas to (- 1, - 1)
setInitialPosition = true;// If the gesture is pressed, the direction is determined and set to true Close drawer:
if (setInitialPosition) {//The direction is determined // now we know content dimensions, so we multiply factors... initX *= mContentWidth;//Initializes the size of the current response control: width and height initY *= mContentHeight; // ... and set initial panel's position / / the position of the panel is set here mGestureListener.setScroll(initX, initY);//Trigger the gesture recognition event and set the range of gesture sliding setInitialPosition = false;//Then set the direction to false // for offsetLocation we have to invert values initX = -initX; initY = -initY; } // offset every ACTION_MOVE & ACTION_UP event event.offsetLocation(initX, initY);
This process corresponds to action_ MOVE & ACTION_ UP event
event. Offset location view for offset restore for next use
When we open the "ring buckle", we need to deal with the business, that is, open the drawer and hand it over to the following code:
if (!mGestureDetector.onTouchEvent(event)) {//Gesture recognition captures gesture types if (action == MotionEvent.ACTION_UP) {//Release the touch screen) // tup up after scrolling post(startAnimation); } }
Function post(startAnimation); From the parameters, we can see that this is an animation. Why use animation? Let's talk about it with effect:
Not open
Open this process
Canvas is a slow moving process, where there is an animation process:
This function is a function of a View class, which will call the thread to execute. Regardless of this function, let's see the animation and how we do it:
Runnable startAnimation = new Runnable() { public void run() { // this is why we post this Runnable couple of lines above: // now its save to use mContent.getHeight() && mContent.getWidth() TranslateAnimation animation; int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0; if (mState == State.FLYING) { mIsShrinking = (mPosition == TOP || mPosition == LEFT) ^ (mVelocity > 0); } int calculatedDuration; if (mOrientation == VERTICAL) { int height = mContentHeight; if (!mIsShrinking) { fromYDelta = mPosition == TOP ? -height : height; } else { toYDelta = mPosition == TOP ? -height : height; } if (mState == State.TRACKING) { if (Math.abs(mTrackY - fromYDelta) < Math.abs(mTrackY - toYDelta)) { mIsShrinking = !mIsShrinking; toYDelta = fromYDelta; } fromYDelta = (int) mTrackY; } else if (mState == State.FLYING) { fromYDelta = (int) mTrackY; } // for FLYING events we calculate animation duration based on // flying velocity // also for very high velocity make sure duration >= 20 ms if (mState == State.FLYING && mLinearFlying) { calculatedDuration = (int) (1000 * Math .abs((toYDelta - fromYDelta) / mVelocity)); calculatedDuration = Math.max(calculatedDuration, 20); } else { calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; } } else { int width = mContentWidth; if (!mIsShrinking) { fromXDelta = mPosition == LEFT ? -width : width; } else { toXDelta = mPosition == LEFT ? -width : width; } if (mState == State.TRACKING) { if (Math.abs(mTrackX - fromXDelta) < Math.abs(mTrackX - toXDelta)) { mIsShrinking = !mIsShrinking; toXDelta = fromXDelta; } fromXDelta = (int) mTrackX; } else if (mState == State.FLYING) { fromXDelta = (int) mTrackX; } // for FLYING events we calculate animation duration based on // flying velocity // also for very high velocity make sure duration >= 20 ms if (mState == State.FLYING && mLinearFlying) { calculatedDuration = (int) (1000 * Math .abs((toXDelta - fromXDelta) / mVelocity)); calculatedDuration = Math.max(calculatedDuration, 20); } else { calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth; } } mTrackX = mTrackY = 0; if (calculatedDuration == 0) { mState = State.READY; if (mIsShrinking) { mContent.setVisibility(GONE); } postProcess(); return; } animation = new TranslateAnimation(fromXDelta, toXDelta,fromYDelta, toYDelta); animation.setDuration(calculatedDuration); animation.setAnimationListener(animationListener); if (mState == State.FLYING && mLinearFlying) { animation.setInterpolator(new LinearInterpolator()); } else if (mInterpolator != null) { animation.setInterpolator((android.view.animation.Interpolator) mInterpolator); } startAnimation(animation); } };
We need to focus on four variables:
int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0;
What do these four variables represent,? We have defined a moving animation object above. The four parameters are required for the construction of TranslateAnimation:
The previous article introduces: Address: http://blog.csdn.net/u014737138/article/details/40861929
fromXDelta At the beginning of the animation X Position on coordinates toXDelta At the end of the animation X Position on coordinates fromYDelta At the beginning of the animation Y Position on coordinates toYDelta At the end of the animation Y Position on coordinates
Animation start coordinates to end coordinates, that is, many of our codes calculate the coordinates of animation.
if (mState == State.FLYING) { mIsShrinking = (mPosition == TOP || mPosition == LEFT) ^ (mVelocity > 0); }
If the state is moving, we use the speed to determine whether it is hidden. mIsShrinking is a Boolean variable int calculatedDuration;// The duration of animation, that is, how long the drawer is opened and the whole process of changing the two pictures
Vertical direction: duration
if (mState == State.FLYING && mLinearFlying) { calculatedDuration = (int) (1000 * Math .abs((toYDelta - fromYDelta) / mVelocity)); calculatedDuration = Math.max(calculatedDuration, 20); } else { calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; }
Distance / speed = time. I believe you can understand this code, Vertical direction: coordinate calculation:
int height = mContentHeight; if (!mIsShrinking) { fromYDelta = mPosition == TOP ? -height : height; } else { toYDelta = mPosition == TOP ? -height : height; } if (mState == State.TRACKING) { if (Math.abs(mTrackY - fromYDelta) < Math.abs(mTrackY - toYDelta)) { mIsShrinking = !mIsShrinking; toYDelta = fromYDelta; } fromYDelta = (int) mTrackY; } else if (mState == State.FLYING) { fromYDelta = (int) mTrackY; }
Snap coordinates:
private PanelOnGestureListener mGestureListener;//Gesture monitoring object Its definition: class PanelOnGestureListener implements OnGestureListener {//This class implements the gesture listener, so you need to overload the necessary functions float scrollY;//Scrolling coordinates Y float scrollX;//Scrolling coordinate X public void setScroll(int initScrollX, int initScrollY) {//Set function scrollX = initScrollX; scrollY = initScrollY; } public boolean onDown(MotionEvent e) {//Gesture press / / the user lightly touches the touch screen, which is composed of 1 MotionEvent ACTION_DOWN trigger scrollX = scrollY = 0; if (mState != State.READY) {//The current state is not ready. The animation operation will begin soon // we are animating or just about to animate return false; } mState = State.ABOUT_TO_ANIMATE;//The state changes to preparing to place animation mIsShrinking = mContent.getVisibility() == VISIBLE;//If the screen is currently visible, return true, otherwise return false, that is, we can display the drawer effect only after entering the interface with drawer effect if (!mIsShrinking) { // this could make flicker so we test mState in dispatchDraw() // to see if is equal to ABOUT_TO_ANIMATE mContent.setVisibility(VISIBLE);//If the current screen is not visible, we set it to visible } return true; } // After the user presses the touch screen and moves quickly, it is released by 1 MotionEvent ACTION_DOWN, multiple actions_ Move, 1 ACTION_UP trigger public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {//Sliding processing function mState = State.FLYING;//The status is sliding mVelocity = mOrientation == VERTICAL ? velocityY : velocityX;//The speed setting depends on whether the direction is Y direction or X direction. If it is vertical, it is Y direction. If it is not vertical or horizontal, it is x direction post(startAnimation);//Execute animation return true; } // The user long presses the touch screen and multiple motionevent actions_ Down trigger public void onLongPress(MotionEvent e) {//The gesture is a long press and does not need to be handled // not used } // The user presses the touch screen and drags it by one MotionEvent ACTION_DOWN, multiple actions_ Move trigger public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {//roll mState = State.TRACKING;//Gestures are moving float tmpY = 0, tmpX = 0;//Temporary variable if (mOrientation == VERTICAL) {//Is a vertical scroll scrollY -= distanceY;//The coordinate Y of the scroll is always changing if (mPosition == TOP) {//If the current position is at the top tmpY = ensureRange(scrollY, -mContentHeight, 0);//Specify the range within which Y can be moved } else {//The direction is the bottom tmpY = ensureRange(scrollY, 0, mContentHeight); } } else {//If horizontal scrollX -= distanceX;//It refers to the coordinates in the X direction if (mPosition == LEFT) {//The direction is left tmpX = ensureRange(scrollX, -mContentWidth, 0); } else {//The direction is to the right tmpX = ensureRange(scrollX, 0, mContentWidth); } } // When the values of X and Y directions are determined, you need to see whether this value is equal to the coordinates of your finger movement, that is, set the gesture coordinates if (tmpX != mTrackX || tmpY != mTrackY) { mTrackX = tmpX;//Set the X coordinate in finger movement mTrackY = tmpY;//Set the Y coordinate in finger movement invalidate();//update the view } return true; } /* * The user lightly touches the touch screen, which has not been released or dragged by one MotionEvent ACTION_DOWN trigger * Note the difference from onDown(), which emphasizes that there is no state of loosening or dragging */ public void onShowPress(MotionEvent e) { // not used } // The user (after touching the touch screen) releases it, which is controlled by one MotionEvent ACTION_UP trigger public boolean onSingleTapUp(MotionEvent e) { // simple tap: click post(startAnimation); return true; } }
About GestureListener, please see my article above
After the coordinates are calculated, we start the animation:
animation = new TranslateAnimation(fromXDelta, toXDelta,fromYDelta, toYDelta); animation.setDuration(calculatedDuration); animation.setAnimationListener(animationListener); if (mState == State.FLYING && mLinearFlying) { animation.setInterpolator(new LinearInterpolator()); } else if (mInterpolator != null) { animation.setInterpolator((android.view.animation.Interpolator) mInterpolator); } startAnimation(animation);
Here we need to learn the monitoring events of animation. Please see the previous article
Handling of listening events for Animation:
private AnimationListener animationListener = new AnimationListener() { public void onAnimationEnd(Animation animation) {//End of animation mState = State.READY; if (mIsShrinking) { mContent.setVisibility(GONE); } postProcess(); } public void onAnimationRepeat(Animation animation) {//Animation restart } public void onAnimationStart(Animation animation) {//Animation start mState = State.ANIMATING; } };
The picture changes are:
Not open
Open postProcess():
private void postProcess() { if (mIsShrinking && mClosedHandle != null) { mHandle.setBackgroundDrawable(mClosedHandle); } else if (!mIsShrinking && mOpenedHandle != null) { mHandle.setBackgroundDrawable(mOpenedHandle); } // invoke listener if any if (panelListener != null) { if (mIsShrinking) { panelListener.onPanelClosed(Panel.this); } else { panelListener.onPanelOpened(Panel.this); } } }
The panelListener variable is a callback function interface type of user-defined view:
/** * Callback invoked when the panel is opened/closed. */ public static interface OnPanelListener { /** * Invoked when the panel becomes fully closed. */ public void onPanelClosed(Panel panel); /** * Invoked when the panel becomes fully opened. */ public void onPanelOpened(Panel panel); }
Variable definitions required for the whole program:
private boolean mIsShrinking;//Shrinking means hiding drawers private int mPosition;//Position, that is, the position of the drawer, left, right, up and down private int mDuration;//Time required to open and close a drawer private boolean mLinearFlying; private View mHandle;//The subcomponent button on the view, that is, the "buckle" private View mContent;//Rectangle representing drawer private Drawable mOpenedHandle;//Show drawer background private Drawable mClosedHandle;//Close drawer background private float mTrackX;//x coordinate of gesture drag private float mTrackY; private float mVelocity;//speed private OnPanelListener panelListener;//Callback function listening object public static final int TOP = 0; public static final int BOTTOM = 1; public static final int LEFT = 2; public static final int RIGHT = 3; private enum State { ABOUT_TO_ANIMATE, ANIMATING, READY, TRACKING, FLYING, }; private State mState;//Corresponding to the above four dynamics private Interpolator mInterpolator;//Interpolator private GestureDetector mGestureDetector;//gesture recognition private int mContentHeight;//Drawer height private int mContentWidth;//Width of drawer private int mOrientation;//direction private PanelOnGestureListener mGestureListener;//Gesture monitoring object
That's it. It's too long. It's been written for a long time and hasn't been sorted out. The ability to write articles needs to be improved. Let's see It's estimated that you didn't speak clearly, and some made mistakes. Please point out the mistakes in your study
Source address: http://download.csdn.net/detail/u014737138/8139417