Üç nokta = "seçim çerçevesi" her zaman kaydırmak için bir yol var mı?


93

Bir TextView üzerinde seçim çerçevesi efektini kullanmak istiyorum, ancak metin yalnızca TextView odaklandığında kaydırılıyor. Bu bir sorun, çünkü benim durumumda olamaz.

Ben kullanıyorum:

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

TextView'in her zaman metnini kaydırmasını sağlamanın bir yolu var mı? Bunun, odaklanılmasa bile uygulama adının başlık çubuğunda kaydığı Android Market uygulamasında yapıldığını gördüm, ancak API belgelerinde bundan bahsedildiğini bulamadım.


Seçim çerçevesinin çalışması için TextView odaklanmalı değil seçilmelidir. Odak seçim verir ama tersi vermez.
Denis Gladkiy

1
AlwaysMarqueeTextView'u deneyin stackoverflow.com/a/28806003/3496570
AndroidGeek

Yanıtlar:


62

Sorunla karşı karşıyayım ve bulduğum en kısa çözüm, TextView'dan türetilmiş yeni bir sınıf oluşturmak. Sınıf , TextView'i tamamen odaklanmış hale getirmek için onFocusChanged , onWindowFocusChanged ve isFocused olmak üzere üç yöntemi geçersiz kılmalıdır .

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

Mükemmel - bu tam da aradığım çözüm.
Jason

7
Ayrıca, menüler açıldığında seçim çerçevesinin durmamasını istiyorsanız, onWindowFocusChanged yöntemini geçersiz kılmalısınız.
virsir

7
Bu arada, durum bilgisi olan çekmeceleri karıştırdığı için aslında bu çözümle ilgili sorunlar yaşadık: Eğer çekilebilir öğeleri odaklanma / odaklanma ile değiştirirseniz, bu durum bozulacaktır. Bu saldırının neden olduğunu fark edene kadar neredeyse bir saat hata ayıklama yaptık.
Matthias

Sorunun daha ayrıntılı bir açıklamasını verebilir misiniz? Bu özelliği birçok uygulamada kullanıyorum. Bu soruna da bir göz atmak isterim.
hnviet

1
Bu hack harika çalışıyor ve yalnızca birden fazla TextView aynı anda ekranda olduğunda (ListView'da kullanıldığında olduğu gibi) gereklidir - çünkü genellikle bunlardan yalnızca birine odaklanılabilir, ancak bu çözüm, hepsini anlatarak sistemi 'kandırır' are :) Aksi takdirde, tek TextView için stackoverflow.com/a/3510891/258848 gibi daha basit bir anwer kullanılmalıdır.
dimsuz

120

Sonunda bugün bu problemle karşılaştım ve hierarchyviewerAndroid Market uygulamasına ateş açtım .

Bir uygulamanın ayrıntı ekranındaki başlığa bakıldığında, eski bir tane kullanıyorlar TextView. O, odaklanmış olmadığını gösterdi özelliklerini incelemek olamazdı gibi kutlandı gerçeği dışında - odaklanmalıdır ve genellikle çok sıradan seçilen .

Bir satır kod sonra ve onu çalıştırdım :)

textView.setSelected(true);

Javadoc'un söylediği düşünüldüğünde bu mantıklı :

Bir görünüm seçilebilir veya seçilemez. Seçimin odak ile aynı şey olmadığını unutmayın. Görünümler tipik olarak ListView veya GridView gibi bir AdapterView bağlamında seçilir.

Örneğin, bir liste görünümünde (Market uygulamasında olduğu gibi) bir öğeyi kaydırdığınızda, ancak o zaman şimdi seçilen metin kaymaya başlar. Ve bu özellikleTextView odaklanabilir veya tıklanabilir olmadığından, seçim durumunu asla kaybetmez.

Ne yazık ki, bildiğim kadarıyla mizanpaj XML'inden seçilen durumu önceden ayarlamanın bir yolu yok.
Ancak yukarıdaki tek satırlık benim için iyi çalışıyor.


Merak ediyorum: bu aynı zamanda odaklanabilir olan, ancak odaklanılmadığında kaydırması gereken Metin Görünümleri için de işe yarar mı? Şimdi, odak durumu değişse bile seçme durumu "sabit" mi?
Matthias

Sanırım öyle. Bir temeldeki odak değişikliğinin TextView(yani a gibi "seçilebilir" bir şeye gömülü olmayan ListView) seçili durumu neden değiştireceğini anlamıyorum .
Christopher Orr

Benim için de iyi çalışıyor. Cevabınız için teşekkür ederim. Tekrarlama şeklini değiştirme imkanı var mı ?!
Tima

@Mur: Evet, TextViewbelgeleri okuyun ve bir göz atın android:marqueeRepeatLimit.
Christopher Orr

1
Bu yöntem, görünümlerin odağını karıştırmadığı için odağa sahip olandan daha iyidir. Ebeveynlerinin odaklanmasını gerektiren görüşleriniz varsa, bu yöntem odağı bozacaktır. Bu yöntem basit, etkilidir ve odağı her seferinde değiştirmek için bilgisayar korsanlarına dayanmaz. Teşekkür ederim!
Ionut Negru

75

Sadece bu parametreleri TextView'unuza yerleştirin. İşe yarıyor :)

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

1
eğer bu cevap dizisi ölmemişse, bence bu kabul edilen cevap olmalıdır. Bunu, metin görünümü için XML tanımıma ekledim ve ilk çekimde işe yaradı. Başka önerileri denedim ve bu en basit olanı. - Ayrıca, "android: marqueeRepeatLimit =" ekleyerek marquee_forever" süresiz kaydırma yapar
Brack

