One, foreword

Recently, I have been consolidating the knowledge of Android custom View. I used to read some theoretical articles, and seldom took the time to realize a custom View by myself. When I encountered problems in the project, I went to Github to find the effect. In fact, custom View involves a lot of content, only to personally complete a few cases, in order to have an in-depth understanding of the relevant knowledge points.

This article is a supplement to the previous article. At the bottom of the stock APP list, there is a running lantern effect that updates trades in real time. Throughout the market, many products have applied this effect, so I decided to implement it myself.

Ii. Preparation for development

1. Realize the effect drawing



2. Download the case source code

Click on the download

3. Knowledge points of case application

  1. ViewFlipper control basics
  2. Android animation basics
  3. Custom View basics
  4. Basic knowledge of the Activity startup process

ViewFlipper introduction

ViewFlipper definition

ViewFlipper is a basic control in Android, which is probably not used in general development, so many developers feel unfamiliar with this control. It is far less well-known in the control world than ViewPager, but ViewFlipper is very simple to use and works well.

The ViewFlipper inherits from the ViewAnimator, which in turn inherits from the FrameLayout, which is basically a layout that shows only one subview, Since it is difficult to determine the location of the subviews under FrameLayout, there are many cases where the subviews are shielded from each other. As a result, we basically only require FrameLayout to display a subview, and then switch with some control. Well, the ViewFlipper does that for us, and all we have to do is call the right method at the right time and essentially encapsulate some ViewAnimator methods, and the ViewAnimator is the one that actually does the action.

2. ViewFlipper properties

methods describe
isFlipping Check whether the View switch is in progress
setFilpInterval Set the time interval for switching between views
startFlipping Start the View switch, and it’s going to loop
stopFlipping Stop the View switch
setOutAnimation Set toggle View exit animation
setInAnimation Set toggle View entry animation
showNext Displays the next View in the View flipper
showPrevious Displays the previous View in the View flipper

Four, code implementation

ViewFlipper control has been introduced above the basic knowledge, if you want to achieve the horselight effect, it is recommended to customize the ViewFlipper to achieve their own needs. This article uses the custom ViewFlipper way to achieve the vertical scrolling effect of running lantern.

1. Customize the ViewFlipper property

Set the following attributes. You are advised to customize them for later modification and use in XML.

/ * ** Single-line display* /
private boolean isSingleLine;
/ * ** Rotation interval* / private int interval = 3000; / * ** Animation time* / private int animDuration = 1000; / * ** Display the number of items once* / private int itemCount = 1; Copy the code

2. Create an animation

  • Anim_marquee_in.xml enters the animation:
    • The y-position is moved from 100% below to position 0, and the animation lasts for 300 milliseconds
    • Gradient transparency animation effect from 0.0 to 1.0, animation lasts 500 milliseconds
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="300"
        android:fromYDelta="100%p"
 android:toYDelta="0"/>
 <alpha  android:duration="500"  android:fromAlpha="0.0"  android:toAlpha="1.0"/> </set> Copy the code
  • Anim_marquee_out.xml exit animation:

    • The y-position moves from 0 below to -100%, and the animation lasts 400 milliseconds
    • The gradient opacity animation is 1.0 to 0.0 and lasts 500 milliseconds

      
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
 android:fromYDelta="0"  android:toYDelta="-100%p"/>  <alpha  android:duration="500"  android:fromAlpha="1.0"  android:toAlpha="0.0"/> </set> Copy the code

Initialize the animation

After completing step 2 above, complete the initialization of the animation in the custom ViewFlipper.

