如何更新 invisible/off-screen 视图?
How to update invisible/off-screen views?
我制作了一个 15x15 的 GridView,其中包含 225 个 TextView,编号为 0 到 224。我可以(通过 getChildAt(int position)
)一次访问适合屏幕的所有行,即 180 个 TextView或前 12 行。我想要做的是调用一个方法(称为 playSoE()
),将所有 TextView 的背景更改为不同的颜色。然而,更改最后 3 行是一个问题,因为它们不在屏幕上。我一直在寻找一种方法来解决这个问题,但我得到的只是 "it's impossible"。如果是这种情况,那么至少我希望隐藏的 TextViews 在它们部分出现在屏幕上后进行更新,这样用户就不会注意到差异。有谁知道我将如何实施其中任何一个?
如您所见,complete/partially 屏幕上有 120 个 TextView,屏幕右侧有 60 个,屏幕下方有 45 个。出于某种原因,只需将 GridView 嵌套到 HorizontalScrollView
中即可访问右侧的 TextView。我尝试对 ScrollView
和底部的 TextView 执行相同的操作,但我尝试的任何操作均无效。
MainActivity.java:
public class MainActivity extends ActionBarActivity {
private boolean mIsPlaying;
private int primesLE;
private GridView mGridView;
private ArrayAdapter<TextView> mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIsPlaying = false;
ViewGroup.LayoutParams layoutParams;
primesLE = 225;
int numOfColumns = (int)Math.round(Math.sqrt((double) primesLE));
int numOfRows = (int)Math.ceil((double)primesLE/(double)numOfColumns);
View v1 = findViewById(R.id.title_horizontalScrollView);
View v2 = v1.findViewById(R.id.relativelayout);
mGridView = (GridView) v2.findViewById(R.id.mGridView);
layoutParams = mGridView.getLayoutParams();
layoutParams.width = 150*numOfColumns; //this is in pixels
mGridView.setLayoutParams(layoutParams);
mGridView.setNumColumns(numOfColumns);
mAdapter = new ImageAdapter(this, android.R.layout.simple_list_item_1, primesLE);
mGridView.setAdapter(mAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
private void playSoE(){
Log.d("mAdapter.getCount()","" + mAdapter.getCount()); //225
Log.d("mGridView.getCount()",""+mGridView.getCount()); //225
Log.d("mGridView.getChildCount()",""+mGridView.getChildCount()); //180
for(int i = 0; i < 180;i++){ //NPE from 180 or higher
Log.d("Getting view number",""+i);
mGridView.getChildAt(i).setBackgroundColor(Color.BLUE);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
Log.d("Menu","Button Pressed");
if (id == R.id.action_settings) {
return true;
}
else if (id == R.id.action_status){
if(mIsPlaying) {
mIsPlaying = false;
item.setIcon(R.drawable.ic_action_play);
item.setTitle("Play");
playSoE();
}
else {
mIsPlaying = true;
item.setIcon(R.drawable.ic_action_pause);
item.setTitle("Pause");
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
ImageAdapter.java:
public class ImageAdapter extends ArrayAdapter {
private Context mContext;
private int mCount;
public ImageAdapter(Context c, int resource, int count) {
super(c, resource);
mContext = c;
mCount = count;
}
public int getCount() {
return mCount;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
textView = new TextView(mContext);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new GridView.LayoutParams(100, 100));
} else {
textView = (TextView) convertView;
}
textView.setBackgroundColor(Color.RED);
textView.setText("" + position);
return textView;
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/title_horizontalScrollView"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/relativelayout">
<GridView
android:id="@+id/mGridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
</RelativeLayout>
</HorizontalScrollView>
menu_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_status"
android:icon="@drawable/ic_action_play"
android:title="Play"
app:showAsAction="always"/>
<item android:id="@+id/action_stop"
android:icon="@drawable/ic_action_stop"
android:title="Stop"
app:showAsAction="always"/>
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>
你有一个非常丑陋的解决方案:D 你应该了解更多关于 adapters
和 recycled views
这是你应该做的,
// adapter class
private boolean setBlueBackground = false;
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
textView = new TextView(mContext);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new GridView.LayoutParams(100, 100));
} else {
textView = (TextView) convertView;
}
if(setBlueBackground)
textView.setBackgroundColor(Color.BLUE);
else
textView.setBackgroundColor(Color.RED);
textView.setText("" + position);
return textView;
}
public void setBlueBg(boolean blue) {
setBlueBackground = blue;
notifyDataSetChanged();
}
现在您只需更改颜色即可
mAdapter.setBlueBg(true); // or false to make it red
它将取代这个
for(int i = 0; i < 180;i++){ //NPE from 180 or higher
Log.d("Getting view number",""+i);
mGridView.getChildAt(i).setBackgroundColor(Color.BLUE);
}
好了。
我制作了一个 15x15 的 GridView,其中包含 225 个 TextView,编号为 0 到 224。我可以(通过 getChildAt(int position)
)一次访问适合屏幕的所有行,即 180 个 TextView或前 12 行。我想要做的是调用一个方法(称为 playSoE()
),将所有 TextView 的背景更改为不同的颜色。然而,更改最后 3 行是一个问题,因为它们不在屏幕上。我一直在寻找一种方法来解决这个问题,但我得到的只是 "it's impossible"。如果是这种情况,那么至少我希望隐藏的 TextViews 在它们部分出现在屏幕上后进行更新,这样用户就不会注意到差异。有谁知道我将如何实施其中任何一个?
如您所见,complete/partially 屏幕上有 120 个 TextView,屏幕右侧有 60 个,屏幕下方有 45 个。出于某种原因,只需将 GridView 嵌套到 HorizontalScrollView
中即可访问右侧的 TextView。我尝试对 ScrollView
和底部的 TextView 执行相同的操作,但我尝试的任何操作均无效。
MainActivity.java:
public class MainActivity extends ActionBarActivity {
private boolean mIsPlaying;
private int primesLE;
private GridView mGridView;
private ArrayAdapter<TextView> mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIsPlaying = false;
ViewGroup.LayoutParams layoutParams;
primesLE = 225;
int numOfColumns = (int)Math.round(Math.sqrt((double) primesLE));
int numOfRows = (int)Math.ceil((double)primesLE/(double)numOfColumns);
View v1 = findViewById(R.id.title_horizontalScrollView);
View v2 = v1.findViewById(R.id.relativelayout);
mGridView = (GridView) v2.findViewById(R.id.mGridView);
layoutParams = mGridView.getLayoutParams();
layoutParams.width = 150*numOfColumns; //this is in pixels
mGridView.setLayoutParams(layoutParams);
mGridView.setNumColumns(numOfColumns);
mAdapter = new ImageAdapter(this, android.R.layout.simple_list_item_1, primesLE);
mGridView.setAdapter(mAdapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
private void playSoE(){
Log.d("mAdapter.getCount()","" + mAdapter.getCount()); //225
Log.d("mGridView.getCount()",""+mGridView.getCount()); //225
Log.d("mGridView.getChildCount()",""+mGridView.getChildCount()); //180
for(int i = 0; i < 180;i++){ //NPE from 180 or higher
Log.d("Getting view number",""+i);
mGridView.getChildAt(i).setBackgroundColor(Color.BLUE);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
Log.d("Menu","Button Pressed");
if (id == R.id.action_settings) {
return true;
}
else if (id == R.id.action_status){
if(mIsPlaying) {
mIsPlaying = false;
item.setIcon(R.drawable.ic_action_play);
item.setTitle("Play");
playSoE();
}
else {
mIsPlaying = true;
item.setIcon(R.drawable.ic_action_pause);
item.setTitle("Pause");
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
ImageAdapter.java:
public class ImageAdapter extends ArrayAdapter {
private Context mContext;
private int mCount;
public ImageAdapter(Context c, int resource, int count) {
super(c, resource);
mContext = c;
mCount = count;
}
public int getCount() {
return mCount;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
textView = new TextView(mContext);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new GridView.LayoutParams(100, 100));
} else {
textView = (TextView) convertView;
}
textView.setBackgroundColor(Color.RED);
textView.setText("" + position);
return textView;
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/title_horizontalScrollView"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/relativelayout">
<GridView
android:id="@+id/mGridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
</RelativeLayout>
</HorizontalScrollView>
menu_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_status"
android:icon="@drawable/ic_action_play"
android:title="Play"
app:showAsAction="always"/>
<item android:id="@+id/action_stop"
android:icon="@drawable/ic_action_stop"
android:title="Stop"
app:showAsAction="always"/>
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>
你有一个非常丑陋的解决方案:D 你应该了解更多关于 adapters
和 recycled views
这是你应该做的,
// adapter class
private boolean setBlueBackground = false;
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
textView = new TextView(mContext);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new GridView.LayoutParams(100, 100));
} else {
textView = (TextView) convertView;
}
if(setBlueBackground)
textView.setBackgroundColor(Color.BLUE);
else
textView.setBackgroundColor(Color.RED);
textView.setText("" + position);
return textView;
}
public void setBlueBg(boolean blue) {
setBlueBackground = blue;
notifyDataSetChanged();
}
现在您只需更改颜色即可
mAdapter.setBlueBg(true); // or false to make it red
它将取代这个
for(int i = 0; i < 180;i++){ //NPE from 180 or higher
Log.d("Getting view number",""+i);
mGridView.getChildAt(i).setBackgroundColor(Color.BLUE);
}
好了。