Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marquee effect for Linear Layout

I am trying to implement marquee effect to the layout to help it scroll/animate from right inner side to left inner side just as the ticker view.

From the below two links, you would be able to get more knowledge just as stock markets keep users updated by showing the values in a circular constant way.

1) http://www.sify.com/finance/livemarkets/

2) http://terminal.moneycontrol.com/index.php?wl=indices

For this i have implemented below code to make somewhat similar.

public class HorizonalSlideActivity extends Activity
{
    private LinearLayout horizontalOuterLayout;
    private HorizontalScrollView horizontalScrollview;
    private int scrollMax;
    private int scrollPos = 0;
    private TimerTask scrollerSchedule;
    private Timer scrollTimer = null;
    private ScrollAdapter adapter = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.horizontal_layout);

        adapter = new ScrollAdapter(HorizonalSlideActivity.this);

        horizontalScrollview = (HorizontalScrollView) findViewById(R.id.horiztonal_scrollview_id);
        horizontalScrollview.setOnTouchListener(new OnTouchListener()
        {
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                return false;
            }
        });
        horizontalOuterLayout = (LinearLayout) findViewById(R.id.horiztonal_outer_layout_id);
        horizontalTextView = (TextView) findViewById(R.id.horizontal_textview_id);
        horizontalScrollview.setHorizontalScrollBarEnabled(false);

        addData();


        ViewTreeObserver vto = horizontalOuterLayout.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
        {
            @Override
            public void onGlobalLayout()
            {
                horizontalOuterLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                getScrollMaxAmount();
                startAutoScrolling();
            }
        }); 
    }

    private void addData()
    {
        for (int i = 0; i < adapter.getCount(); i++)
        {
            View convertView = adapter.getView(i, null, null);
            horizontalOuterLayout.addView(convertView);
        }
    }

    public void getScrollMaxAmount()
    {
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int width = size.x;
        Log.e("getScrollMaxAmount", "getWidth == "+width);
        Log.e("getScrollMaxAmount", "getMeasuredWidth == "+horizontalOuterLayout.getMeasuredWidth());
        int actualWidth = (horizontalOuterLayout.getMeasuredWidth() - width);
        Log.e("getScrollMaxAmount", "actualWidth == "+actualWidth);
        scrollMax = actualWidth;
        Log.e("getScrollMaxAmount", "scrollMax == "+scrollMax);
    }

    public void startAutoScrolling()
    {
        if (scrollTimer == null)
        {
            scrollTimer = new Timer();
            final Runnable TimerTick = new Runnable()
            {
                public void run()
                {
                    moveScrollView();
                }
            };

            if (scrollerSchedule != null)
            {
                scrollerSchedule.cancel();
                scrollerSchedule = null;
            }
            scrollerSchedule = new TimerTask()
            {
                @Override
                public void run()
                {
                    runOnUiThread(TimerTick);
                }
            };

            scrollTimer.schedule(scrollerSchedule, 3000, 30);
        }
    }

    public void moveScrollView()
    {
        Log.e("moveScrollView", "scrollMax == "+scrollMax);
        scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
        Log.e("moveScrollView", "scrollPos == "+scrollPos);
        if (scrollPos >= scrollMax)
        {
            scrollPos = 0;
        }
        horizontalScrollview.scrollTo(scrollPos, 0);
    }

    public void stopAutoScrolling()
    {
        if (scrollTimer != null)
        {
            scrollTimer.cancel();
            scrollTimer = null;
        }
    }

    public void onBackPressed()
    {
        super.onBackPressed();
        finish();
    }

    public void onPause()
    {
        super.onPause();
        finish();
    }

    public void onDestroy()
    {
        clearTimerTaks(scrollerSchedule);
        clearTimers(scrollTimer);

        scrollerSchedule = null;
        scrollTimer = null;
        super.onDestroy();
    }

    private void clearTimers(Timer timer)
    {
        if (timer != null)
        {
            timer.cancel();
            timer = null;
        }
    }

    private void clearTimerTaks(TimerTask timerTask)
    {
        if (timerTask != null)
        {
            timerTask.cancel();
            timerTask = null;
        }
    }
}

