Apakah ada cara agar ellipsize = "marquee" selalu di-scroll?


93

Saya ingin menggunakan efek marquee pada TextView, tetapi teks hanya digulir saat TextView mendapatkan fokus. Itu masalah, karena dalam kasus saya, tidak bisa.

Saya menggunakan:

  android:ellipsize="marquee"
  android:marqueeRepeatLimit="marquee_forever"

Apakah ada cara agar TextView selalu menggulir teksnya? Saya telah melihat ini dilakukan di aplikasi Android Market, di mana nama aplikasi akan bergulir di bilah judul, meskipun tidak menerima fokus, tetapi saya tidak dapat menemukan hal ini disebutkan dalam dokumen API.


Untuk membuat pekerjaan tenda TextView harus dipilih, tidak fokus. Fokus memberi pilihan tetapi tidak sebaliknya.
Denis Gladkiy

1
Coba selaluMarqueeTextView stackoverflow.com/a/28806003/3496570
AndroidGeek

saya akan mengubah jawaban yang benar untuk yang satu ini stackoverflow.com/a/3700651/4548520
pengguna25

Jawaban:


62

Saya telah menghadapi masalah dan solusi terpendek yang saya dapatkan adalah membuat kelas baru yang berasal dari TextView. Kelas harus mengganti tiga metode onFocusChanged , onWindowFocusChanged , dan isFocused untuk membuat TextView semuanya terfokus.

@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    if(focused)
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
}

@Override
public void onWindowFocusChanged(boolean focused) {
    if(focused)
        super.onWindowFocusChanged(focused);
}


@Override
public boolean isFocused() {
    return true;
}

Sempurna - ini hanya solusi yang saya cari.
Jason

6
Anda juga harus mengganti metode onWindowFocusChanged jika Anda ingin marquee tidak berhenti saat menu muncul.
virsir

7
Ngomong-ngomong, kami sebenarnya memiliki masalah dengan solusi ini, karena ini mengacaukan stateful drawable: jika Anda mengubah drawable dengan focus-in / focus-out, ini akan rusak. Butuh waktu hampir satu jam untuk debugging sampai kami menyadari peretasan ini yang menyebabkannya.
Matthias

Dapatkah Anda memberikan deskripsi masalah yang lebih detail? Saya menggunakan fitur ini di banyak aplikasi. Saya ingin melihat masalah ini juga.
hnviet

1
Peretasan ini berfungsi dengan baik dan hanya diperlukan ketika beberapa Tampilan Teks ada di layar pada saat yang sama (seperti saat digunakan di ListView) - karena biasanya hanya satu dari mereka yang dapat difokuskan, tetapi solusi ini 'menipu' sistem dengan memberitahukan semuanya. are :) Jika tidak, untuk satu TextView jawaban sederhana seperti stackoverflow.com/a/3510891/258848 harus digunakan.
dimsuz

120

Saya akhirnya menemukan masalah ini hari ini dan mulai hierarchyviewermenggunakan aplikasi Android Market.

Melihat judul di layar detail aplikasi, mereka menggunakan yang lama TextView. Memeriksa propertinya menunjukkan bahwa itu tidak fokus, tidak bisa fokus dan umumnya sangat biasa - kecuali fakta bahwa itu ditandai sebagai terpilih .

Satu baris kode kemudian dan saya berhasil :)

textView.setSelected(true);

Ini masuk akal, mengingat apa yang dikatakan Javadoc :

Tampilan bisa dipilih atau tidak. Perhatikan bahwa pemilihan tidak sama dengan fokus. Tampilan biasanya dipilih dalam konteks AdapterView seperti ListView atau GridView.

yaitu Saat Anda menggulir item dalam tampilan daftar (seperti di aplikasi Market), baru kemudian teks yang sekarang dipilih mulai bergulir. Dan karena ini TextViewtidak dapat difokuskan atau diklik, status pemilihannya tidak akan pernah hilang.

Sayangnya, sejauh yang saya tahu tidak ada cara untuk mengatur keadaan yang dipilih dari tata letak XML.
Tapi satu baris di atas berfungsi dengan baik untuk saya.


hanya ingin tahu: apakah ini juga akan berfungsi untuk TextView yang dapat difokuskan, tetapi masih harus di-scroll saat tidak difokuskan? Iow, apakah status pilih "tetap" bahkan ketika status fokus berubah?
Matthias

Saya rasa begitu. Saya tidak melihat mengapa perubahan fokus pada dasar TextView(yaitu yang tidak tertanam dalam sesuatu yang "dapat dipilih" seperti a ListView) akan mengubah keadaan yang dipilih.
Christopher Orr

Ini bekerja dengan baik untuk saya juga. Terima kasih atas jawaban Anda. Apakah ada kemungkinan untuk mengubah cara pengulangan ?!
Tima

@ Mur: Ya, baca TextViewdokumentasi dan lihat android:marqueeRepeatLimit.
Christopher Orr

1
Metode ini lebih baik daripada metode dengan fokus karena tidak mengacaukan fokus tampilan. Jika Anda memiliki pandangan yang mengharuskan orang tua mereka untuk fokus, metode itu akan mengacaukan fokus. Metode ini sederhana, efisien dan tidak bergantung pada peretasan untuk mengubah fokus setiap saat. Terima kasih!
Ionut Negru

75

Letakkan saja parameter ini di TextView Anda. Berhasil :)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 

1
jika utas jawaban ini belum mati, ini harus menjadi jawaban yang diterima, menurut saya. Saya menambahkan ini ke definisi XML saya untuk tampilan teks, dan ini berfungsi pada bidikan pertama. Saya sudah mencoba saran lain, dan ini yang paling sederhana. - Selain itu, menambahkan "android: marqueeRepeatLimit =" marquee_forever "membuatnya menggulir tanpa batas
tanda kurung

19
Menggunakan ini memecah pilihan fokus dari Baris ListView jika TextView ada di dalamnya.
Tivie

Bekerja dengan sempurna. Solusi sederhana dan elegan. Terima kasih!
Rabi

Bagaimana memulai dan menghentikan tenda TextView
Dwivedi Ji

Ini tidak berhasil untuk saya sampai saya mencoba jawaban lain - textView.setSelected (true);
Justin

13

TranslateAnimationbekerja dengan "menarik" View ke satu arah dengan jumlah tertentu. Anda dapat mengatur di mana untuk memulai "penarikan" ini dan di mana harus mengakhirinya.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta mengatur offset posisi awal gerakan di sumbu X.

fromXDelta = 0 //no offset. 
fromXDelta = 300 //the movement starts at 300px to the right.
fromXDelta = -300 //the movement starts at 300px to the left

toXDelta mendefinisikan posisi akhir offset dari gerakan di sumbu X.

toXDelta = 0 //no offset. 
toXDelta = 300 //the movement ends at 300px to the right.
toXDelta = -300 //the movement ends at 300px to the left.

Jika lebar teks Anda lebih besar dari modul perbedaan antara fromXDelta dan toXDelta, teks tidak akan dapat sepenuhnya dan benar-benar bergerak di dalam layar.


Contoh

Anggaplah ukuran layar kita 320x240 px. Kami memiliki TextView dengan teks yang memiliki lebar 700px dan kami ingin membuat animasi yang "menarik" teks tersebut sehingga kami dapat melihat akhir frasa.

                                       (screen)
                             +---------------------------+
                             |<----------320px---------->|
                             |                           |
                             |+---------------------------<<<< X px >>>>
               movement<-----|| some TextView with text that goes out...
                             |+---------------------------
                             |  unconstrained size 700px |
                             |                           |
                             |                           |
                             +---------------------------+


                             +---------------------------+
                             |                           |
                             |                           |
               <<<< X px >>>>---------------------------+|
movement<----- some TextView with text that goes out... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

Pertama kita atur fromXDelta = 0agar pergerakan tidak memiliki offset awal. Sekarang kita perlu mencari nilai toXDelta. Untuk mencapai efek yang diinginkan, kita perlu "menarik" teks dengan piksel yang sama persis dengan yang membentang di luar layar. (dalam skema diwakili oleh <<<< X px >>>>) Karena teks kita memiliki lebar 700, dan area yang terlihat adalah 320px (lebar layar) yang kita atur:

tXDelta = 700 - 320 = 380

Dan bagaimana kita menghitung Lebar Layar dan Lebar teks?


Kode

Mengambil Cuplikan Zarah sebagai titik awal:

    /**
     * @param view The Textview or any other view we wish to apply the movement
     * @param margin A margin to take into the calculation (since the view
     *               might have any siblings in the same "row")
     *
     **/
public static Animation scrollingText(View view, float margin){

    Context context = view.getContext(); //gets the context of the view

            // measures the unconstrained size of the view
            // before it is drawn in the layout
    view.measure(View.MeasureSpec.UNSPECIFIED, 
                         View.MeasureSpec.UNSPECIFIED); 

            // takes the unconstrained wisth of the view
    float width = view.getMeasuredWidth();

            // gets the screen width
    float screenWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();


            // perfrms the calculation
    float toXDelta = width - (screenWidth - margin);

            // sets toXDelta to 0 if the text width is smaller that the screen size
    if (toXDelta < 0) {toXDelta = 0; } else { toXDelta = 0 - toXDelta;}

            // Animation parameters
    Animation mAnimation = new TranslateAnimation(0, toXDelta, 0, 0);
    mAnimation.setDuration(15000); 
    mAnimation.setRepeatMode(Animation.RESTART);
    mAnimation.setRepeatCount(Animation.INFINITE);

    return mAnimation;
}

Mungkin ada cara yang lebih mudah untuk melakukan ini, tetapi ini berfungsi untuk setiap tampilan yang dapat Anda pikirkan dan dapat digunakan kembali. Ini sangat berguna jika Anda ingin menganimasikan TextView dalam ListView tanpa merusak kemampuan aktif / onFocus dari textView. Itu juga menggulir terus menerus bahkan jika Tampilan tidak fokus.


