滚动和恢复时按钮更改状态

Button change state when scrolling and resuming

我有一个 ListView,此列表中的一些 View 有一个 Button(并非每个视图都有)。此按钮有 2 种状态:开始和停止。因此,每当我滚动列表或打开另一个应用程序,然后返回此应用程序(不是永久关闭)时,按钮的状态就会变回之前的状态。无论如何要修复它?

它工作正常。问题是状态没有保存,所以当我滚动时,它再次调用 getView ,状态变回以前的状态。当更改应用程序时,然后也返回


这是 getView 函数,所有问题都从这里开始:

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ContentViewHolder.CaptionTitleHolder captionHolder = null;
        ContentViewHolder.PreCookingViewHolder preCookingHolder = null;
        ContentViewHolder.CookingViewHolder cookingHolder = null;
        int type = getItemViewType(position);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (type == CAPTION_TITLE){
            if (convertView == null){
                convertView = inflater.inflate(R.layout.caption_title_view, parent, false);
                captionHolder = new ContentViewHolder.CaptionTitleHolder();
                captionHolder.text = (TextView) convertView.findViewById(R.id.caption_title_textview);
                convertView.setTag(captionHolder);
            } else {
                captionHolder = (ContentViewHolder.CaptionTitleHolder) convertView.getTag();
            }
            captionHolder.text.setText(((RecipeContentActivity2.CaptionTitle) allItems.get(position)).getContent());

        } else if (type == COOKING){
            if (convertView == null){
                convertView = inflater.inflate(R.layout.cooking_steps_and_timer, parent, false);
                cookingHolder = new ContentViewHolder.CookingViewHolder();
                cookingHolder.text = (TextView) convertView.findViewById(R.id.cooking_step_content);
                cookingHolder.time = (TextView) convertView.findViewById(R.id.cooking_timer);
                cookingHolder.skipButton = (Button) convertView.findViewById(R.id.button_skip);
                cookingHolder.startButton = (Button) convertView.findViewById(R.id.button_timer);

                convertView.setTag(cookingHolder);
            } else {
                cookingHolder = (ContentViewHolder.CookingViewHolder) convertView.getTag();
            }
            CookingStep myStep = (CookingStep) allItems.get(position);
            setUpCookingView(convertView, cookingHolder, myStep);
        } else {
            if (convertView == null){
                convertView = inflater.inflate(R.layout.pre_cooking_view, parent, false);
                preCookingHolder = new ContentViewHolder.PreCookingViewHolder();
                preCookingHolder.text = (TextView) convertView.findViewById(R.id.pre_cooking_textview);
                convertView.setTag(preCookingHolder);
            } else {
                preCookingHolder = (ContentViewHolder.PreCookingViewHolder) convertView.getTag();
            }
            preCookingHolder.text.setText((String) allItems.get(position));
        }

        return convertView;
    }

    private void setUpCookingView(final View c, final ContentViewHolder.CookingViewHolder view, final CookingStep step){
        String stepOrder = context.getResources().getString(R.string.step_order) + " " + step.getOrder();
        String content = "<b>" + stepOrder + ":</b> " + step.getContent() + "\n";
        view.text.setText(Html.fromHtml(content));

        if (step.getMinute() != null && step.getMinute() > 0){
            if (step.getMyTimer() == null) {
                CookingTimer2 timer = new CookingTimer2(step.getMinute()) {

                    @Override
                    public void upgradeUI() {
                        view.time.setText(toString());
                    }
                };
                step.setTimer(timer);
            }
            view.time.setVisibility(View.VISIBLE);
            view.startButton.setVisibility(View.VISIBLE);
            view.skipButton.setVisibility(View.VISIBLE);



            view.startButton.setText(R.string.button_available);
            view.skipButton.setText(R.string.skip_button_content);
            view.startButton.setEnabled(step.isTurnEnable());
            view.skipButton.setEnabled(step.isTurnEnable());
            view.time.setText(step.getMyTimer().toString());


            view.startButton.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (!view.startButton.isPressed()) {
                            view.startButton.setPressed(true);
                            view.startButton.setText(R.string.button_pressed);
                            step.getMyTimer().doStart();
                            //c.setTag(R.id.button_timer, true);
                        } else {
                            view.startButton.setPressed(false);
                            view.startButton.setText(R.string.button_available);
                            step.getMyTimer().doStop();
                            //c.setTag(R.id.button_timer, false);
                        }
                    }
                    return true;
                }
            });

            view.skipButton.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        step.getMyTimer().doStop();
                        ((RecipeContentActivity2) context).enableNextStep();
                    }
                    return true;
                }
            });
        } else {
            view.time.setVisibility(View.GONE);
            view.startButton.setVisibility(View.GONE);
            view.skipButton.setVisibility(View.GONE);
        }

    }

