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 , onWindowFocusChangedisFocused 를 재정 의하여 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.