Android Custom view for vertical marquee effect

Source: Internet
Author: User
Tags drawtext

First, give the



The middle of the color block is because the video turns into GIF caused by the distortion, automatically ignore the ha.

As you know, the landscape of the race lights Android comes with the TextView can be achieved, details please Baidu "Android marquee effect." But vertical marquee effect native Android is not supported. Online also have a lot of users to achieve a custom effect, but I always do not like to see other people's code, so the idea of this blog is my own idea ha.

First, we need to comb the layout of the custom controls, as shown in:


1, first we divided the control into three blocks, the above green part is vanishing invisible block, the middle black part is visible area, the red part below is want to appear invisible area. The Blue line represents the entire control's on-line and offline.

2, first we only give two pieces of text in memory, respectively, the black part of the visible block and the red part of the desired block.

3, find the width of these blocks, the height and the center point coordinate values.

4. When scrolling, dynamically change the y-coordinate of the center point of each block so that it pans upward.

5, when the translation is finished, the visible block is located in the invisible block to disappear, the visible block to appear in the visible area of the text block. At this point, remove the missing text block list, and reset the text and center of gravity coordinate values of the next index, re-join the list, refresh.

6, with a handler to deal with the interval between animation. Use the property animation Valueanimator to achieve the animated effect of panning.


The following is the beginning of the code explanation, the first is to set some general properties with the chained Setup method:

<span style= "FONT-SIZE:14PX;" > Public    verticalmarqueeview color (int color) {        This.color = color;        return this;    }        Public Verticalmarqueeview textSize (int textSize) {        this.textsize = textSize;        return this;    }        Public Verticalmarqueeview datas (string[] datas) {        this.datas = datas;        return this;    }        public void Commit () {        if (This.datas = = NULL | | datas.length = = 0) {            log.e ("Verticalmarqueeview", "the datas ' s Le Ngth is illegal ");            throw new IllegalStateException ("May is not invoke the method named Datas (string[])");        }        Paint.setcolor (color);        Paint.settextsize (textSize);    } </span>

Finally make sure to call the Commit method to commit, through the code can be seen here in addition to the evacuation measures, there is the most important step: set the size of the font.

Then I abstracted out a block of text Bean class:

    public class TextBlock {private int width;        private int height;        private String text;        private int drawx;        private int Drawy;        private paint paint;                private int position;            public TextBlock (int width, int height, paint paint) {this.width = width;            This.height = height;        This.paint = paint;        } public void Reset (int centery) {Reset (text, CenterX, centery, position);        } public void Reset (String text, int centery) {Reset (text, CenterX, centery, position); } public void Reset (String text, int centery, int position) {Reset (text, CenterX, CenterY, posit        ION);            } public void Reset (String text, int centerx, int centery, int position) {this.text = text;            This.position = position;            int measurewidth = (int) paint.measuretext (text); DRAWX = (Width-meaSurewidth)/2;            FontMetrics metrics = Paint.getfontmetrics ();        Drawy = (int) (CenterY + (metrics.bottom-metrics.top)/2-metrics.bottom);        } public int getPosition () {return position;        public void Draw (canvas canvas) {canvas.drawtext (text, drawx, Drawy, paint); }    }

This bean class, the most important method is a few overloaded reset method, by changing the value of the CenterY, to dynamically change the starting point of the drawing text to achieve center drawing. For the center drawing of the text, please refer to Baidu "Android Canvas Center drawing text".

Then rewrite the Onmeasure method

@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespe        c, Heightmeasurespec); if (This.datas = = NULL | | this.datas.length = = 0) {log.e ("Verticalmarqueeview", "the datas ' s length is illegal")            ;        Return        } width = measurespec.getsize (widthmeasurespec)-Getpaddingleft ()-getpaddingright ();        Height = measurespec.getsize (heightmeasurespec)-getpaddingtop ()-Getpaddingbottom ();        CenterX = WIDTH/2;        CenterY = HEIGHT/2;        Blocks.clear ();        Add a text block for the display area TextBlock block1 = new TextBlock (width, height, paint);        Block1.reset (Datas[0], CenterX, centery, 0);        Blocks.add (BLOCK1);            if (Datas.length > 1) {TextBlock Block2 = new TextBlock (width, height, paint);            Block2.reset (Datas[1], CenterX, centery + height, 1);        Blocks.add (BLOCK2); }    }

In this method, non-null judgments are first made to avoid fatal logic errors. It then gets the width and center of gravity coordinates of the entire control. Then instantiate two blocks of text TextBlock, the first block of text is set by reset, the midpoint y coordinate is the midpoint y coordinate of the entire control, and the second block sets the midpoint y coordinate by reset to centery+height, meaning that it is placed in the invisible area of the next block of text.

Then there is the OnDraw method, which is very simple, and has forwarded the business logic to the TextBlock draw method.

    @Override    protected void OnDraw (canvas canvas) {for        (int i = 0; i < blocks.size (); i++) {            blocks.get (i). Draw (canvas);        }    }

