滚动和恢复时按钮更改状态
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;
}
});
希望能帮到和我有同样问题的人。
我有一个 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;
}
});
希望能帮到和我有同样问题的人。