ellipsize = "marquee"를 항상 스크롤하는 방법이 있습니까?


93

TextView에 선택 윤곽 효과를 사용하고 싶지만 TextView에 포커스가있을 때만 텍스트가 스크롤됩니다. 그것은 문제입니다. 제 경우에는 할 수 없기 때문입니다.

나는 사용하고있다 :

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

TextView가 항상 텍스트를 스크롤하도록하는 방법이 있습니까? 이 작업이 Android Market 앱에서 수행되는 것을 보았습니다. 여기서 앱 이름이 포커스를받지 않더라도 제목 표시 줄에서 스크롤되지만 API 문서에서 언급되지 않았습니다.


선택 윤곽 작업을하려면 TextView를 선택해야합니다. 초점은 선택을 제공하지만 반전은 제공하지 않습니다.
— Denis Gladkiy

1
alwaysMarqueeTextView의 시도 stackoverflow.com/a/28806003/3496570을
— AndroidGeek

나는이 하나에 대한 정답을 바꿀 것입니다. stackoverflow.com/a/3700651/4548520
— user25

답변:


62

나는 문제에 직면했고 내가 생각 해낸 가장 짧은 해결책은 TextView에서 파생 된 새 클래스를 만드는 것입니다. 클래스는 세 가지 메서드 onFocusChanged , onWindowFocusChanged 및 isFocused 를 재정 의하여 TextView가 모두 포커스를 받도록해야합니다.

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

완벽합니다. 이것은 제가 찾던 솔루션입니다.
— Jason

6
메뉴가 팝업 될 때 선택 윤곽이 중지되지 않도록하려면 onWindowFocusChanged 메서드도 재정의해야합니다.
— virsir

7
그건 그렇고, 우리는 상태 저장 드로어 블을 엉망으로 만들기 때문에 실제로이 솔루션에 문제가있었습니다. 포커스 인 / 포커스 아웃으로 드로어 블을 변경하면이 문제가 발생합니다. 이 해킹이 원인이라는 것을 깨달을 때까지 거의 한 시간의 디버깅 시간이 걸렸습니다.
— Matthias

문제에 대한 자세한 설명을 제공 할 수 있습니까? 이 기능을 많은 앱에서 사용합니다. 저도이 문제를 살펴보고 싶습니다.
— hnviet 2010

1
이 해킹은 훌륭하게 작동하며 여러 TextView가 동시에 화면에있을 때만 필요합니다 (ListView에서 사용할 때와 같이)-일반적으로 그중 하나만 초점을 맞출 수 있기 때문에이 솔루션은 모든 것을 알려 시스템을 '트릭'합니다. :) 그렇지 않으면 단일 TextView의 경우 stackoverflow.com/a/3510891/258848 과 같은 더 간단한 anwer를 사용해야합니다.
— dimsuz

120

나는 오늘 마침내이 문제에 대해 생각해 냈고 hierarchyviewerAndroid Market 응용 프로그램에 불을 붙 였습니다.

앱의 세부 정보 화면에서 제목을 보면 평범한 오래된 TextView. 그 속성을 조사한 결과 초점이 ​​맞지 않았고, 초점을 맞출 수 없었 으며 일반적으로 매우 평범한 것으로 나타났습니다. 단, 선택된 것으로 표시되었다는 사실을 제외하고는 말입니다 .

나중에 한 줄의 코드가 작동했습니다. :)

textView.setSelected(true);

이것은 Javadoc이 말하는 것을 감안할 때 의미 가 있습니다 .

보기를 선택하거나 선택하지 않을 수 있습니다. 선택은 초점과 동일하지 않습니다. 보기는 일반적으로 ListView 또는 GridView와 같은 AdapterView의 컨텍스트에서 선택됩니다.

즉, 마켓 앱에서와 같이 목록보기에서 항목을 스크롤 할 때만 지금 선택한 텍스트가 스크롤을 시작합니다. 그리고이 특정 항목 TextView은 포커스를 받거나 클릭 할 수 없기 때문에 선택 상태를 잃지 않습니다.

불행히도 내가 아는 한 레이아웃 XML에서 선택한 상태를 미리 설정할 수있는 방법이 없습니다.
그러나 위의 한 줄짜리가 잘 작동합니다.


그냥 궁금해 : 이것은 초점을 맞출 수 있지만 초점이 맞지 않을 때 스크롤 해야하는 TextView에서도 작동합니까? 포커스 상태가 변경 되어도 선택 상태가 "고정"됩니까?
— 마티아스

그런 것 같아요. 기본 TextView(예 : "선택 가능한"항목에 ​​포함되지 않은 항목) 에 대한 포커스 변경이 왜 ListView선택한 상태를 변경 하는지 모르겠습니다 .
— Christopher Orr

나에게도 잘 작동합니다. 답변 주셔서 감사합니다. 반복 방식을 바꿀 가능성이 있습니까?!
— Tima

@Mur : 예, TextView문서를 읽고 android:marqueeRepeatLimit.
— Christopher Orr

1
이 방법은 뷰 포커스를 엉망으로 만들지 않기 때문에 포커스가있는 방법보다 낫습니다. 부모가 집중해야하는 견해가 있다면 그 방법은 초점을 엉망으로 만들 것입니다. 이 방법은 간단하고 효율적이며 매번 초점을 변경하기 위해 해킹에 의존하지 않습니다. 감사합니다!
— Ionut Negru

75

이 매개 변수를 TextView에 넣으십시오. 효과가있다 :)

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

