Create an Android 3D stereo rotating container from scratch

Source: Internet
Author: User

This address, reproduced please specify http://blog.csdn.net/mr_immortalz/article/details/51918560

Well, 2 months did not write a blog, is to have a good reflection, take advantage of the summer vacation in the two months to see the things well settled down. Well, just set this flag, and I hope you don't hit your face again.

1. Overview

Back to the chase, the effect this time brings is an Android 3D stereo rotation effect.
The source of inspiration, of course, came from the earlier microblog.
Very cool with wood there! As a program ape, of course I'm going to add it to my next project!
Original effect

The effect we achieve:

(in order to be more customizable, I added new effects on the original image)

Can be scrolled quickly and with infinite loops

This is the setting of some parameters

Wrapping effect on a picture

Because it inherits itself from ViewGroup, the basic control can be wrapped.

2. Analysis
因为代码量有点大,感觉把代码全部粘贴上来也不现实。所以想了解我的思路的盆友可以先来这里下载代码。然后边看代码边看我的分析

: Https://github.com/ImmortalZ/StereoView

What we can realize is that:

1. When switching is a 3D stereo effect

2. Each item in the layout can be toggled freely, and infinite loop scrolling

What technical points do we need to solve the above effects?

1. To achieve a 3D effect, we can use the camera in Android, the Matrix

2. To achieve scrolling, there is no doubt that we need to use scroller

Of course everything looks very simple, but in addition, you also need to deal with the sliding conflict, and so on, I began to introduce.

That's what we've been doing for this project.

3. Implement
因为我们是要打造一个容器类,所以肯定得继承自 ViewGroup按照一般的思路,我们肯定是先要进行一些变量的申明,onMeasure,onLayout操作
private void init(Context context) {    mCamera = new Camera();    mMatrix = new Matrix();    if (mScroller == null) {        mScroller = new Scroller(context);    }}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    measureChildren(widthMeasureSpec, heightMeasureSpec);    mWidth = getMeasuredWidth();    mHeight = getMeasuredHeight();    //滑动到设置的StartScreen位置    scrollTo(0, mStartScreen * mHeight);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {    int childTop = 0;    for (int i = 0; i < getChildCount(); i++) {        View child = getChildAt(i);        if (child.getVisibility() != GONE) {            child.layout(0, childTop,                    child.getMeasuredWidth(), childTop + child.getMeasuredHeight());            childTop = childTop + child.getMeasuredHeight();        }    }}

After doing this, we need to handle the sliding event in the ontouchevent.

3.1 Complete infinite loop sliding scrolling

The number of our item is limited, how to achieve infinite cyclic scrolling? Very simple, with 3 item as an example (three to one), we let the screen show 2

So again, the position of the screen is always the 2nd item, which allows us to scroll with infinite loops and scroll down as well.

