如何将 android tts 与 recyclerview smoothscroll 同步

how to sync android tts with a recyclerview smoothscroll

好的,所以我有一个回收站视图,我向其中添加了一堆文本,文本位于具有固定高度和宽度的卡片中,当我按下按钮时,使用 androids 读出文本语音合成引擎。

问题是如果文本超出了视图的空间,我希望回收器视图滚动到 text/recycler 视图的开头,读出文本并滚动视图,同时保持同步或使用 android tts 引擎减慢速度,所以我在 的帮助下在我的回收站视图上设置了一个自定义 linearlayoutmanager,它允许我根据浮点变量加快或减慢滚动速度,然后我尝试了几种方法来完成这个无济于事,发现我需要使用 UtteranceProgressListener 所以我创建了一个方法来更新卡片的位置并试图像这样将它传递给 UtteranceProgressListener

    public void speakWordsExclusive(String speech, final int position) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        myTTS.speak(speech, TextToSpeech.QUEUE_ADD, params, "");
    }
    else{
        myTTS.speak(speech, TextToSpeech.QUEUE_ADD, map);
    }
    myTTS.setOnUtteranceProgressListener(new UtteranceProgressListener() {
        @Override
        public void onStart(final String utteranceId) {
        }

        @Override
        public void onDone(final String utteranceId) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
       //position should print 1,2,3, etc but just gives me the last number
       System.out.println("position UtteranceProgress " + position );
       //the line below will smooth scroll the view to the end position with 
       //no care for which cards is being read
       SpeakGridDB.recyclerView.getLayoutManager()
      .smoothScrollToPosition(SpeakGridDB.recyclerView, null, position );
                }
            });
        }
        @Override
        public void onError(String utteranceId) {
        }
    });
}

这不起作用位置总是最高的数字所以如果我期待 1,2,3,4 我实际上会像这样得到 4,

11-07 14:23:09.121 28882-28882/ss.sealstudios.com.socialstories 
I/System.out: position UtteranceProgress 4 
11-07 14:23:09.741 28882-  
28882/ss.sealstudios.com.socialstories 
I/System.out: position UtteranceProgress 4 
11-07 14:23:10.353 28882-
28882/ss.sealstudios.com.socialstories 
I/System.out: position UtteranceProgress 4 
11-07 14:23:10.944 28882-  
28882/ss.sealstudios.com.socialstories 
I/System.out: position UtteranceProgress 4

我通过下面的方法给 UtteranceProgressListener 位置

    public void speakAndMoveExclusive() {
    final ArrayList<String> list = new ArrayList<>();
    list.clear();
    words = list.toString();
    SpeakGridDB.recyclerView.getLayoutManager().scrollToPosition(0);
    for (int i = 0; i < SpeakGridDB.cardMakerList.size(); i++) {
        list.add(SpeakGridDB.cardMakerList.get(i).getCardSpeech());
        words = list.toString();
    }
    System.out.println(words);
    if (words == null) {
        speakWords("");
    } else if (words.contains(", 's")) {
        formatString = words.replaceFirst(", 's", "'s");
    } else if (words.contains(", ing")) {
        formatString = words.replaceFirst(", ing", "ing");
    }else{
        formatString = words;
    }
    List<String> items = Arrays.asList(formatString.split("\s*,\s*"));
    if (items.contains("[]")){
        speakWords("");
    }
    else{
        for(int j = 0; j < items.size();j++){

            speakWordsExclusive(items.get(j), j);
            //the below line prints the position just fine
            System.out.println("position j " + j);
            params.putString
            (TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"UniqueID" + j);
            map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"UniqueID" + 
            j);
        }
    }
} 

我在这里设置的位置变量显然不是位置,但它是相同的,打印输出反映了这一点,如下所示

11-07 14:23:08.452 28882-28882/ss.sealstudios.com.socialstories 
I/System.out: position j 0
11-07 14:23:08.454 28882-28882/ss.sealstudios.com.socialstories 
I/System.out: position j 1
11-07 14:23:08.456 28882-28882/ss.sealstudios.com.socialstories  
I/System.out: position j 2
11-07 14:23:08.459 28882-28882/ss.sealstudios.com.socialstories 
I/System.out: position j 3

如果我只是将其提供给静态 int 并将其提供给 onUtteranceProgressListener,那么我会得到稍微好一点的结果,但它们之间仍然不同步

所以我想知道他们之间发生了什么我已经查看了文档但似乎无法理解它我已经将我的呼叫转移到 onStart 而不是 onDone 希望得到更好的结果但是没有任何改变可以任何人帮我解决这个问题?

好的,就像@brandall 所说的最好的做法是设置一个 UtteranceProgressListener 一次,最好是从 onInit(int initStatus) 开始,所以我切换到这个模型并让它工作,我的代码通常适用于滚动视图,请注意我的代码将在 onDone 中粘贴抛出一个 NPE,我正在设置背景颜色与它不在视图中有关确保您从 UI 线程

更新视图
    public void onInit(int initStatus) {
    if (initStatus == TextToSpeech.SUCCESS) {
        myTTS.setLanguage(Locale.UK);
        //myExclusiveTTS.setLanguage(Locale.UK);
        myExclusiveTTS.setOnUtteranceProgressListener(new 
        UtteranceProgressListener() {
                @Override
                public void onDone(String utteranceId) {

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            SpeakGridDB.recyclerView.getLayoutManager()
                           .getChildAt(cardCountPosition)
                           .setBackgroundResource(R.drawable.border);
                            cardCountPosition ++;

                            if(cardCountPosition ==                 
                            SpeakGridDB.cardMakerList.size()){
                                cardCountPosition = 0;

                            }
                        }
                    });

                }

                @Override
                public void onError(String utteranceId) {
                }

                @Override
                public void onStart(String utteranceId) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                         moveView();
                         SpeakGridDB.recyclerView.getLayoutManager()
                        .getChildAt(cardCountPosition).setBackgroundResource
                        (R.drawable.selected_blue_border);
                        }
                    });
                }
            });

    } else if (initStatus == TextToSpeech.ERROR) {
        Toast.makeText(this, "Oops sorry! Text To Speech failed... 
        SimpleAAC cannot fix this", Toast.LENGTH_LONG).show();
    }
}

    public void moveView(){
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (cardCountPosition < SpeakGridDB.cardMakerList.size()){
           SpeakGridDB.recyclerView.getLayoutManager()
          .smoothScrollToPosition(SpeakGridDB.recyclerView, null,
           cardCountPosition + 1);
            }
            else{
               //this is never called
                cardCountPosition = 0;
            }

        }
    });
}