1
이 답변 스레드가 아직 죽지 않았다면 내 의견으로는 이것이 허용되는 답변이어야합니다. 나는 이것을 텍스트 뷰에 대한 XML 정의에 추가했고 첫 번째 샷에서 작동했습니다. 나는 다른 제안을 시도했으며 이것이 가장 간단합니다. -또한 "android : marqueeRepeatLimit ="marquee_forever "를 추가하면 무기한 스크롤됩니다
— brack

19
이것을 사용하면 TextView가 내부에있는 경우 ListView 행의 포커스 선택이 중단됩니다.
— Tivie 2010

완벽하게 작동합니다. 간단하고 우아한 솔루션. 감사!
— Rabi

TextView 선택 윤곽을 시작하고 중지하는 방법
— Dwivedi Ji

이것은 다른 대답을 시도하기 전까지는 작동하지 않았습니다. textView.setSelected (true);
— Justin

13

TranslateAnimation뷰를 지정된 양만큼 한 방향으로 "당겨"작동합니다. 이 "풀링"을 시작할 위치와 끝점을 설정할 수 있습니다.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta는 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는 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.

텍스트 너비가 fromXDelta와 toXDelta의 차이 모듈보다 크면 텍스트가 화면 내에서 완전히 움직일 수 없습니다.


예

화면 크기가 320x240 픽셀이라고 가정 해 보겠습니다. 너비가 700px 인 텍스트가있는 TextView가 있고 문구의 끝을 볼 수 있도록 텍스트를 "당기는"애니메이션을 만들고 싶습니다.

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

먼저 fromXDelta = 0움직임에 시작 오프셋이 없도록 설정 합니다. 이제 toXDelta 값을 계산해야합니다. 원하는 효과를 얻으려면 텍스트가 화면 밖으로 확장되는 것과 똑같은 픽셀을 "당겨"야합니다. (구성표에서 <<<< X px >>>>로 표시됩니다.) 텍스트 너비가 700이고 가시 영역이 320px (화면 너비)이므로 다음을 설정합니다.

tXDelta = 700 - 320 = 380

그리고 화면 너비와 텍스트 너비를 어떻게 계산할까요?


암호

Zarah Snippet을 시작점으로 사용 :

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

이 작업을 수행하는 더 쉬운 방법이있을 수 있지만 이것은 생각할 수있는 모든보기에서 작동하며 재사용 할 수 있습니다. textView의 활성화 / onFocus 기능을 중단하지 않고 ListView에서 TextView에 애니메이션을 적용하려는 경우 특히 유용합니다. 또한 뷰에 초점이 맞춰져 있지 않아도 계속 스크롤됩니다.


위의 답변 (예 : 코드 한 줄 추가 textView.setSelected(true);:)이 귀하의 상황에서 작동하지 않습니까?
— Christopher Orr

불행하게도. 각 행에 여러 TextView로 채워진 ListView가 있습니다 (따라서 공간 위기 = P). textview의 각 행을 클릭 할 수 있으며 상황에 맞는 메뉴가 나타납니다. setSelected를 true로 설정하면 상황에 맞는 메뉴가 손상되는 것 같습니다.
— Tivie 2010

맞나요? 대부분의 경우 오버 샷이 될 수 있습니다. 나에게는 위에서 설명한 이유 때문에 유일한 해결책이었습니다. (재사용 가능합니다, btw!) = P
— Tivie 2010 년

12

여전히 답이 필요한지 모르겠지만 쉽게 할 수있는 방법을 찾았습니다.

다음과 같이 애니메이션을 설정하십시오.

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_Y하고 END_POS_Y있는 float반면, 값 TICKER_DURATION입니다 int내 다른 상수를 선언했다.

그런 다음 이제이 애니메이션을 TextView에 적용 할 수 있습니다.

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

그리고 그게 다야. :)

내 애니메이션은 오른쪽 화면 (300f)에서 시작하여 왼쪽 화면 (-300f)에서 15 초 (15000)의 지속 시간으로 끝납니다.


1
그다지 간단하지 않은 것 같습니다. 그러나 나는 그가 여전히 답을 필요로한다고 생각하지 않는다. 위의 수락 된 답변을 참조하십시오. :)
— Christopher Orr

2
하지만이 솔루션은 새 클래스를 만드는 것보다 더 간단하다고 생각합니다. : D 그대로, 애니메이션을 적용하려는 다른 뷰에 애니메이션 개체를 재사용 할 수도 있습니다. ;)
— Zarah 2010-08-13

잘 작동하지만 긴 텍스트를 표시하려면 어떻게해야합니까?! 이제 내 텍스트는 cuted의 것
— TIMA

@Mur Votema : TextView의 너비를 wrap_content로 설정해 보셨습니까?
— Zarah

3
크기 및 기간 매개 변수가 텍스트 크기에 크게 의존하기 때문에 훌륭한 솔루션은 아닙니다. 또한 텍스트 길이가보기 너비보다 작더라도 애니메이션이 적용됩니다. setSelected (true)는 정말 가장 쉬운 솔루션입니다.
— Anm

5

선택 윤곽 텍스트 항목이있는 ListView에 대해 다음 코드를 작성했습니다. 위에서 설명한 setSelected 솔루션을 기반으로합니다. 기본적으로 ArrayAdapter 클래스를 확장하고 getView 메서드를 재정 의하여 TextView를 반환하기 전에 선택합니다.

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

이것은 내 Google 검색 상단에 나타나는 답변이므로 꽤 자주 기억하는 데 어려움을 겪고 있기 때문에 여기에 유용한 답변을 게시 할 수 있다고 생각했습니다. 어쨌든 이것은 나를 위해 작동하며 XML 속성과 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" />

// 자바

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.