@Override PublicBooleanontouchevent(motioneventEvent) {if(Mvelocitytracker = =NULL) {Mvelocitytracker = Velocitytracker.obtain (); } mvelocitytracker.addmovement (Event);floaty =Event. GetY ();Switch(Event. Getaction ()) { CaseMotionevent.action_down:if(!mscroller.isfinished ()) {//When the last slide does not end, click again, Force swipe at the end of the click PositionMscroller.setfinaly (Mscroller.getcurry ());                    Mscroller.abortanimation (); ScrollTo (0, getscrolly ()); } mdowny = y; Break; CaseMotionevent.action_move:intRealdelta = (int) (MDOWNY-Y); Mdowny = y;if(Mscroller.isfinished ()) {//Because you want to cycle the scrollRecyclemove (Realdelta); } Break; CaseMotionEvent.ACTION_UP:mVelocityTracker.computeCurrentVelocity ( +);floatYvelocity = Mvelocitytracker.getyvelocity ();//slide faster than the specified speed, or swipe up, the previous page shows a height of more than 1/2. The setting state is State.topre                if(Yvelocity > Standerspeed | | ((getscrolly () + mheight/2)/Mheight < Mstartscreen) {mstate = State.topre; }Else if(Yvelocity <-standerspeed | | ((getscrolly () + mheight/2)/mheight > Mstartscreen)) {//slide faster than the specified speed, or swipe down, the next page shows a height of more than 1/2. The setting state is State.tonextMstate = State.tonext; }Else{mstate = State.normal; }//Change accordingly according to MstateChangebystate (yvelocity);if(Mvelocitytracker! =NULL) {mvelocitytracker.recycle (); Mvelocitytracker =NULL; } Break; }//Returns TRUE, consumes click events        return true; }

As the hand moves away from the screen, let's look at this method changebystate (yvelocity);

We use mstate = State.topre as an example to illustrate

/** * mState = State.ToPre 时进行的动作 * @param yVelocity 竖直方向的速度 */private void toPreAction(float yVelocity) {    int startY;    int delta;    int duration;    mState = State.ToPre;    addPre();//增加新的页面    //计算松手后滑动的item个数    int flingSpeed = (yVelocity - standerSpeed) > 0 ? (int) (yVelocity - standerSpeed) : 0;    addCount = flingSpeed / flingSpeed + 1;    //mScroller开始的坐标    startY = getScrollY() + mHeight;    setScrollY(startY);    //mScroller 移动的距离    delta = -(startY - mStartScreen * mHeight) - (addCount - 1) * mHeight;    duration = (Math.abs(delta)) * 3;    mScroller.startScroll(0, startY, 0, delta, duration);    addCount--;}

And then it goes into the Addpre method.

/** * 把最后一个item移动到第一个item位置 */private void addPre() {    mCurScreen = ((mCurScreen - 1) + getChildCount()) % getChildCount();    int childCount = getChildCount();    View view = getChildAt(childCount - 1);    removeViewAt(childCount - 1);    addView(view, 0);    if (iStereoListener != null) {        iStereoListener.toPre(mCurScreen);    }}

Last Mscroller.startscroll (0, starty, 0, Delta, duration); Start execution.
This function method is recalled during execution Computescroll

To complete this step, our infinite sliding scrolling is done even

3.2 Achieve 3D switching effect.

Under normal circumstances, we do not need to override the Dispatchdraw method to customize ViewGroup.
And here we need to rewrite

 @Override    protected void Dispatchdraw(Canvas canvas) {if(!isadding && iscan3d) {//When the 3D effect is turned on and the current state does not belong to Computescroll addpre () or AddNext ()            //If you do not make this judgment, Addpre () or AddNext () the page will flash a bit            //I was written by this hole, and later through the log judge, the original is computescroll in the onlayout, and child children draw trigger order caused.             //The friend who knows the principle wants to be able to tell the next             for(inti =0; I < Getchildcount ();            i++) {Drawscreen (canvas, I, getdrawingtime ()); }        }Else{isadding =false;Super. Dispatchdraw (canvas); }    }

Okay, let's drawscreen this method.

Private void Drawscreen(Canvas canvas,intILongDrawingtime) {intCurscreeny = Mheight * i;//The parts not displayed in the screen are not drawn        if(getscrolly () + Mheight < Curscreeny) {return; }if(Curscreeny < getscrolly ()-Mheight) {return; }floatCenterX = mwidth/2;floatCenterY = (getscrolly () > Curscreeny)? Curscreeny + Mheight:curscreeny;floatdegree = MAngle * (getscrolly ()-Curscreeny)/mheight;if(Degree > -|| Degree <- -) {return;        } canvas.save ();        Mcamera.save ();        Mcamera.rotatex (degree);        Mcamera.getmatrix (Mmatrix);        Mcamera.restore ();        Mmatrix.pretranslate (-centerx,-centery);        Mmatrix.posttranslate (CenterX, centery);        Canvas.concat (Mmatrix);        Drawchild (canvas, Getchildat (i), drawingtime);    Canvas.restore (); }

the key to this is
Mcamera.rotatex (degree);
Mmatrix.pretranslate (-centerx,-centery);
Mmatrix.posttranslate (CenterX, centery);

For camera we know that our entire layout is tiled, why does it produce 3D effect? The reason is that the camera class, the name of the person, it is equivalent to a camera, it takes pictures of objects. We are shooting the camera on the object, the effect is the plane, when we rotate the camera 90 degrees to shoot the original object, the object is equivalent to rotation of 90 degrees.
After the camera is shot, the values of the captured parameters are then uploaded to the matrix, and the matrix is then bound to the canvas and drawn by the canvas. is finally displayed in the screen.

So what's the matter with pretranslate,posttranslate?
Very simply, we know that the coordinate system is (0,0) as the reference point. Now the scaling of the objects we have taken is at the center of the object. We need to move the center of the object first to the (0,0) position and then to the original center position of the object.

Specifically, you can refer to this article
http://blog.csdn.net/rav009/article/details/7763223 (understanding of Android posttranslate and Pretranslate)

But I have a little bit of a problem with the camera's coordinate system, and I'm ready to write an article about camera and matrix.

3.3 Handling of sliding event collisions

Complete the two steps above, so we're over?

No! Another important point is the handling of event conflicts. For example: if we put our hands on our container, how does the system know if we are going to give the container or the sub-class to the container?

(to the container itself, then the operation of sliding, to the sub-class of the container, then the sub-class of the container can be a click event judgment processing)

For this situation, I am very generous, all to the container sub-class processing! Subclass do not, OK, the container you take to play it.

———— do not take the usual way: to the container handling, the container does not need to be handed over to subclasses

The reason is: the container to get the sliding event only need to do sliding operations, and the sub-class is different, it has a click event needs to be judged, a container has a lot of subclasses, and many subclasses have only a common container, if the control to the container, then how can the container can determine whether the different sub-classes need this sliding event? So, since this is so troublesome, then all of them are handed over to the sub-class.

To subclass processing, the onintercepttouchevent in the container needs to do the following:

@Override    publicbooleanonInterceptTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            returnfalse;        }        returntrue;    }

and subclasses (using Customedittext as an example) Dispatchtouchevent need to make the following judgments

@Override PublicBooleandispatchtouchevent(motioneventEvent) {Switch(Event. Getaction ()) { CaseMotionEvent.ACTION_DOWN:getParent (). Requestdisallowintercepttouchevent (true); Break; CaseMotionevent.action_move:if(!iscontain (Event)) {//subclass does not need to be handled by the container itselfGetParent (). Requestdisallowintercepttouchevent (false); Setfocusable (false); }Else{//Sub-class do the operation yourselfSetfocusableintouchmode (true); } Break; CaseMOTIONEVENT.ACTION_UP: Break; }returnSuper.dispatchtouchevent (Event); }

In Iscontain, what I do is whether the clicked coordinates are in the EditText, then the Intercept, subclass processing, not, then to the parent class container

privateisContainevent) {        region.set(rect);        if (region.contains((intevent.getX(), (intevent.getY())) {            returntrue;        }        returnfalse;    }

of course, to the subclass. This also leads to the problem that I need to customize a view if I need to do a click event for a subclass in the container(for example, Customedittext inherits from EditText).

For example, I've customized three view, but it's quite simple, and a few minutes will be done (dispatchtouchevent in Custom view).

Specifically, you can refer to the code.

3.4 Click on the watermark effect

Careful people will find that I have a rippleview here.
That's right. This is the effect of a wave after a click.
Android itself can be implemented in XML with Ripple, but Android 5.0 or more, the individual feel that compatibility is not very good, I casually write a simple, haha, efficiency can not be guaranteed, you look at the spectators just fine.

4. Application

4.1 Method of Definition

The use of the method is no different from the other, I am here to customize a few methods, I explained below.

Customizing the method

setstartscreen (int startscreen) : Sets the page shown on the first page @param startscreen (0,getchildcount-1)

setresistance (float resistance) : Set sliding resistance @param resistance (0,...)

setinterpolator (interpolator minterpolator) : interpolator interpolation when setting scrolling

Setangle (float mAngle): Sets the number of clip angles for two item when scrolling [0f,180f]

setcan3d (Boolean can3d) : Whether 3D effect is turned on

setitem (int itemId) : Jumps to the specified item @param itemId [0,getchildcount-1]

Topre () : prev

Tonext () : Next page

Defines the callback interface

4.2 How to use

Directly in the layout

In the Code

4.3 Defect description

The current container's item number needs to be greater than or equal to 3, less than 3 slippage will be a problem. The item position at the beginning of the setting cannot be the first or last, and this is done to ensure that the 1th or last one is hidden so that it is normal to start up or slide down.

5. Download

If it feels helpful to you, welcome star,fork, if interested in me, welcome follow me

: Https://github.com/ImmortalZ/StereoView

Create an Android 3D stereo rotating container from scratch

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.