The key is the implementation of the scrolling effect, first we give two methods, start scrolling and end scrolling.

    public void Startscroll () {        isstopscroll = false;        if (datas = = NULL | | datas.length = = 0 | | datas.length = = 1) {            log.e ("Verticalmarqueeview", "the datas ' s length is Illeg Al ");            return;        }        if (!isstopscroll) {            handler.postdelayed (new Runnable () {                                @Override public                void Run () {                    scroll ();                    if (!isstopscroll) {                        handler.postdelayed (this, duration_scroll);}}            , duration_scroll);}    } Public        void Stopscroll () {        this.isstopscroll = true;    }

The principle is very simple, first give a Boolean flag isstopscroll. The scroll method is then used to scroll through the cyclic delay with the handler postdelayed method. Next, we give the most important method of the full text, scroll method.

private void Scroll () {Valueanimator animator = Valueanimator.ofpropertyvaluesholder (Propertyvaluesholder.ofint ("SC        RollY ", CenterY, Centery-height));        Animator.setduration (Duration_animator); Animator.addupdatelistener (New Animatorupdatelistener () {@Override public void Onanimati                OnUpdate (Valueanimator animation) {int scrolly = (int) animation.getanimatedvalue ("scrolly");                Blocks.get (0). Reset (scrolly);                Blocks.get (1). Reset (scrolly + height);            Invalidate ();        }        }); Animator.addlistener (New Animatorlistener () {@Override public void Onanimationstart (Anim Ator animation) {} @Override public void Onanimationrepeat (Animator animation                {} @Override public void Onanimationend (Animator animation) { removing the first int position = Blocks.get (1). GetPosition ();                TextBlock TextBlock = blocks.remove (0);                The last if (position = = datas.length-1) {position = 0;                }else{position + +;                } textblock.reset (Datas[position], centery + height, position);                Blocks.add (TextBlock);            Invalidate ();        } @Override public void Onanimationcancel (Animator animation) {}});    Animator.start (); }

First, the Valueanimator class is used for property animation, the start value is the midpoint y-coordinate of the control, and the ending value is centery-height, which means moving the distance from the bottom to the top of a block of text. Then, in the animation update callback method, make the reset method for the block of text. When the animation is finished, get the position value of the second block of text, then remove the first block of text, reset the index value of the text block, and then add to the list container. So follow the bad.

Finally, return the position to a get method.

    public int getcurrentposition () {        if (datas = = NULL | | datas.length = = 0) {            return-1;        }        if (datas.length = = 1 && blocks.size () = = 1) {            return 0;        }        Return Blocks.get (0). GetPosition ();    }

All of the code for this custom control is presented here, and all of the code is printed out, given the relatively fragmented:

/** * @FileName: Verticalmarqueeview.java * @Author * @Description: * @Date July 13, 2016 morning 9:32:27 * @CopyRight CNP Co Rporation */package Cc.wxf.component;import Android.animation.animator;import Android.animation.animator.animatorlistener;import Android.animation.propertyvaluesholder;import Android.animation.valueanimator;import Android.animation.valueanimator.animatorupdatelistener;import Android.content.context;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.paint.fontmetrics;import Android.os.handler;import Android.util.attributeset;import Android.util.log;import Android.view.view;import Java.util.ArrayList;import    Java.util.list;public class Verticalmarqueeview extends view{public static final int duration_scroll = 3000;    public static final int duration_animator = 1000;    private int color = Color.Black;    private int textSize = 30;        Private string[] datas = null;    private int width; Private int height;    private int CenterX;        private int centery;    Private list<textblock> blocks = new arraylist<textblock> (2);    Private Paint paint = new paint (Paint.anti_alias_flag);    Private Handler Handler = new Handler ();        Private Boolean isstopscroll = false; Public Verticalmarqueeview (context context, AttributeSet attrs, int defstyleattr) {Super (context, Attrs, defstyleat    TR);    } public Verticalmarqueeview (context context, AttributeSet Attrs) {Super (context, attrs);    } public Verticalmarqueeview (context context) {super (context);        public Verticalmarqueeview color (int color) {this.color = color;    return this;        } public verticalmarqueeview textSize (int textSize) {this.textsize = textSize;    return this;        } public Verticalmarqueeview datas (string[] datas) {this.datas = datas;    return this; public void commit () {if (This.datas = = NULL | | daTas.length = = 0) {log.e ("Verticalmarqueeview", "the datas ' s length is illegal");        throw new IllegalStateException ("May is not invoke the method named Datas (string[])");        } paint.setcolor (color);    Paint.settextsize (textSize); } @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasu        Respec, Heightmeasurespec); if (This.datas = = NULL | | this.datas.length = = 0) {log.e ("Verticalmarqueeview", "the datas ' s length is illegal")            ;        Return        } width = measurespec.getsize (widthmeasurespec)-Getpaddingleft ()-getpaddingright ();        Height = measurespec.getsize (heightmeasurespec)-getpaddingtop ()-Getpaddingbottom ();        CenterX = WIDTH/2;        CenterY = HEIGHT/2;        Blocks.clear ();        Add a text block for the display area TextBlock block1 = new TextBlock (width, height, paint);        Block1.reset (Datas[0], CenterX, centery, 0); Blocks.add (BLOCK1);            if (Datas.length > 1) {TextBlock Block2 = new TextBlock (width, height, paint);            Block2.reset (Datas[1], CenterX, centery + height, 1);        Blocks.add (BLOCK2);            }} @Override protected void OnDraw (canvas canvas) {for (int i = 0; i < blocks.size (); i++) {        Blocks.get (i). Draw (canvas);        }} public void Startscroll () {isstopscroll = false; if (datas = = NULL | | datas.length = = 0 | | datas.length = = 1) {LOG.E ("Verticalmarqueeview", "the datas ' s length I            s illegal ");        Return                } if (!isstopscroll) {handler.postdelayed (new Runnable () {@Override                    public void Run () {scroll ();                    if (!isstopscroll) {handler.postdelayed (this, duration_scroll);        }}}, Duration_scroll); }} Public void Stopscroll () {this.isstopscroll = true; private void Scroll () {Valueanimator animator = Valueanimator.ofpropertyvaluesholder (Propertyvaluesholder.        Ofint ("scrolly", CenterY, Centery-height));        Animator.setduration (Duration_animator); Animator.addupdatelistener (New Animatorupdatelistener () {@Override public void Onanimati                OnUpdate (Valueanimator animation) {int scrolly = (int) animation.getanimatedvalue ("scrolly");                Blocks.get (0). Reset (scrolly);                Blocks.get (1). Reset (scrolly + height);            Invalidate ();        }        }); Animator.addlistener (New Animatorlistener () {@Override public void Onanimationstart (Anim Ator animation) {} @Override public void Onanimationrepeat (Animator animation ) {} @Override public void Onanimationend (Animator animation) {//Remove the first block int position = Blocks.get (1). GetPosition ();                TextBlock TextBlock = blocks.remove (0);                The last if (position = = datas.length-1) {position = 0;                }else{position + +;                } textblock.reset (Datas[position], centery + height, position);                Blocks.add (TextBlock);            Invalidate ();        } @Override public void Onanimationcancel (Animator animation) {}});    Animator.start ();        } public int GetCurrentPosition () {if (datas = = NULL | | datas.length = = 0) {return-1;        } if (datas.length = = 1 && blocks.size () = = 1) {return 0;    } return Blocks.get (0). GetPosition ();        } public class TextBlock {private int width;        private int height; Private StrinG text;        private int drawx;        private int Drawy;        private paint paint;                private int position;            public TextBlock (int width, int height, paint paint) {this.width = width;            This.height = height;        This.paint = paint;        } public void Reset (int centery) {Reset (text, CenterX, centery, position);        } public void Reset (String text, int centery) {Reset (text, CenterX, centery, position); } public void Reset (String text, int centery, int position) {Reset (text, CenterX, CenterY, posit        ION);            } public void Reset (String text, int centerx, int centery, int position) {this.text = text;            This.position = position;            int measurewidth = (int) paint.measuretext (text);            DRAWX = (width-measurewidth)/2;            FontMetrics metrics = Paint.getfontmetrics (); Drawy = (int) (CENTery + (metrics.bottom-metrics.top)/2-metrics.bottom);        } public int getPosition () {return position;        public void Draw (canvas canvas) {canvas.drawtext (text, drawx, Drawy, paint); }    }    }

Finally, the method used is very simple.

Package Cc.wxf.androiddemo;import Android.app.activity;import Android.content.context;import android.os.Bundle; Import Android.view.view;import Android.widget.toast;import Cc.wxf.component.verticalmarqueeview;public class    Mainactivity extends Activity {private Verticalmarqueeview vmview;        @Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);        Setcontentview (R.layout.activity_main);        Vmview = (Verticalmarqueeview) Findviewbyid (R.id.vmview); string[] datas = new string[]{"The South China Sea is beginning to be turbulent", "the Philippines is full of accidents", "This time for a trial of waste paper, the cost of the Philippines", "test Data 4", "test data 5 for the length of different", "the        As test data Bar "}; Vmview.color (Getresources (). GetColor (Android.        R.color.black). TextSize (sp2px (this,)). Datas (Datas). commit ();        Vmview.startscroll ();                Vmview.setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) { Toast.maketext (MainactiviTy.this, "Current index is:" + vmview.getcurrentposition (), Toast.length_short). Show ();    }        }); } private int sp2px (context context, int sp) {float density = context.getresources (). Getdisplaymetrics (). Scaledd        ensity;    return (int) (SP * density + 0.5f);        } @Override protected void OnDestroy () {Super.ondestroy ();    Must be called, otherwise the memory will always be infinite loop vmview.stopscroll (); }}

Demo is not provided, the custom view is only the above one file.

In addition, respect for the original Kazakhstan. Reprint needs to explain OH.

Android Custom view for vertical marquee effect

Related Article

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.