private void initView(Context context) {
    / / animation
    Animation animIn = AnimationUtils.loadAnimation(context, R.anim.anim_marquee_in);
    Animation animOut = AnimationUtils.loadAnimation(context, R.anim.anim_marquee_out);
    // Set the animation
 animIn.setDuration(animDuration);  animOut.setDuration(animDuration);  // Set toggle View entry animation  setInAnimation(animIn);  // Set toggle View exit animation  setOutAnimation(animOut);  // Set the time interval between views  setFlipInterval(interval);  // Sets whether to consider all children or only children in visible or invisible states when measuring.  setMeasureAllChildren(false); } Copy the code

4. Create Adapter

Because the running light data basically exists in the form of collections, the Adapter mode is adopted to define the data refresh callback interface OnDataChangedListener, which receives the callback and refreshes the data in CustomizeMarqueeView.

public void setOnDataChangedListener(OnDataChangedListener onDataChangedListener) {
    mOnDataChangedListener = onDataChangedListener;
}

public void notifyDataChanged(a) {
 if(mOnDataChangedListener ! =null) {  mOnDataChangedListener.onChanged();  } }  public interface OnDataChangedListener {  void onChanged(a); } Copy the code

Defines methods for creating child View layouts and binding data

/ * * * @param parent
 * @returnCustomize Item layout for running lantern* /
public View onCreateView(CustomizeMarqueeView parent) {
 return LayoutInflater.from(parent.getContext()).inflate(R.layout.marqueeview_item, null); }  / * ** Update data * @param view  * @param position * / public void onBindView(View view, int position) { } Copy the code

Create the layout and bind the data

Set View data according to the List set, here we mainly use the custom View custom attributes, mainly divided into the following steps:

  1. How many pages need to be displayed according to the collection Size and the surplus “%” of items displayed on each page;
  2. Iterate over the number of pages obtained in Step 1;
  3. Create a child View layout by traversing each page based on a single/multi-line display;
  4. Call the adapter.onbindView () method to complete the data binding of each child View;
  5. AddView () adds all child views to the ViewFlipper;
private void setData(a) {
    removeAllViews();
    int currentIndex = 0;
    // It takes several pages to display the calculated data, based on the total entries % per page
    int loopCount = mMarqueeViewBaseAdapter.getItemCount() % itemCount == 0 ?
 mMarqueeViewBaseAdapter.getItemCount() / itemCount :  mMarqueeViewBaseAdapter.getItemCount() / itemCount + 1;  // Dynamically add views for each page  for (int i = 0; i < loopCount; i++) {  // Display a single page  if (isSingleLine) {  LinearLayout parentView = new LinearLayout(getContext());  parentView.setOrientation(LinearLayout.VERTICAL);  parentView.setGravity(Gravity.CENTER);  parentView.removeAllViews();  View view = mMarqueeViewBaseAdapter.onCreateView(this);  parentView.addView(view);  if (currentIndex < mMarqueeViewBaseAdapter.getItemCount()) {/ / bind the View  mMarqueeViewBaseAdapter.onBindView(view, currentIndex);  }  currentIndex = currentIndex + 1;  addView(parentView);  } else {  LinearLayout parentView = new LinearLayout(getContext());  parentView.setOrientation(LinearLayout.VERTICAL);  parentView.setGravity(Gravity.CENTER);  parentView.removeAllViews();  // Add child views as many pages are displayed on each page  for (int j = 0; j < itemCount; j++) {  View view = mMarqueeViewBaseAdapter.onCreateView(this);  parentView.addView(view);  currentIndex = getRealPosition(j, currentIndex);  if (currentIndex < mMarqueeViewBaseAdapter.getItemCount()) {  mMarqueeViewBaseAdapter.onBindView(view, currentIndex);  }  }  addView(parentView);  }  } } Copy the code

6. Start the Activity

Some friends may be curious about the relationship between this and the Activity startup process.

Because the ViewFlipper property sees that you need to manually call the startFlipping() and stopFlipping() methods to complete the View switch and loop execution. Therefore, considering the View performance and use effect, we rewrite the View of the three methods, to achieve open and close.

  • Whether onVisibilityChanged is called depends on whether the View executes the onAttachedToWindow method. That is, whether the View is added to the Window.

  • The onAttachedToWindow method is called when the Activity resumes, when the window corresponding to the Activity is added, and each view is called only once, with the parent view calling first. Regardless of the view’s visibility state will be called, suitable for some view-specific initialization operations;

  • The onDetachedFromWindow method is called when the Activity destroys, when the window corresponding to the Activity is deleted, and each view is called only once, after the parent view is called. Also regardless of the view visibility state will be called, suitable for the final cleanup operation;

  1. OnAttachedToWindow is called, which means the View is added to a drawn View tree.
  2. OnAttachedToWindow and onDetachedFromWindow can be called multiple times.
  3. When a View is added to the already drawn View tree, onAttachedToWindow is immediately executed, followed by onVisibilityChanged.
  4. When the View is removed from the View, onDetachedFromWindow will be executed if the onAttachedToWindow method has been executed before.
  5. OnVisibilityChanged is called only if the View executes the onAttachedToWindow method.
  6. If the View executes onAttachedToWindow, the mAttachInfo object in the View is not empty.
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
    super.onVisibilityChanged(changedView, visibility);
    if (VISIBLE == visibility) {
        startFlipping();
 } else if (GONE == visibility || INVISIBLE == visibility) {  stopFlipping();  } }  @Override protected void onAttachedToWindow(a) {  super.onAttachedToWindow();  startFlipping(); }  @Override protected void onDetachedFromWindow(a) {  super.onDetachedFromWindow();  stopFlipping(); } Copy the code

7. Use in Activity

Simply load the custom View layout in THE XML, then fetch the View in the Activity, and load the data collection.

marquessViewAdapter = new MarquessViewAdapter(this);
mMarqueeView.setItemCount(1);
mMarqueeView.setSingleLine(true);
mMarqueeView.setAdapter(marquessViewAdapter);
marquessViewAdapter.setMessageBeans(messageBeans);
Copy the code

Combined with the final effect of the last blog post:


Five, the summary

The above is a perfect implementation of the horselight effect, through the custom View, combined with animation properties. The code can be used directly in the project by simply changing the layout of the item according to the effect of your project. This article has been the fifth custom View actual combat case, although are some simple effects, but can customize the View related knowledge: View drawing process, View measurement, View event distribution to do a systematic in-depth. I hope this article can be helpful to friends who have just learned to customize View.

My wechat account is Jaynm888

Welcome to comment, invite Android programmers to join the wechat communication group, public number reply “add group” or add my wechat pull you into the group