[Kaizige takes you to consolidate the application layer] All of them say "Zhi Hu" is too high. We will achieve "Zhi Hu" to answer the details page animation effect and consolidate the application layer
Reprinted please indicate the source: http://blog.csdn.net/zhaokaiqiang1992
2014 is far away. The goal in 2015 is to continue to be familiar with the upper-layer APIs of Android. Although the FrameWork Code is occasionally studied for a certain problem, for new users like us, only when you are familiar with the APIS at the upper layer can you better study the principle. Therefore, this year's task is to continue to learn and study the use of Android's upper-layer APIs. By the way, I wrote a graduation thesis and completed my career.
Okay. From the beginning of this article, we will start the series []. If you have any interface effects or any questions during development, please trust me, if I think it is better, I will implement it myself, and then write a blog to share with you the Implementation ideas.
Not to mention nonsense. Our first article is to imitate the animation effect of "zhihu"'s answer details page. First, the original version is used to make this effect.
Before implementation, we will first study the requirements based on the above animation effects. because the number of gif frames is limited, it is not very consistent. We recommend you download a zhihu directly and find this interface to play it yourself.
☞After the article is moved up to a certain position, the top Title Bar and question layout Title are hidden, and the Author layout of the respondent is not hidden.
☞When the article moves down to a certain position, the original hidden Title Bar and problem layout Title will decrease and display
☞When the document moves up, the hidden Tools layout in the lower part is displayed.
☞When the document moves down, if the layout of Tools is displayed, it is hidden.
☞When the Title Bar and problem layout Title drop, the Title is displayed from below the Bar, with a blocking effect
☞The hidden Tools are displayed when the content is quickly slide to the bottom.
☞When the content is quickly swiped to the top, the hidden Bar and Title are displayed.
Without analysis, I don't know. This simple result requires many things to be done after analysis. So let's analyze the solution based on the needs to be implemented.
Before doing this kind of imitation interface, we can use the View Hierarchy tool of ADT to see how the native "zhihu" is implemented.
From the analysis on the right, we can see that this interface of zhihu uses WebView for content, which is normal because the format in the user's answer is complicated and WebView is the best solution, it is unknown whether the title bar is a VIew, ActionBar, or custom View. Below is a LinearLayout with four togglebuttons. The layout is very simple. We do not have a WebView, so we use ScrollView instead, the layout above is directly ImageView, and a src is set to simulate a layout.
In fact, the layout is very simple. We can achieve an effect.
First, how are the following Tools displayed and hidden? Of course, animation is used! What animation? Attribute animation can be implemented with attribute animation and Frame Animation. The attribute animation can actually change the attribute of the View. The Frame Animation only moves visually, and the actual attribute of the View does not change. either of the two can be implemented, attribute animation is used here.
/*** Display toolbar */private void showTools () {ObjectAnimator anim = ObjectAnimator. ofFloat (img_tools, "y", img_tools.getY (), img_tools.getY ()-img_tools.getHeight (); anim. setDuration (TIME_ANIMATION); anim. start (); isToolsHide = false;}/*** hide toolbar */private void hideTools () {ObjectAnimator anim = ObjectAnimator. ofFloat (img_tools, "y", img_tools.getY (), img_tools.getY () + img_tools.getHeight (); anim. setDuration (TIME_ANIMATION); anim. start (); isToolsHide = true ;}
So when will it be called? From the above requirement analysis, we know that, when a user's finger is pulled down, Tools is displayed, and vice versa, we can monitor the onTouch of ScrollView, determine the finger direction, and call the animation effect.
MScroller. setOnTouchListener (new View. onTouchListener () {@ Overridepublic boolean onTouch (View v, MotionEvent event) {switch (event. getAction () {case MotionEvent. ACTION_DOWN: lastY = event. getY (); break; case MotionEvent. ACTION_MOVE: float disY = event. getY ()-lastY; // vertically slide if (Math. abs (disY)> viewSlop) {// whether to slide isUpSlide = disY <0; // display and hide the bottom tools if (isUpSlide) {if (! IsToolsHide) hideTools () ;}else {if (isToolsHide) showTools () ;}} break ;}return false ;}});
Use the variable isToolsHide to place the code for repeated calls.
The following Tools solves the problem. Let's take a look at how the layout animation above is implemented. The above idea is the same as below. It also uses attribute animation to move the position. The moving layout includes Bar, Title, and root layout. Why is Author not moving? Because the root layout must be moved, otherwise the text content below will be blocked, and the movement of the root layout will move the sub layout, so only the root layout can be moved.
By the way, for a wider range of real text, the WebView of zhihu occupies the entire layout, and other la s are in the root layout FrameLayout. Therefore, when loading for the first time, the following text needs to be separated at the beginning to prevent being blocked. When the layout of the surface is hidden, there is no problem.
After a simple analysis, I will give the layout code for implementation.
<FrameLayout xmlns: android = "http://schemas.android.com/apk/res/android" android: layout_width = "match_parent" android: layout_height = "match_parent" android: background = "@ android: color/white"> <com. socks. zhihudetail. myScrollView android: id = "@ + id/scroller" android: layout_width = "match_parent" android: layout_height = "wrap_content"> <TextView android: layout_width = "match_parent" android: layout_height = "match _ Parent "android: textSize =" 16sp "android: textColor =" @ android: color/black "android: text =" @ string/hello_world "/> </com. socks. zhihudetail. myScrollView> <FrameLayout android: id = "@ + id/ll_top" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: background = "@ android: color/white "android: orientation =" vertical "android: layout_gravity =" top "> <ImageView android: id =" @ + id/img_autho R "android: layout_width =" match_parent "android: layout_height =" 80dp "android: scaleType =" fitXY "android: src =" @ drawable/bg_author "/> <TextView android: id = "@ + id/TV _title" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_marginTop = "55dp" android: text = "Why are there so many muscular men in the United States? "Android: textSize =" 18sp "android: background =" # DBDBDB "android: gravity =" center | left "android: paddingLeft =" 15dp "android: paddingRight = "15dp" android: paddingTop = "5dp" android: paddingBottom = "5dp" android: textColor = "@ android: color/darker_gray"/> <ImageView android: id = "@ + id/img_bar" android: layout_width = "match_parent" android: layout_height = "55dp" android: scaleType = "fitXY" android: src = "@ drawable/bg_actionbar"/> </FrameLayout> <ImageView android: id = "@ + id/img_tools" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: scaleType = "fitXY" android: layout_gravity = "bottom" android: src = "@ drawable/bg_bottom"/> </FrameLayout>
As shown in the following figure, some blank lines are left in the text to ensure that the text is not blocked.
Some may wonder why there is no layout for the Q & A personnel here?
This is actually the case. In order to simulate the display of the layout in the upper part, the Title appears under the Bar, so it is designed in this way. I tried to use linearLayout to achieve the same effect. However, when the Title is moved down and displayed, it will overwrite the Bar. This is also easy to understand. LinearLayout has no hierarchical order, so it will be blocked. I tried View. bringToFront () tries to increase the Bar layout to a higher level, but this will lead to layout disorder. When the Bar is loaded for the first time, it will be displayed at the bottom, because after increasing the level, bar layout is recalculated, so it does not follow the layout rules of LinearLayout. In desperation, the Bar height can be set, but the Title height will change as the text increases, the bottom of the Author layout cannot be set, because we do not know how far it is from the top, so we can only dynamically calculate the Bar and Title height in the code, then, when loading the interface, we dynamically set MargenTop for the Author layout to ensure that the location is correct.
In onCreate, the View has not been drawn, so the actual height of the control is not obtained. We can use the following method to obtain the height of this period.
// Obtain the Bar and Title heights. Set ViewTreeObserver viewTreeObserver = fl_top.getViewTreeObserver () and viewTreeObserver in the margenTop of the auther layout. addOnPreDrawListener (new ViewTreeObserver. onPreDrawListener () {@ Overridepublic boolean onPreDraw () {if (! HasMeasured) {FrameLayout. layoutParams layoutParams = new FrameLayout. layoutParams (FrameLayout. layoutParams. MATCH_PARENT, FrameLayout. layoutParams. WRAP_CONTENT); layoutParams. setMargins (0, img_bar.getHeight () + TV _title.getHeight (), 0, 0); img_author.setLayoutParams (layoutParams); hasMeasured = true;} return true ;}});
After obtaining the height, we can set the location correctly. However, what if the above layout changes with the moving of our content?
After a manual visual test, the interface of zhihu changes the display status based on a fixed value. Therefore, we can monitor the sliding distance of ScrollView to determine. But ScrollView does not give us such a listener. What should we do? Rewrite!
/** * Created by zhaokaiqiang on 15/2/26. */public class MyScrollView extends ScrollView {private BottomListener bottomListener;private onScrollListener scrollListener;public MyScrollView(Context context) {this(context, null);}public MyScrollView(Context context, AttributeSet attrs) {super(context, attrs);}protected void onScrollChanged(int l, int t, int oldl, int oldt) {super.onScrollChanged(l, t, oldl, oldt);if (getScrollY() + getHeight() >= computeVerticalScrollRange()) {if (null != bottomListener) {bottomListener.onBottom();}}if (null != scrollListener) {scrollListener.onScrollChanged(l, t, oldl, oldt);}}public void setBottomListener(BottomListener bottomListener) {this.bottomListener = bottomListener;}public void setScrollListener(onScrollListener scrollListener) {this.scrollListener = scrollListener;}public interface onScrollListener {public void onScrollChanged(int l, int t, int oldl, int oldt);}public interface BottomListener {public void onBottom();}}
We only need to override the onScrollChange () method. In this method, we can not only get location changes from time to time, but also add a BottomListener interface to listen to events sliding to the bottom. After writing it, it will be very easy.
mScroller.setBottomListener(this);mScroller.setScrollListener(this);
/*** Display the layout of the upper part */private void showTop () {ObjectAnimator anim1 = ObjectAnimator. ofFloat (img_bar, "y", img_bar.getY (), 0); anim1.setDuration (TIME_ANIMATION); anim1.start (); ObjectAnimator anim2 = ObjectAnimator. ofFloat (TV _title, "y", round (), img_bar.getHeight (); Round (new Round (); anim2.setDuration (TIME_ANIMATION + 200); anim2.start (); ObjectAnimator anim4 = ObjectAn Imator. ofFloat (fl_top, "y", fl_top.getY (), 0); anim4.setDuration (TIME_ANIMATION); anim4.start (); isTopHide = false ;} /*** hide the upper Layout */private void hideTop () {ObjectAnimator anim1 = ObjectAnimator. ofFloat (img_bar, "y", 0,-img_bar.getHeight (); anim1.setDuration (TIME_ANIMATION); anim1.start (); ObjectAnimator anim2 = ObjectAnimator. ofFloat (TV _title, "y", TV _title.getY (),-TV _title.getHeight (); anim2.setDuratio N (TIME_ANIMATION); anim2.start (); ObjectAnimator anim4 = ObjectAnimator. ofFloat (fl_top, "y", 0,-(img_bar.getHeight () + TV _title.getHeight (); anim4.setDuration (TIME_ANIMATION); anim4.start (); isTopHide = true ;} @ Overridepublic void onBottom () {if (isToolsHide) {showTools () ;}@ Overridepublic void onScrollChanged (int l, int t, int oldl, int oldt) {if (t <= dp2px (TOP_DISTANCE_Y) & isTopHide & isAnimatio NFinish) {showTop (); Log. d (TAG, "show");} else if (t> dp2px (TOP_DISTANCE_Y )&&! IsTopHide & isAnimationFinish) {hideTop (); Log. d (TAG, "hide ");}}
We only need to display and hide the layout based on the current position!
OK. This article is here. If you have any questions or suggestions, you can either comment or send a private message.
: Https://github.com/ZhaoKaiQiang/ZhiHuDetailDemo
---------------------------------------- Split line ---------------------------------------------
We have replaced WebView with ScrollView. Some may ask, what if we want to use WebView?
Two solutions are provided here.
First, JS interacts with Android, and uses JS to transfer the Mobile Location of the webpage. I have never tried it. It is just an idea and I don't know whether it can be implemented.
The second approach is to integrate WebView, which also has onScrollChanged (). You don't need to talk about the rest ~
---------------------------------------- Split line ---------------------------------------------
I tried it again yesterday and found that there is another feature, that is, clicking the screen to hide and display the upper layout and Tools layout. This is not difficult, we can define a GestureDetector and then implement Gesturedetector. simpleOnGestureListener, onDown returns true, and then calls hideXXX and showXXX in onSingleTapConfirmed to provide the idea. You can do the rest by yourself!