我设法解决了使用此计时器状态滚动时出现的问题。感谢 milosmns 提醒我我的计时器还在计时

if (step.getMyTimer().isTicking()){
                view.startButton.setPressed(true);
                view.startButton.setText(R.string.button_pressed);
            }

但是当切换到另一个应用程序时我仍然遇到这个问题,然后返回。似乎在这种情况下, getView 没有被调用。那么我接下来应该做什么?


所以是的,我找到了一种骇人听闻的方法来做到这一点。不过我不太喜欢

在我的 activity 中:

@Override
    protected void onResume() {
        super.onResume();
        if (wasStoped)
            ((MyAdapter)listContent.getAdapter()).notifyDataSetChanged();
    }

    @Override
    protected void onStop() {
        wasStoped = true;
        super.onStop();
    }

我还想知道其他方法

使用支架class喜欢:

public View getView(final int i, View view, final ViewGroup viewGroup) {
        View vi = view;
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            vi = inflater.inflate(R.layout.listview_row_cart, null);
            holder.yourbutton = (Button) vi.findViewById(R.id.btn);
            vi.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
            holder.yourbutton.setText("Start");
     }
     class ViewHolder {
           Button yourbutton
    }

您的 onCreate 方法很可能被再次调用以重建视图并且正在刷新按钮的状态,您需要保存按钮的状态。

您可以使用 sharedPreferences 执行此操作。

您可以查看有关如何实现此功能的文档 Here

所以我能够通过为自己实现具有自定义状态的 Button 来解决这个问题。是的,我只是意识到取决于按钮的状态 pressed 不是办法,因为有太多的干扰可以改变这种状态。

public class TimerButtonControl extends Button{
    private static final int[] STATE_RUN = {R.attr.timer_run};

    private boolean running = false;

    public TimerButtonControl(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setRun(boolean r){
        running = r;
        refreshDrawableState();
    }
    public boolean isRunning() {return running; }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState =  super.onCreateDrawableState(extraSpace + 1);
        if (running) {
            mergeDrawableStates(drawableState, STATE_RUN);
        }
        return drawableState;
    }
}

然后为这个按钮定义 xml :

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:drawable="@drawable/clock_button_not_pressed"
        app:timer_run="false" android:state_enabled="true" />
    <item android:drawable="@drawable/clock_button_pressed"
        app:timer_run="true" android:state_enabled="true" />
    <item android:drawable="@drawable/button_unavailable"
        android:state_enabled="false" />
</selector>

然后在我的布局中使用它:

<com.username.mypackage.uiassistance.TimerButtonControl
        android:id="@+id/button_timer"
        android:padding="4dip"
        android:layout_width="90dip"
        android:layout_height="wrap_content"
        android:layout_below="@id/cooking_step_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:background="@drawable/timer_button"
        android:enabled="false"/>

最后在适配器内部:

if (step.getMyTimer().isTicking()){
                view.startButton.setRun(true);
                view.startButton.setText(R.string.button_pressed);
            }

            view.startButton.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (!view.startButton.isRunning()) {
                            view.startButton.setRun(true);
                            view.startButton.setText(R.string.button_pressed);
                            step.getMyTimer().doStart();
                        } else {
                            view.startButton.setRun(false);
                            view.startButton.setText(R.string.button_available);
                            step.getMyTimer().doStop();
                        }
                    }
                    return true;
                }
            });

希望能帮到和我有同样问题的人。