Here is the layout for this file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <HorizontalScrollView
        android:id="@+id/horiztonal_scrollview_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fadingEdge="none" >

        <LinearLayout
            android:id="@+id/horiztonal_outer_layout_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingBottom="5dip"
            android:paddingTop="5dip" >
        </LinearLayout>
    </HorizontalScrollView>

</LinearLayout>

Adapter class to show data:

public class ScrollAdapter extends BaseAdapter
{

    private Context context;

    public ScrollAdapter(Context context)
    {
        this.context = context;
    }

    @Override
    public int getCount()
    {
        return 10;
    }

    @Override
    public Object getItem(int position)
    {
        return position;
    }

    @Override
    public long getItemId(int position)
    {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        LayoutInflater inflater = ((Activity)context).getLayoutInflater();
        convertView = inflater.inflate(R.layout.scroll_child, null);
        return convertView;
    }

}

And its xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/txtPercent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingLeft="30dp"
        android:paddingRight="30dp"
        android:text="0.14%" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@android:color/white" />

    <TextView
        android:id="@+id/txtData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingLeft="30dp"
        android:paddingRight="30dp"
        android:text="data" />

</LinearLayout>

By implementing this, i somewhat reached nearer but could not make what is desired. Please help me to make it circular without any interruption and restart scrolling after the last data moves inside from left side.

Here is the desired result:

enter image description here

Also i have checked this link, it gives the scroll effect what is needed but does not shows the whole data, its shows only 3 to 4 views but as you can see i have added 10 data in adapter class.

Any sort of help would be appreciable.

Thanks in advance.

like image 564
Jignesh Jain Avatar asked Jul 17 '15 08:07

Jignesh Jain


People also ask

How do you align a linear layout?

To control how linear layout aligns all the views it contains, set a value for android:gravity . For example, the snippet above sets android:gravity to "center". The value you set affects both horizontal and vertical alignment of all child views within the single row or column.

How do you make a linear layout vertical?

To create a linear layout in which each child uses the same amount of space on the screen, set the android:layout_height of each view to "0dp" (for a vertical layout) or the android:layout_width of each view to "0dp" (for a horizontal layout). Then set the android:layout_weight of each view to "1" .

What is linear layout in mad?

LinearLayout is a view group that aligns all children in a single direction, vertically or horizontally. You can specify the layout direction with the android:orientation attribute. Note: For better performance and tooling support, you should instead build your layout with ConstraintLayout.

What are the attributes of linear layout?

Some Important Attributes of LinearLayout Possible values are – center_vertical, fill, center, bottom, end, etc. Sets the gravity of the View or Layout relative to its parent. Possible values are – center_vertical, fill, center, bottom, end, etc. from aligning its children's baselines.


1 Answers

It can be accomplished using Recycleview and a autoscroll runnable . adding the code snippet here

1. MainActivity (MarqueeViewSample.java)

package com.test.mo.test;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;

/**
* Created by jovin.pj on 29-07-2015.
*/
public class MarqueeViewSample extends Activity {

private final Runnable SCROLLING_RUNNABLE = new Runnable() {

    @Override
    public void run() {
        final int duration = 10;
        final int pixelsToMove = 10;
        marqueList.smoothScrollBy(pixelsToMove, 0);
        mHandler.postDelayed(this, duration);
    }
};

private final Handler mHandler = new Handler(Looper.getMainLooper());
private RecyclerView marqueList;
//private boolean loading = true;
private boolean foundTotalPixel = true;
private int pastVisiblesItems, visibleItemCount, totalItemCount;
private int totalMovedPixel;
private int totalPixel;

/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    marqueList = (RecyclerView) findViewById(R.id.marqueList);
    final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
    marqueList.setLayoutManager(layoutManager);
    marqueList.setAdapter(new ScrollAdapter());

