【问题标题】:a "List of Favorites" in android - re-change the rating barandroid中的“收藏夹列表” - 重新更改评分栏
【发布时间】:2014-02-06 11:20:33
【问题描述】:

我想在我的应用中创建一个收藏列表。 我正在使用数组适配器。

我有一个字符串和一个评级栏,只有一颗星! 我希望如果你按一次星星,它会点亮星星(并让它成为最爱) 当你再次按下它时,星星没有被填满......(现在它不再喜欢了)

我应该在这里写什么?如果问题甚至可以纠正这个问题吗?

public class ChooseFavorites extends Activity implements OnItemClickListener
{
    String[] stations;
    float[] rating;
    boolean[] ifCheacked;
    RatingAdapter ratingAdapter; 

ArrayAdapter<String> arr;
ListView list;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_choose_favorites);
    stations =  getResources().getStringArray(R.array.stations);
    rating = new float[stations.length];
    ifCheacked = new boolean[stations.length];
    Arrays.fill(ifCheacked, false);
    ratingAdapter = new RatingAdapter(this, R.layout.favorite_row, stations);
    list = (ListView)findViewById(R.id.stationsList1);
    list.setAdapter(ratingAdapter);
    list.setOnItemClickListener(this);

}




class RatingAdapter extends ArrayAdapter<String> 
{
    Context ctx;
    LayoutInflater inflater;
    TextView stationName;
    RatingBar star;


    public RatingAdapter(Context context, int textViewResourceId, String[] objects) 
    {
        super(context, textViewResourceId, objects);
        ctx = context;
        inflater = LayoutInflater.from(context);
    }



@Override
public View getView(int position, View convertView, ViewGroup parent) 
{
    View row = convertView;
    if(row==null)
    { // Object reuse
        inflater = getLayoutInflater();
        row = inflater.inflate(R.layout.favorite_row, parent, false);
    }
    stationName = (TextView)row.findViewById(R.id.textFavoriteItemInRow);
    stationName.setText(stations[position]);
    star= (RatingBar)row.findViewById(R.id.ratingBar1);
    if (!ifCheacked[position]) //ifChecked is false
    {
        star.setRating(rating[position]);
        star.setTag(position);
        ifCheacked[position] = true;
    }
    else
    {


    }
    star.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener()
    {
        public void onRatingChanged(RatingBar ratingBar, float rating2, boolean fromUser)
        {
            if(!fromUser) return;
            int index = (Integer)(ratingBar.getTag());
            rating[index] = rating2;
        }
    });
    return row;
}


    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        // TODO Auto-generated method stub

    }
}

