Эффект Marquee для линейной компоновки

Я пытаюсь реализовать эффект выделения для макета, чтобы помочь ему прокручивать/анимировать с правой внутренней стороны на левую внутреннюю сторону, так же как вид тикера.

Из приведенных ниже двух ссылок вы сможете получить больше знаний, так как фондовые рынки будут обновлять пользователей, показывая значения циклическим постоянным образом.

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

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

Для этого я выполнил ниже код, чтобы сделать несколько схожим.

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;
        }
    }
}

Вот макет для этого файла:

<?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>

Класс адаптера для отображения данных:

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;
    }

}

И его xml файл:

<?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>

Используя это, я несколько приблизился, но не смог сделать желаемого. Пожалуйста, помогите мне сделать его круговым без прерывания и перезапустить прокрутку после того, как последние данные перемещаются внутри с левой стороны.

Вот желаемый результат:

введите описание изображения здесь

Также я проверил эту ссылку, он дает эффект прокрутки, что нужно, но не отображает все данные, его показы только 3 4, но, как вы видите, я добавил 10 данных в класс адаптера.

Любая помощь будет заметна.

Спасибо заранее.

Ответы

Ответ 1

Это может быть выполнено с использованием Recycleview и runsable autoscroll. добавление фрагмента кода здесь

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 of total item 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.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. Файл макета адаптера (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>

увеличить или уменьшить pixelsToMove, это значение переменных для изменения скорости

Ответ 2

Вы можете решить эту проблему с помощью библиотеки MarqueeView, которую я использую в течение некоторого времени, и ее работы великолепны. Здесь является ссылкой для него.

Использование

В XML,

<asia.ivity.android.marqueeview.MarqueeView
        android:id="@+id/marqueeView150"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        marquee:speed="5"
        marquee:pause="1000"
        marquee:autoStart="true"
        >

        <TextView
            android:id="@+id/textView2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do."
            android:textSize="20sp"
            android:textStyle="bold"
            android:singleLine="true"
            android:ellipsize="end"
            tools:ignore="HardcodedText"/>
    </asia.ivity.android.marqueeview.MarqueeView>

В Java,

final MarqueeView mv = (MarqueeView) findViewById(R.id.marqueeView100);
        mv.setPauseBetweenAnimations(500);
        mv.setSpeed(10);
        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                mv.startMarquee();
            }
        });

Для получения дополнительной информации обратитесь к проекту sample.

Я предлагаю вам использовать один TextView внутри MarqueeView и объединить в него как "процент", так и "данные".

Вы можете абсолютно настроить атрибуты размер текста, стиль шрифта, цвет и т.д. частей TextView с помощью Spannable.

Вот небольшой пример для вас,

Spannable spn = (Spannable) tv3.getText();
        spn.setSpan(new BackgroundColorSpan(Color.RED), 0, 7,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        spn.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC),0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Вы можете настроить его так, как хотите, чтобы процент и данные выглядели иначе в одном текстовом файле.

Вы также можете отображать изображения внутри TextView в любом месте, где хотите, используя ImageSpan,

Вот краткий пример,

ImageSpan is = new ImageSpan(context, resId);
text.setSpan(is, index, index + strLength, 0);

Просто убедитесь, что вы используете правильные позиции индекса, иначе вы получите StringIndexOutOfBoundsException.