19
Bunun kullanılması, TextView içindeyse ListView Satırının odak seçimini bozar.
Tivie

Mükemmel çalışıyor. Basit ve zarif çözüm. Teşekkürler!
Rabi

TextView kayan yazı nasıl başlatılır ve durdurulur
Dwivedi Ji

Diğer yanıtı deneyene kadar bu benim için işe yaramadı - textView.setSelected (true);
Justin

13

TranslateAnimationGörünümü belirli bir miktarda bir yönde "çekerek" çalışır. Bu "çekmeye" nereden başlayacağınızı ve nerede biteceğini belirleyebilirsiniz.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta, X eksenindeki hareketin başlangıç ​​konumunun ofsetini ayarlar.

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, hareketin X eksenindeki ofset bitiş konumunu tanımlar.

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

Metninizin genişliği, XDelta ve toXDelta arasındaki farkın modülünden daha büyükse, metin ekranda tamamen hareket edemez ve tamamen hareket edemez.


Misal

Ekran boyutumuzun 320x240 piksel olduğunu varsayalım. 700 piksel genişliğinde bir metin içeren bir TextView'ımız var ve ifadenin sonunu görebilmemiz için metni "çeken" bir animasyon oluşturmak istiyoruz.

                                       (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... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

Önce fromXDelta = 0hareketin bir başlangıç ​​ofseti olmayacak şekilde ayarladık . Şimdi toXDelta değerini bulmamız gerekiyor. İstenilen efekti elde etmek için metni ekrandan tam olarak yaydığı piksel ile "çekmemiz" gerekir. (şemada <<<< X px >>>> ile temsil edilir) Metnimiz 700 genişliğe sahip olduğundan ve görünür alan 320 piksel (ekran genişliği) olduğundan şunları ayarladık:

tXDelta = 700 - 320 = 380

Ve Ekran Genişliğini ve Metin Genişliğini nasıl anlarız?


Kod

Zarah Snippet'ini başlangıç ​​noktası olarak almak:

    /**
     * @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;
}

Bunu gerçekleştirmenin daha kolay yolları olabilir, ancak bu, aklınıza gelebilecek her görünüm için işe yarar ve yeniden kullanılabilir. TextView'in etkin / onFocus yeteneklerini bozmadan ListView'da bir TextView'ı canlandırmak istiyorsanız özellikle kullanışlıdır. Ayrıca, Görünüm odaklanmasa bile sürekli olarak kayar.


Yukarıdaki cevabım (yani bir satır kod textView.setSelected(true);ekleyin :) sizin durumunuzda işe yaramıyor mu?
Christopher Orr

Ne yazık ki hayır. Her satırda birkaç TextView ile doldurulmuş bir ListView vardı (dolayısıyla uzay krizi = P). metin görünümünün her satırı tıklanabilir ve bir bağlam menüsü açılır. SetSelected'ın true olarak ayarlanması bağlam menüsünü bozuyor gibi görünüyor.
Tivie

bu mu? Çoğu durumda aşırı ısınma olabilir. Benim için yukarıda açıklanan sebepten dolayı tek çözüm buydu. (yeniden kullanılabilir, btw!) = P
Tivie

12

Hâlâ cevaba ihtiyacınız var mı bilmiyorum ama bunu yapmanın kolay bir yolunu buldum.

Animasyonunuzu şu şekilde ayarlayın:

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_YVe END_POS_Yolan floatdeğerler, sırasında TICKER_DURATIONbir birint benim diğer sabitleri ile ilan etti.

Daha sonra artık bu animasyonu TextView'unuza uygulayabilirsiniz:

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

Ve bu kadar. :)

Animasyonum ekranın dışında (300f) sağ tarafta başlıyor ve 15 saniye (15000) süreyle ekranın dışında (-300f) sol tarafta bitiyor.


1
Bu çok basit görünmüyor. Ama yine de cevaba ihtiyacı olduğunu sanmıyorum; yukarıdaki kabul edilen cevaba bakın .. :)
Christopher Orr

2
Ancak bu çözümün yeni bir sınıf oluşturmaktan daha basit olduğunu düşünüyorum. : D Olduğu gibi, canlandırmak istediğiniz diğer görünümler için animasyon nesnesini yeniden kullanabilirsiniz. ;)
Zarah

Yine de iyi çalışıyor, ama uzun metinleri görüntülemek için ne yapmalıyım ?! Şimdi metnim sadece kesilecek
Tima

@Mur Votema: TextView'ınızın genişliğini wrap_content olarak ayarlamayı denediniz mi?
Zarah

3
Harika bir çözüm değil, çünkü boyut ve süre parametreleri son derece metin boyutuna bağlı. Ayrıca, metin uzunluğu görünüm genişliğinden daha az olsa bile canlandırılacaktır. setSelected (true) gerçekten en kolay çözümdür.
Anm

5

Seçim çerçevesi metin öğeleri içeren bir ListView için aşağıdaki kodu yazdım. Yukarıda açıklanan setSelected çözümüne dayanmaktadır. Temel olarak, ArrayAdapter sınıfını genişletiyorum ve döndürmeden önce TextView öğesini seçmek için getView yöntemini geçersiz kılıyorum:

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

Bu, google aramamın en üstünde beliren cevaptır, bu yüzden bunu oldukça sık hatırlamakta zorlandığım için burada yararlı bir cevap gönderebileceğimi düşündüm. Her neyse, bu benim için çalışıyor ve XML nitelikleri ve bir onFocusChangeListener gerektiriyor.

//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" />

// Java'da

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.