【问题讨论】:

    标签: java android eclipse listview


    【解决方案1】:

    您可能不应该使用RatingBar,而应该使用CheckBox。我正在我的一个应用程序中使用CheckBox,完全符合您的需要。

    基本上你需要做的是:

    在您的 res\drawable\ 文件夹中,定义一个新的布局文件,假设您将其命名为 checkboxes.xml

    在该文件中,您将定义如下内容:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
      <item android:state_checked="true" android:drawable="@drawable/checkbox_star_down" />
      <item android:state_checked="false" android:drawable="@drawable/checkbox_star" />
    </selector>
    

    在我的例子中,两个可绘制对象都是两张 JPG 图片,一张星星闪烁,一张关闭。

    现在在您的行布局中,定义 CheckBox 而不是您的 RatingBar,如下所示:

    <CheckBox
       android:id="@+id/soloR"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_weight="0.6"
       android:onClick="somethingChanged"
       android:textSize="12sp"
       android:textColor="#FFFFFF"
       android:button="@drawable/checkboxes"
       android:text="@string/soloR" />
    

    很好,您可能看到android:button 属性设置为您刚刚定义的checkboxes。完成后,删除您的 star.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() ... 实现,并将其替换为:

    onCheckedChangeListener (CompoundButton.OnCheckedChangeListener listener) 
    

    onCheckedChanged的监听器提供了两个参数:CompoundButton buttonView, boolean isChecked

    基本上,第二个告诉你你的星星是否在发光。您的其余代码似乎通常是合理的,但是:

    • 我不会分配row = convertView。这是我见过很多次的做法,但没有任何意义,直接在 convertView 实例上工作。

    • 我不知道您在ListView 中工作了多少行,但如果它们太多或难以呈现,我会考虑使用viewHolders。如果您还没有与他们合作过,这里有一个 nice link 可以很好地解释这一点。

    • 我看到你在每一行都使用了findViewById()。这可能会导致巨大的性能问题,因为此调用非常昂贵。我会在你的类中保存两个可绘制对象(假设你的星星可能只有 2 个)并在构造函数中分配它们,所以你只处理它们一次 - 或者如我之前所说,为此使用 viewHolders。

    • 请记住一件事:如果您不保存更改的状态,一旦您的行从屏幕上“消失”(例如,因为用户在列表中滚动)并且该行是新呈现的,您将看到以前的状态 - 即不会保存更改。为此,在ArrayAdapter 扩展中处理数据非常重要,每次用户单击星号时,将其状态保存在您的类中。我的意思是你的第三个构造函数参数:public RatingAdapter(Context context, int textViewResourceId, String[] objects)。现在你只需调用super 就可以了,但你不保存它。请记住,这是您的工作数据,任何更改都应反映在该 Object 数组中,否则每次渲染行时,都不会保存更改。例如:

      class RatingAdapter extends ArrayAdapter<String> 
      {
          Context ctx;
          LayoutInflater inflater;
          TextView stationName;
          RatingBar star;
          ArrayMap<String, Boolean> rowLayout = ArrayMap<String, Boolean>();
      
          public RatingAdapter(Context context, int textViewResourceId, String[] objects) 
          {
              super(context, textViewResourceId, objects);
              ctx = context;
              inflater = LayoutInflater.from(context);
      
              for (String rowText : (String) objects)
                rowLayout.put(rowText, false);  // Supposing all your initial stars will be off
          }
      

      现在您要做的就是同步您的getView() 方法来告诉Android如何管理它。例如,如果值为false,则放掉星号 - 否则放上闪亮的星号等。

    ---- 编辑----

    关于如何跟踪更改:我不知道您是否最终决定使用viewHolders,所以我将仅说明全局案例。

    所有更改以及您想要跟踪的内容都应在您的getView() 方法中完成。在那个方法中,看到第二个参数是一个名为convertViewView。说得很模糊,这是每一行的布局,即每一行的所有内容都包含在每个convertView中。所以基本上,getView() 每行至少会被调用一次。

    假设您有一个布局,其中有一个 CheckBox,其 id 为 lvCheckBox 和一个 TextView,其 id 为 lvTextView。你可以通过调用来有效地获取它们中的任何一个,例如:

    TextView tv = (TextView) convertView.findViewById(R.id.lvTextView);
    

    Any 侦听器也应该在您的 getView() 方法中定义(就像已经做的那样)。从您的代码来看,到目前为止,您似乎已经很清楚了。

    现在,如何管理更改:考虑到您需要实现我之前发布的关于在 ArrayList 扩展中存储数据结构的内容,您应该了解 3 个概念:

    • positiongetView() 的第一个参数是调用渲染的项目的位置。但也请注意,当您在 getView() 方法中定义侦听器时,您也可以访问此参数,这很重要。

    • getItem(position)getItem() 是来自 ArrayAdapter 类的方法,它从列表中返回一个项目。在position 上调用它会返回正在渲染的项目。它返回你的ArrayAdapter 的类型,所以如果你有Strings,你会得到String

    • notifyDataSetChanged()。每次数据集更改时,您都必须在适配器上调用此方法。理想的方法是在调用 Fragment/Activity 中执行此操作,但如果您不能(例如,因为您不知道它何时会被触发(侦听器)),您可以在侦听器中获取适配器并调用它你的监听器中的方法,这样:

      final ListView lv = (ListView) findViewById(R.id.your_listview));
      RatingAdapter adapter = (RatingAdapter) lv.getAdapter();
      adapter.notifyDataSetChanged();
      

    知道了这一切,只剩下一步:从 ArrayAdapter 的数据集副本中删除该项目,您将使用 getItem(position) 知道它并在您的适配器上调用 notifyDataSetChanged() - 如果您需要在内部触发它,请从内部调用它或从您的 Fragment/Activity 以其他方式。

    另一种(可能更简单)的方法是在 Fragment/Activity 中的 Adapter 上调用 .add.del,然后在其上调用 notifyDataSetChanged()。然而,这并不总是可行的。

    例如,我有一个自定义布局的ListView。我是这样声明的:

    private ArrayList<String> elemlist;
    elemlist.add("First row");
    elemlist.add("Second one");
    
    MultiLayoutArrayAdapter adapter = new MultiLayoutArrayAdapter(MyActivity.this, R.layout.my_custom_layout, elemlist);
    

    我在我的Activity 中称​​其为:

    elemlist.add("Yet another row");
    adapter.notifyDataSetChanged();
    

    这将出现在我的行​​中。但有时您不想只是添加或删除,而是要修改:这就是您的情况(CheckBox 正在听被点击),所以这就是上述操作的时候。您必须使用getItem(position) 修改项目列表并将其从rowLayout 结构中删除,然后从onCheckedChangeListener() 中调用notifyDataSetChanged()

    【讨论】:

    • 哇!!超级感谢!!我不能说它对我有多大帮助......但我想我会失去星星,并且只使用复选框(不知道,但后来你写了,我用谷歌搜索了......)但它对我帮助很大!谢谢!
    • 如果您只使用复选框,它与您不需要自定义布局的区别完全相同 - 但您还需要跟踪其状态。祝你好运! :)
    • 我如何跟踪状态?
    • 我更新了我的答案。检查它,如果你需要一个具体的例子来说明如何处理你的情况,请索取。
    【解决方案2】:

    您可以通过复选框来完成此操作。设置两个图像 oncheck(setimage(Highlighted star)) 和 uncheck(setimage(undo image))。

    CheckBox fav;
    boolean isCheck=false;
    

    如果(!isCheck){

    fav.setChecked(true);
                        checked.setBackgroundResource(R.drawable.blue_star);
                    }else{
    
                        fav.setBackgroundResource(R.drawable.grey_star);
    
            fav.setChecked(false);
                    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-17
      相关资源
      最近更新 更多