Apakah jawaban saya di atas (yaitu menambahkan satu baris kode :) textView.setSelected(true);tidak berfungsi dalam situasi Anda?
Christopher Orr

Sayangnya tidak ada. Saya memiliki ListView yang diisi dengan beberapa TextView di setiap baris (karenanya krisis ruang = P). setiap baris textview dapat diklik dan memunculkan menu konteks. Pengaturan setSelected ke true tampaknya merusak menu konteks.
Tivie

Apakah itu? Mungkin agak melampaui batas untuk banyak kasus. Bagi saya, untuk alasan yang dijelaskan di atas, itulah satu-satunya solusi. (dapat digunakan kembali, btw!) = P
Tivie

12

Saya tidak tahu apakah Anda masih membutuhkan jawabannya, tetapi saya menemukan cara mudah untuk melakukannya.

Siapkan animasi Anda seperti ini:

Animation mAnimation = new TranslateAnimation(START_POS_X, END_POS_X, 
                START_POS_Y, END_POS_Y);
mAnimation.setDuration(TICKER_DURATION); 
mAnimation.setRepeatMode(Animation.RESTART);
mAnimation.setRepeatCount(Animation.INFINITE);

START_POS_X, END_POS_X, START_POS_YDan END_POS_Yadalah floatnilai-nilai, sedangkan TICKER_DURATIONmerupakan intSaya menyatakan dengan konstanta saya yang lain.

Kemudian Anda sekarang dapat menerapkan animasi ini ke TextView Anda:

TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);

Dan itu dia. :)

Animasi saya dimulai di sisi kanan off-screen (300f) dan berakhir di sisi kiri off-screen (-300f), dengan durasi 15s (15000).


1
Itu tidak terlihat sederhana. Tetapi saya tidak berpikir dia masih membutuhkan jawabannya; lihat jawaban yang diterima di atas .. :)
Christopher Orr

2
Tapi menurut saya solusi ini lebih sederhana daripada membuat kelas baru. : D Sebagaimana adanya, Anda juga dapat menggunakan kembali objek animasi untuk tampilan lain yang ingin Anda animasikan. ;)
Zarah

Ini bekerja dengan baik, tapi apa yang harus saya lakukan, untuk menampilkan teks yang panjang ?! Sekarang teks saya akan dipotong
Tima

@Mur Votema: Sudahkah Anda mencoba menyetel lebar TextView Anda ke wrap_content?
Zarah

3
Bukan solusi yang bagus, karena parameter ukuran dan durasi sangat bergantung pada ukuran teks. Selanjutnya, akan dianimasikan, meskipun panjang teks kurang dari lebar tampilan. setSelected (true) sebenarnya adalah solusi termudah.
Anm

5

Saya menulis kode berikut untuk ListView dengan item teks marquee. Ini didasarkan pada solusi setSelected yang dijelaskan di atas. Pada dasarnya, saya memperluas kelas ArrayAdapter dan mengganti metode getView untuk memilih TextView sebelum mengembalikannya:

    // Create an ArrayAdapter which selects its TextViews before returning      
    // them. This would enable marqueeing while still making the list item
    // clickable.
    class SelectingAdapter extends ArrayAdapter<LibraryItem>
    {
        public
        SelectingAdapter(
            Context context, 
            int resource, 
            int textViewResourceId, 
            LibraryItem[] objects
        )
        {
            super(context, resource, textViewResourceId, objects);
        }

        @Override
        public
        View getView(int position, View convertView, ViewGroup parent)
        {
            View view = super.getView(position, convertView, parent);
            TextView textview = (TextView) view.findViewById(
                R.id.textview_playlist_item_title
            );
            textview.setSelected(true);
            textview.setEnabled(true);
            textview.setFocusable(false);
            textview.setTextColor(0xffffffff);
            return view;

        }
    }

1

Ini adalah jawaban yang muncul di bagian atas pencarian google saya jadi saya pikir saya bisa memposting jawaban yang berguna di sini karena saya kesulitan mengingat ini cukup sering. Bagaimanapun, ini berfungsi untuk saya dan membutuhkan atribut XML dan A onFocusChangeListener.

//XML
        <TextView
            android:id="@+id/blank_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:layout_gravity="center_horizontal|center_vertical"
            android:background="#a4868585"
            android:textColor="#fff"
            android:textSize="15sp"
            android:singleLine="true"
            android:lines="1"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit ="marquee_forever"
            android:scrollHorizontally="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            tools:ignore="Deprecated" />

//JAVA
    titleText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                titleText.setSelected(true);
            }
        }
    });

1

// xml

 <TextView
            android:id="@+id/tvMarque"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:layout_gravity="center_horizontal"
            android:fadingEdge="horizontal"
            android:marqueeRepeatLimit="marquee_forever"
            android:scrollHorizontally="true"
            android:padding="5dp"
            android:textSize="16sp"
            android:text=""
            android:textColor="@color/colorSyncText"
            android:visibility="visible" />

// Di Jawa

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.