Search code examples
androidtextviewimageviewmarquee

Marquee of TextView with ImageView


I need to have marquee of textview and imageview as show in the image. where the textview along with the imageview will be moving Where onclick of either the textview or Imageview , it should open an activity. Can some one suggest a way to that.

ImageView should be clickable.


Solution

  • Created custom view

    public class MarqueeLayout extends ViewGroup {
    
    private static final int VERTICAL_SPACING = 10;
    private static final int HORIZONTAL_SPACING = 10;
    private static final String TAG = MarqueeLayout.class.getName();
    private int line_width;
    private List<View> views; 
    private Timer timer;
    
    private int scrollX = 0;
    
    public MarqueeLayout(Context context)
    {
        super(context);
    }
    private Handler handler;
    private int index = 0;
    private int childCount;
    public MarqueeLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        handler = new Handler();
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        requestLayout();
                    }
                });
            }
        }, 1000, 200);
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);
        if(views == null) {
            views = new ArrayList<View>();
            childCount = getChildCount();
            for(int i = 0; i < childCount; i++) {
                views.add(getChildAt(i));
            }
    
        }
        final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
        final int count = getChildCount();
        int line_height = 0;
    
        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();
    
        int childHeightMeasureSpec;
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST)
        {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
        }
        else
        {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
    
        for (int i = 0; i < count; i++)
        {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE)
            {
                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
                final int childw = child.getMeasuredWidth();
                line_height = Math.max(line_height, child.getMeasuredHeight() + VERTICAL_SPACING);
    
                xpos += childw + HORIZONTAL_SPACING;
            }
        }
        this.line_width = xpos;
    
        setMeasuredDimension(width, height);
    }
    
    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams()
    {
        return new LayoutParams(1, 1); 
    }
    
    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p)
    {
        if (p instanceof LayoutParams)
        {
            return true;
        }
        return false;
    }
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        Log.d(TAG, "onLayout called");
        int count = getChildCount();
        final int width = r - l;
    
        scrollX -= 20;
        if(line_width + scrollX < 0) {
            scrollX = 0;
        }
        int i = 0;
        while(count > 0) {
            View c = getChildAt(i);
            if(c == null) {
                break;
            }
            int w = c.getMeasuredWidth();
            Log.d(TAG, "scrollX : " + scrollX + " width : " + w);
            if(scrollX < -w) {
                this.removeViewAt(0);
                scrollX += w;
            } else {
                break;
            }
            i++;
            count--;
        }
        count = getChildCount();
        int xpos = getPaddingLeft() + scrollX;
        int ypos = getPaddingTop();
        for (i = 0; i < count; i++)
        {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE)
            {
                final int childw = child.getMeasuredWidth();
                final int childh = child.getMeasuredHeight();
                child.layout(xpos, ypos, xpos + childw, ypos + childh);
                xpos += childw + HORIZONTAL_SPACING;
            }
        }
        while(xpos < getWidth()) {
            View v = views.get(index % childCount);
            addView(v);
            xpos += v.getMeasuredWidth();
            index++;
        }
    }} 
    

    and you can have any type of view inside this layout , you can call this layout in xml

    <Your.Package.name.MarqueeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="this is textview 1"
            tools:context=".MainActivity" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="clicked"
            android:text="Click me 1" />
    
    </Your.Package.name.MarqueeLayout>