    marqueList.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            totalMovedPixel = totalMovedPixel + dx;
            visibleItemCount = layoutManager.getChildCount();
            totalItemCount = layoutManager.getItemCount();
            pastVisiblesItems = layoutManager.findFirstVisibleItemPosition();
            if (foundTotalPixel) {
                if (totalItemCount > 2) {
                    View headerView = layoutManager.getChildAt(0);
                    View itemView = layoutManager.getChildAt(1);

                    if (itemView != null && headerView != null) {
                        /*total visible scrolling part is total pixel's of total item's count and header view*/
                        totalPixel = /*-c.getTop() +*/ ((totalItemCount - 2) * itemView.getWidth()) + (1 * headerView.getWidth());
                        Log.v("...", "Total pixel x!" + totalPixel);
                        foundTotalPixel = false;
                    }
                }
            }

            //if (loading) {
            //if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
            if (!foundTotalPixel && totalMovedPixel >= totalPixel) {
                // loading = false;
                Log.v("...", "Last Item Wow !");
                Log.v("...", "totalMovedPixel !" + totalMovedPixel);

                // use this to turn auto-scrolling off:
                //mHandler.removeCallbacks(SCROLLING_RUNNABLE);
                marqueList.setAdapter(null);
                marqueList.setAdapter(new ScrollAdapter());
                pastVisiblesItems = visibleItemCount = totalItemCount = 0;
                totalMovedPixel = 0;

            }
        }
        // }
    });
    // use this to turn auto-scrolling on:
    mHandler.post(SCROLLING_RUNNABLE);
 }
}

2. SampleAdapter(ScrollAdapter.java)

package com.test.mo.test;

import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

/**
 * Created by jovin.pj on 29-07-2015.
 */
public class ScrollAdapter extends  RecyclerView.Adapter<RecyclerView.ViewHolder> {

private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private static final int TYPE_FOOTER = 2;


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    RecyclerView.ViewHolder viewHolder = null;
    if (viewType == TYPE_ITEM) {
        //inflate your layout and pass it to view holder
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.scroll_child, parent, false);
        viewHolder = new ViewHolderItem(view);
    } else if (viewType == TYPE_HEADER || viewType == TYPE_FOOTER) {
        //inflate your layout and pass it to view holder
        //View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_footer, parent, false);
        View view = new View(parent.getContext());
        DisplayMetrics metrics = parent.getContext().getResources().getDisplayMetrics();
        int width = metrics.widthPixels;
        view.setLayoutParams(new LinearLayout.LayoutParams(width, LinearLayout.LayoutParams.WRAP_CONTENT));
        viewHolder = new ViewHolderHeaderOrFooter(view);
    }

    return viewHolder;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

}

@Override
public int getItemCount() {
    // 1 for header and 1 for footer
    return 4 + 1 + 1;
}

@Override
public int getItemViewType(int position) {
    if (isPositionHeader(position))
        return TYPE_HEADER;
    else if (isPositionFooter(position))
        return TYPE_FOOTER;
    return TYPE_ITEM;
}


private boolean isPositionHeader(int position) {
    return position == 0;
}

private boolean isPositionFooter(int position) {
    return position == getItemCount() - 1;
}


// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolderItem extends RecyclerView.ViewHolder {
    // each data item is just a string in this case
    public View mView;
    public ViewHolderItem(View v) {
        super(v);
        mView = v;
    }
}

// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolderHeaderOrFooter extends RecyclerView.ViewHolder {
    // each data item is just a string in this case
    public View mView;
    public ViewHolderHeaderOrFooter(View v) {
        super(v);
        mView = v;
    }
 }
}

3. Main Activity's Layout file(main.xml)

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical">


 <android.support.v7.widget.RecyclerView
    android:id="@+id/marqueList"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:clipToPadding="false" />


</LinearLayout>

4. Adapter's Layout File(scroll_child.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical" >

<TextView
    android:id="@+id/txtPercent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:paddingLeft="30dp"
    android:paddingRight="30dp"
    android:text="0.14%" />

<View
    android:layout_width="match_parent"
    android:layout_height="1px"
    android:background="@android:color/darker_gray" />

<TextView
    android:id="@+id/txtData"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:paddingLeft="30dp"
    android:paddingRight="30dp"
    android:text="data" />

</LinearLayout>

increase or decrease pixelsToMove, this variables value to change the speed

like image 111
Jovin Avatar answered Oct 06 '22 06:10

Jovin