简体   繁体   English

单击行中的按钮突出显示 ListView 中的行

[英]Highlighting a row in ListView on click of a button in the row

I am new to Android development and I am creating a Music Player app.我是 Android 开发的新手,我正在创建一个音乐播放器应用程序。 I am done with the logical part.我已经完成了逻辑部分。 Now I am focusing on the appearance of the app.现在我专注于应用程序的外观。 One of the things I want to do is to highlight a row when the corresponding 'Play' button in the row is clicked.我想做的一件事是在单击行中相应的“播放”按钮时突出显示该行。

Desired Effect: When Play button of a row is clicked the row gets highlighted (Background color changes) and simultaneously the background of the last clicked row gets reset.期望的效果:当点击一行的播放按钮时,该行被突出显示(背景颜色改变),同时最后点击的行的背景被重置。

Attempt: I tried storing the previously selected View and make required changes in the current and previous views.尝试:我尝试存储之前选择的视图并在当前和之前的视图中进行必要的更改。

Following is the code I wrote in my custom Adapter for the ListView:以下是我在自定义适配器中为 ListView 编写的代码:

(Relevant code is written in the onClickListener() of the buttons) (相关代码写在按钮的onClickListener()中)

package com.example.mediaplayer;

import android.app.Activity;
import android.content.ContentUris;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;

public class MusicAdapter extends ArrayAdapter<Music> {

    private MediaPlayer mp;
    private ArrayList<Integer> Lengths = new ArrayList<>();
    private int mCurrentPosition = 0;
    private LinearLayout mpreviousView = null;
    private LinearLayout mitemView = null;
    private IAdapterToFragment listener;

    private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            releaseMediaPlayer();
            Lengths.set(mCurrentPosition, 0);
            mitemView.setBackgroundColor(Color.parseColor("#FDBCA8"));
        }
    };

    public interface IAdapterToFragment {
        void onSuccess(String songName);
    }

    public MusicAdapter(Activity context, ArrayList<Music> songs, IAdapterToFragment listener) {

        super(context, 0, songs);
        for(int i = 0; i < songs.size(); i ++) {
            Lengths.add(0);
        }

        this.listener = listener;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        mpreviousView = mitemView;

        View musicItemView = convertView;

        if(musicItemView == null) {
            musicItemView = LayoutInflater.from(getContext()).inflate(
                    R.layout.music_item, parent, false);
        }

        Music currentSong = getItem(position);

        LinearLayout itemView = musicItemView.findViewById(R.id.item);
        mitemView = itemView;

        TextView songnameView = musicItemView.findViewById(R.id.song_name);
        songnameView.setText(currentSong.getMusicName());

        Button stop = (Button) musicItemView.findViewById(R.id.stop_button);
        Button pause = (Button) musicItemView.findViewById(R.id.pause_button);
        Button play = (Button) musicItemView.findViewById(R.id.play_button);

        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                releaseMediaPlayer();

                if(listener != null)
                    listener.onSuccess(currentSong.getMusicName());

                mCurrentPosition = position;

                itemView.setBackgroundColor(Color.parseColor("#FAA185"));

                long songID = currentSong.getMusicResourceId();
                Uri uri = ContentUris.withAppendedId(
                        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                        songID);
                mp = MediaPlayer.create(getContext(), uri);

                mp.start();
                mp.seekTo(Lengths.get(position));

                mp.setOnCompletionListener(mCompletionListener);
            }
        });

        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(listener != null)
                    listener.onSuccess("Play another song!");

                releaseMediaPlayer();
                itemView.setBackgroundColor(Color.parseColor("#FDBCA8"));
                Lengths.set(position, 0);
            }
        });

        pause.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int currentPosition = 0;
                if(mp != null) {
                    currentPosition = mp.getCurrentPosition();
                    mp.stop();
                    Lengths.set(position, currentPosition);
                    releaseMediaPlayer();
//                    mp.setOnCompletionListener(mCompletionListener);
                }
            }
        });

        return musicItemView;
    }

    private void releaseMediaPlayer() {
        if (mp != null) {
            mp.release();
            mp = null;

            if(mpreviousView != null)
                mpreviousView.setBackgroundColor(Color.parseColor("#FDBCA8"));

//            mp.abandonAudioFocus(mOnAudioFocusChangeListener);
        }
    }
}

This however doesn't work because ListView recycles the views.然而这不起作用,因为 ListView 回收视图。 So I am not accessing a distinct row, rather, I am making changes to many rows simultaneously.因此,我没有访问不同的行,而是同时对多行进行更改。

Questions:问题:

  1. Is there a way I can uniquely access a row in a ListView in the adapter class itself?有没有办法可以唯一地访问适配器 class 本身的 ListView 中的一行?

  2. Is there an easier way to achieve the desired effect?有没有更简单的方法来达到预期的效果?

Thank you.谢谢你。

EDIT:编辑:

After researching a lot and trying several methods from related questions, I still haven't figured out a way to get the desired effect.经过大量研究并从相关问题中尝试了几种方法后,我仍然没有想出一种获得预期效果的方法。 All the methods I tried result in multiple rows getting highlighted when one button is clicked, again, due to recycling of views.由于视图的回收,我尝试过的所有方法都会导致在单击一个按钮时突出显示多行。 If you are looking for an alternate solution, you can either:如果您正在寻找替代解决方案,您可以:

  1. (Not Optimal) Replace ListView with some layout that doesn't recycle views. (不是最佳的)用一些不回收视图的布局替换 ListView。 This way the exactly one item gets highlighted and remains highlighted even when you scroll past it.这样,即使滚动过去,恰好一个项目也会突出显示并保持突出显示。

  2. Remove all types of buttons from the list, create a list item selector and set it as the background for you list_item.从列表中删除所有类型的按钮,创建一个列表项选择器并将其设置为您 list_item 的背景。 Follow the steps mentioned here: Reset background color in a ListView .请按照此处提到的步骤操作: 在 ListView 中重置背景颜色 This is the one I am using for my app now.这是我现在用于我的应用程序的那个。

Set it such that all ListView item's Layout has a corresponding boundary or whatever with the transparent color.设置它,使所有 ListView 项目的布局都具有相应的边界或任何具有透明颜色的边界。 When that particular item has been accessed, simply change the color of that widget to something else.访问该特定项目后,只需将该小部件的颜色更改为其他颜色即可。 Don't forget to change back the color to transparent once it's task has finished.任务完成后不要忘记将颜色改回透明。 You can do multiple boundaries/ whaever you want provided it is one ListView item and not multiple.只要它是一个 ListView 项目而不是多个,你可以做多个边界/任何你想要的。 There are other ways to handle that, but in most cases, is not a good design pattern.还有其他方法可以处理这个问题,但在大多数情况下,这不是一个好的设计模式。

Stop checking convertView for null will stop ListView from recycle item views, so change:停止检查 null 的 convertView 将停止 ListView 回收项目视图,因此更改:

    View musicItemView = convertView;

    if(musicItemView == null) {
        musicItemView = LayoutInflater.from(getContext()).inflate(
                R.layout.music_item, parent, false);
    }

to

    View musicItemView = LayoutInflater.from(getContext()).inflate(R.layout.music_item, parent, false);

Then every row is created with new views.然后用新视图创建每一行。

Try this adapter code:试试这个适配器代码:

public class MusicAdapter extends ArrayAdapter<Music> {

private MediaPlayer mp;
private ArrayList<Integer> Lengths = new ArrayList<>();
private int mCurrentPosition = -1; //Changed
//private LinearLayout mpreviousView = null;
private LinearLayout mitemView = null;
private IAdapterToFragment listener;

private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mp) {
        releaseMediaPlayer();
        Lengths.set(mCurrentPosition, 0);
        mitemView.setBackgroundColor(Color.parseColor("#FDBCA8"));
        mitemView = null; //Added
        mCurrentPosition = -1; //Added
    }
};

public interface IAdapterToFragment {
    void onSuccess(String songName);
}

public MusicAdapter(Activity context, ArrayList<Music> songs, IAdapterToFragment listener) {

    super(context, 0, songs);
    for(int i = 0; i < songs.size(); i ++) {
        Lengths.add(0);
    }

    this.listener = listener;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    //mpreviousView = mitemView;

    //View musicItemView = convertView;

    //if(musicItemView == null) {
        View musicItemView = LayoutInflater.from(getContext()).inflate(R.layout.music_item, parent, false);
    //}

    Music currentSong = getItem(position);

    LinearLayout itemView = musicItemView.findViewById(R.id.item);
    mitemView = itemView;

    TextView songnameView = musicItemView.findViewById(R.id.song_name);
    songnameView.setText(currentSong.getMusicName());
    if (mCurrentPosition == position) itemView.setBackgroundColor(Color.parseColor("#FAA185")); //Added

    Button stop = (Button) musicItemView.findViewById(R.id.stop_button);
    Button pause = (Button) musicItemView.findViewById(R.id.pause_button);
    Button play = (Button) musicItemView.findViewById(R.id.play_button);

    play.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            releaseMediaPlayer();

            if(listener != null)
                listener.onSuccess(currentSong.getMusicName());

            mCurrentPosition = position;

            itemView.setBackgroundColor(Color.parseColor("#FAA185"));
            mitemView = itemView; //Added

            long songID = currentSong.getMusicResourceId();
            Uri uri = ContentUris.withAppendedId(
                    android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    songID);
            mp = MediaPlayer.create(getContext(), uri);

            mp.start();
            mp.seekTo(Lengths.get(position));

            mp.setOnCompletionListener(mCompletionListener);
        }
    });

    stop.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(listener != null)
                listener.onSuccess("Play another song!");

            releaseMediaPlayer();
            itemView.setBackgroundColor(Color.parseColor("#FDBCA8"));
            Lengths.set(position, 0);
            mitemView = null; //Added
        }
    });

    pause.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int currentPosition = 0;
            if(mp != null) {
                currentPosition = mp.getCurrentPosition();
                mp.stop();
                Lengths.set(position, currentPosition);
                releaseMediaPlayer();
//                    mp.setOnCompletionListener(mCompletionListener);
            }
        }
    });

    return musicItemView;
}

private void releaseMediaPlayer() {
    if (mp != null) {
        mp.release();
        mp = null;

        if (mitemView != null) //Changed
            mitemView.setBackgroundColor(Color.parseColor("#FDBCA8")); //Changed

//            mp.abandonAudioFocus(mOnAudioFocusChangeListener);
    }
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM