I'm trying to center two textViews that are in a LinearLayout. This LinearLayout is nested in another one, with a ListView-element.
I think my XML is pretty correct. I fill my textViews dynamically in my Adapterclass.
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView android:layout_height="wrap_content"
android:id="#+id/atlVacaturesnummer"
android:layout_width="wrap_content"
android:textColor="#color/Accent"
android:text="x"
/>
<TextView android:layout_height="wrap_content"
android:id="#+id/atlVacatures"
android:layout_width="wrap_content"
android:text="y"
/>
</LinearLayout>
<ListView android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
<TextView android:layout_height="fill_parent"
android:id="#+id/android:empty"
android:layout_width="fill_parent"
android:text="Er zijn geen jobs die voldoen aan uw criteria..."
android:gravity="center"/>
</LinearLayout>
Adapterclass:
/*
* Klasse VacatureAdapter
*/
private class VacatureAdapter extends ArrayAdapter<Vacature>{
private ArrayList<Vacature> vacatures;
public VacatureAdapter(Context context, int textViewResourceId, ArrayList<Vacature> vacatures){
super(context, textViewResourceId, vacatures);
this.vacatures = getArray();
//System.out.println("Array vacatureadapter: " + v);
}
#Override
public View getView(int position, View convertview, ViewGroup parent){
View view = convertview;
if(view==null){
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.vacature_list_item, null);
//view.setBackgroundColor((position % 2) == 1? Color.LTGRAY: Color.WHITE);
}
TextView atlVacatures = (TextView)findViewById(R.id.atlVacatures);
TextView atlVacaturesnr = (TextView)findViewById(R.id.atlVacaturesnummer);
atlVacaturesnr.setText("" + arrVacatures.size());
atlVacatures.setText(" jobs op maat gevonden!");
Vacature vaca = vacatures.get(position);
if(vaca != null){
TextView tvNaam = (TextView) view.findViewById(R.id.vacatureNaam);
TextView tvWerkveld = (TextView) view.findViewById(R.id.vacatureWerkveld);
TextView tvRegio = (TextView) view.findViewById(R.id.vacatureRegio);
if(tvNaam != null){
tvNaam.setText(vaca.getTitel());
if(tvWerkveld != null){
tvWerkveld.setText("Werkveld: " + vaca.getWerkveld());
if(tvRegio!=null){
tvRegio.setText("Regio: "+vaca.getRegio());
}
}
}
}
return view;
}
}
The weird thing is that if my spinner runs, he shows the texts set in my XML correctly, if the spinner stops and fills my ListView it only shows one digit of my number and when I scroll once he shows my number completly plus the second TextView. I don't quite understand what's wrong, maybe some code needs te be put somewhere else?
I've solved my problem by putting my setText code in my Runnable method, after I dismiss my Dialog. Now It looks like this:
private Runnable returnRes = new Runnable(){
public void run(){
if (arrVacatures.size() == 0){
dialog.dismiss();
}
if(arrVacatures!=null && arrVacatures.size() > 0){
adapter.notifyDataSetChanged();
for(int i= 0; i< arrVacatures.size();i++){
adapter.add(arrVacatures.get(i));
}
dialog.dismiss();
TextView atlVacatures = (TextView)findViewById(R.id.atlVacatures);
TextView atlVacaturesnr = (TextView)findViewById(R.id.atlVacaturesnummer);
atlVacaturesnr.setText("" + arrVacatures.size());
atlVacatures.setText(" jobs op maat gevonden!");
adapter.notifyDataSetChanged();
}
}
};
Related
I'm getting a very odd (to me) issue when populating a GridView - when it first loads all looks fine, but scrolling ends up with data from cells moving to other positions. In the following example I just have an ArrayList of the numbers 0-800, and an 8 column grid. When loaded 0-7 is in the first row, 8-15 in the second etc, with a different value in the first cell in each row. But after scrolling the first column value will change. Here's the code - it's driving me crazy!
MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<Integer> positions = new ArrayList<Integer>();
for(int i=0;i<800;i++) {
positions.add(i);
}
GridView gvVals = findViewById(R.id.gvVals);
CellAdapter adapter = new CellAdapter(this, new ArrayList<Integer>());
adapter = new CellAdapter(this, positions);
gvVals.setAdapter(adapter);
}
Cell Adapter.java:
public class CellAdapter extends ArrayAdapter<Integer> {
private Context context;
public CellAdapter(Context context, ArrayList<Integer> vals) {
super(context, 0, vals);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null) {
v = LayoutInflater.from(getContext()).inflate(R.layout.activity_cell, parent, false);
} else {
v = (View)convertView;
}
TextView tvDay = v.findViewById(R.id.tvVal);
tvDay.setVisibility(View.VISIBLE);
if(position % 8 == 0) {
tvDay.setText("ST:"+position);
}
else
{
v.findViewById(R.id.btnM).setVisibility(View.VISIBLE);
((Button)v.findViewById(R.id.btnM)).setText(position + " ");
tvDay.setText(" ");
}
return v;
}
ActivityMain.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<GridView
android:id="#+id/gvVals"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="60dp"
android:numColumns="8"/>
</android.support.constraint.ConstraintLayout>
ActivityCell.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tvVal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:visibility="invisible"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="#+id/btnM"
android:layout_width="0dp"
android:layout_weight=".34"
android:layout_height="20dp"
android:text="M"
android:background="#color/colorAccent"
android:minWidth="0dp"
android:visibility="invisible"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
GridView when app first opened
After scrolling down a few rows and then back up
Change this:
TextView tvDay = v.findViewById(R.id.tvVal);
tvDay.setVisibility(View.VISIBLE);
if(position % 8 == 0) {
tvDay.setText("ST:"+position);
}
else
{
v.findViewById(R.id.btnM).setVisibility(View.VISIBLE);
((Button)v.findViewById(R.id.btnM)).setText(position + " ");
tvDay.setText(" ");
}
to this:
boolean firstColumn = position % 8 == 0;
TextView tvDay = v.findViewById(R.id.tvVal);
tvDay.setVisibility(firstColumn ? View.VISIBLE : View.GONE);
Button btnM = v.findViewById(R.id.btnM);
btnM.setVisibility(firstColumn ? View.GONE : View.VISIBLE);
if(firstColumn) {
tvDay.setText("ST:"+position);
}
else
{
btnM.setText(position + " ");
}
It's important when working with RecyclerView to make sure that you always update every view every time. This is because old view holders get recycled, so if you only do something some of the time, it can get overwritten or it can overwrite the "expected" behavior.
Previously, you were making btnM visible if it wasn't the first column, but you weren't making it not visible if it was the first column.
I am working on a WearOS app. I am using a ListView to show a list of strings. Right now, the ListView looks like this:
I want a single row to take up the entire screen. Once a user swipes up, then Row 2 takes up the entire screen. Swipe up again and Row 3 takes up the entire screen, etc. So like this:
I came across this link, which is exactly what I want to do, but the first method doesn't work and the second method suggests a library, but I don't want to use a library for what seems like a pretty simple task. I don't want to use RecyclerView. Thank you for your help.
Here is my XML file for the main activity, which is where the ListView is.
<?xml version="1.0" encoding="utf-8"?>
<android.support.wear.widget.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/dark_grey"
android:padding="#dimen/box_inset_layout_padding"
tools:context=".MainActivity"
tools:deviceIds="wear">
<!-- Change FrameLayout to a RelativeLayour -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/inner_frame_layout_padding"
app:boxedEdges="all">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
</android.support.wear.widget.BoxInsetLayout>
Try the following (The idea here is to programmatically set the height of the textView to the height of the screen):
1) MnnnnnnnActivity.class:----------
public class MnnnnnnnActivity extends AppCompatActivity {
private ListView lv;
private CustomAdapter customAdapter;
private String[] s = new String[10];
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout6);
for (int i = 0; i < 10; i++) {
s[i] = "ROW " + String.valueOf(i + 1);
}
lv = (ListView) findViewById(R.id.lv);
customAdapter = new CustomAdapter(MnnnnnnnActivity.this, s);
lv.setAdapter(customAdapter);
}
public int getScreenHeight() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.heightPixels;
}
}
2) CustomAdapter.class:--------
public class CustomAdapter extends ArrayAdapter<String> {
private String[] s;
private WeakReference<MnnnnnnnActivity> mActivity;
public CustomAdapter(MnnnnnnnActivity activity1, String[] s) {
super(activity1.getApplicationContext(), R.layout.list_view_item, s);
this.s = s;
mActivity = new WeakReference<MnnnnnnnActivity>(activity1);
}
#NonNull
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(mActivity != null) {
MnnnnnnnActivity activity = mActivity.get();
if (activity != null) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(activity);
convertView = inflater.inflate(R.layout.list_view_item, null);
holder = new ViewHolder();
holder.tv = (TextView) convertView.findViewById(R.id.tv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tv.setText(s[position]);
holder.tv.setHeight(activity.getScreenHeight());
}
}
return convertView;
}
private class ViewHolder {
TextView tv;
}
}
3) layout6.xml:-----------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/lv">
</ListView>
</android.support.constraint.ConstraintLayout>
4) list_view_item.xml:----------
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="-"
android:gravity="center"
android:textSize="20sp"
android:textStyle="bold">
</TextView>
</LinearLayout>
5) Note: Although this is tested on phone, the same idea can be used to achieve something similar on a wareable. Also, a better approach would be to set the height of the linearLayout (which contains the textView) to the screen height.
6) Output:
I have a ListView in one of my activities that I have bound to an ArrayList using a custom ArrayAdapter. I have set an OnItemClickListener to the ListView which should call a method that starts another activity. However, I find that when I click on the ListView items, it only sometimes works. Sometimes it will start the activity as it should; other times it seems to detect the click (the ripple effect appears on the list item) but does nothing; other times it doesn't even appear to detect the click (the ripple effect doesn't appear).
I've tried all the usual suggestions that I've come across: blocking descendants on the parent view item, setting clickable and focusable to false on all the components of the item views, setting isEnabled to return true in the custom adapter, etc, but the behavior remains the same. Any help appreciated. Here is the relevant code:
Activity containing the ListView:
public class ViewCollectionActivity extends AppCompatActivity {
private final String className = this.getClass().getSimpleName();
private CollectionHandler collectionHandler;
private Context context;
private ArrayList<Game> displayedCollection;
private GameCollectionAdapter collectionAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_collection);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
context = this;
collectionHandler = CollectionHandler.getInstance(this);
TextView view = null;
if (collectionHandler.getDisplayedCollection().size() > 0) {
view = (TextView) findViewById(R.id.no_items_textview);
view.setVisibility(View.GONE);
}
String currentDate = collectionHandler.getDateLastSynchronised();
view = (TextView) findViewById(R.id.last_updated_textview);
view.setText("Last synchronised: " + currentDate + " Total games: " + String.valueOf(collectionHandler.getDisplayedCollection().size()));
collectionAdapter = collectionHandler.getCollectionAdapter();
ListView listView = (ListView) findViewById(R.id.collection_list_view);
listView.setAdapter(collectionAdapter);
AdapterView.OnItemClickListener collectionItemClickListener = new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
launchGameDetailsActivity(position);
}
};
listView.setOnItemClickListener(collectionItemClickListener);
}
public void launchGameDetailsActivity(int position){
Log.d(className,"Starting lauchGameDetailsActivity method");
collectionHandler.setSelectedGame(position);
Intent intent = new Intent(this,ViewGameDetailsActivity.class);
startActivity(intent);
Log.d(className, "Ending lauchGameDetailsActivity method");
}
The XML for the activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.bleachedlizard.ludome.viewcollection.ViewCollectionActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Synchronise Collection"
android:onClick="synchroniseCollection"/>
<TextView
android:id="#+id/last_updated_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Last synchronised: "
android:textAlignment="center"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Display Collection"
android:visibility="gone"
android:onClick="displayCollection"/>
<ListView
android:id="#+id/collection_list_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</ListView>
<TextView
android:id="#+id/no_items_textview"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="You have no items in your collection."
android:textAlignment="center"
android:textSize="20sp"/>
</LinearLayout>
The XML for the item views:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/collection_item_layout"
android:layout_width="match_parent"
android:layout_height="75dp"
android:orientation="horizontal"
android:clickable="false"
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false">
<ImageView
android:id="#+id/collection_item_image"
android:layout_width="75dp"
android:layout_height="75dp"
android:src="#drawable/testimage"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
/>
<TextView
android:id="#+id/collection_item_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:padding="16dp"
android:singleLine="false"
android:textColor="#android:color/darker_gray"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:textIsSelectable="false"/>
<TextView
android:id="#+id/collection_item_plays"
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:padding="8dp"
android:textColor="#android:color/darker_gray"
android:text="Plays: 0"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:textIsSelectable="false"/>
</LinearLayout>
The code for the custom adapter:
public class GameCollectionAdapter extends ArrayAdapter<Game> {
private ArrayList<Game> collection;
public GameCollectionAdapter(Context context, int resource, ArrayList<Game> collection){
super(context, resource, collection);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout gameView = (LinearLayout) convertView;
LayoutInflater mInflater = LayoutInflater.from(getContext());
if (gameView == null) {
gameView = (LinearLayout) mInflater.inflate(R.layout.collection_item_view, null);
}
//Game game = collection.get(position);
Game game = super.getItem(position);
if (game != null) {
// This is how you obtain a reference to the TextViews.
// These TextViews are created in the XML files we defined.
TextView gameTitle = (TextView) gameView.findViewById(R.id.collection_item_name);
TextView numOfPlays = (TextView) gameView.findViewById(R.id.collection_item_plays);
ImageView thumbnail = (ImageView) gameView.findViewById(R.id.collection_item_image);
// check to see if each individual textview is null.
// if not, assign some text!
if (gameTitle != null){
gameTitle.setText(game.getTitle());
}
if (numOfPlays != null){
numOfPlays.setText("Plays: " + String.valueOf(game.getNumOfPlays()));
}
if (thumbnail != null){
thumbnail.setImageBitmap(game.getThumbnail());
}
}
// the view must be returned to our activity
return gameView;
}
#Override
public boolean isEnabled(int position) {
return true;
}
}
I discovered what was causing the problem: the way I had set up the array that backed the ListView meant that it was downloading and storing the Bitmaps for every element in the array all the time. Once I changed the implementation so that it only downloaded the images as the ListView required them, then that seemed to improve performance and the onClickListener started to work fine.
The implementation I used was the exact same one shown here:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
I think the issue is due to the position of the item selection whenever you click you have an list position which is passed to your method launchGameDetailActivity(int position) check with log or toast on item click what all the position you are getting do the needful.
Here is my code try this like this if it helps.
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(RecipeClass.this, "Position is" + position, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(RecipeClass.this, RecipeIngredients.class)
intent.putExtra("position", position);
startActivity(intent);
}
Check your arraylist value also whether they are not null.
I have a ListView and a custom adapter. Now i have red posts about getView() method being called multiple times, and most of them have to do with the wrap_content feature of the ListView.
I have changed my height, so that it can be match_parent but still, the method is being called.
I think it has something to do with adding TextViews dynamically in the adapter, and i don't know how to do it, so it works properly.
If there is an alternative, i am opened to it, the only reason why i put TextViews is so that i can have letters written in different colors.
Here is my code:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
Row current = mList.get(position);
/* if the given channel row view is not being updated*/
if (v == null)
{
/* inflate layout */
LayoutInflater vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.list_item2, null,false);
}
v = setLinearLayout(v,current);
return v;
}
Here is the setLinearLayout() method:
private View setLinearLayout(View v,Row current) {
ArrayList<Integer> winResults = current.checkNumbers(mResult,mType);
int numbers[] = current.getNumbers();
int N = Global.getNumberOfNumbers(mType);
boolean FLAG_SET = false;
final TextView[] myTextViews = new TextView[N]; // create an empty array;
for (int i = 0; i < N; i++) {
Log.d("PAVLE",""+i+" row is: "+current.getStringNumbers());
// create a new textview
final TextView rowTextView = new TextView(v.getContext());
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,75);
rowTextView.setTextSize(24.0f);
rowTextView.setPadding(8, 8, 8, 8);
rowTextView.setGravity(Gravity.CENTER);
rowTextView.setBackgroundColor(Color.BLACK);
rowTextView.setTypeface(null, Typeface.BOLD);
rowTextView.setLayoutParams(lp);
if(mType == R.string.sans_topu && i == 5 && !FLAG_SET){
i--;
rowTextView.setTextColor(Color.WHITE);
rowTextView.setText("+");
FLAG_SET = true;
}
else {
// set some properties of rowTextView or something
if (mWin == Global.WIN || mWin == Global.LOSE) {
if (winResults.contains(numbers[i]))
rowTextView.setTextColor(Color.GREEN);
else rowTextView.setTextColor(Color.RED);
} else {
rowTextView.setTextColor(Color.WHITE);
}
if (numbers[i] < 10) {
rowTextView.setText("0" + numbers[i]);
} else rowTextView.setText("" + numbers[i]);
}
// add the textview to the linearlayout
LinearLayout ll = (LinearLayout) v.findViewById(R.id.ll_item);
ll.addView(rowTextView);
// save a reference to the textview for later
myTextViews[i] = rowTextView;
}
final TextView prize = new TextView(v.getContext());
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,75);
prize.setTextSize(24.0f);
prize.setPadding(8, 8, 8, 8);
prize.setGravity(Gravity.CENTER);
prize.setBackgroundColor(Color.BLACK);
prize.setTypeface(null, Typeface.BOLD);
prize.setTextColor(Color.WHITE);
prize.setLayoutParams(lp);
try {
String cash = findCorretAmmount(winResults, numbers);
prize.setText(cash);
mTotal.append(" "+cash);
}
catch (Exception e){
e.printStackTrace();
}
LinearLayout ll = (LinearLayout) v.findViewById(R.id.ll_item);
ll.addView(prize);
return v;
}
And a little bit of XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tvRandomTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:paddingRight="8dp"
android:text="#string/your_ticket_numbers_"
android:textColor="#android:color/black"
android:textSize="28sp"
android:textStyle="bold"
/>
<View
android:id="#+id/divider4"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="#id/tvRandomTextView"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:background="#android:color/darker_gray"/>
<ListView
android:id="#+id/lvRowList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/divider4"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
>
<Button
android:id="#+id/btnDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="#string/delete"/>
<Button
android:id="#+id/btnShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="#string/btn_share"/>
<Button
android:id="#+id/btnDone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="#string/done"/>
</RelativeLayout>
<TextView
android:id="#+id/tvResultLink"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:autoLink="web"
android:gravity="center"
android:linksClickable="true"
/>
Also worth mentioning is that list_item2(LinearLayout) has height of 100dp, it's fixed size.
I think its not about textview.
The getView is always called multiple times. If you have 10 items on the screen to be shown, the getView going to be called 15 times, because the android creating views that are not on the screen. It`s good, because when the user start scrolling, it is not going to lagging.
After the user left the item, the view get`s recycle and reused by the adapter. Lets say, you have a list with 10000000 item, but you have 5 item on the screen at all time. In this case - to save power, and improve performance - the android going to create 10 list item, and this 10 item is going to recylce and refresh by content.
ViewHolder pattern
Please read this and use this patter to improve your code performance:
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
Google about ListView:
http://developer.android.com/guide/topics/ui/layout/listview.html
Tutorials:
http://developer.xamarin.com/guides/android/user_interface/working_with_listviews_and_adapters/
I have a Activity that displays a list of check boxes (Focus Areas) that can be assigned to an activity event in my application. However I want to be able to prevent the user form editing these values until a button is clicked to put the form into edit mode.
Can some one explain or provide code sample how I can implement this into my application?
This list is held in a ListView with a custom ArrayAdapter of a Type FocusArea a class I have created for my application.
The xml for the Activity is shown below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" android:background="#drawable/horizontal_gradient_line_reverse">
<TextView
android:id="#+id/textViewCustomerNameNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Customer Name & Number" android:layout_margin="5dp"/>
<ListView
android:id="#+id/listViewFocusAreas"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/relativeLayoutControls"
android:layout_alignParentLeft="true"
android:layout_below="#+id/textViewCustomerNameNumber"
android:layout_margin="5dp"
android:background="#drawable/myborder" >
</ListView>
<RelativeLayout
android:id="#+id/relativeLayoutControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" >
<ImageView
android:id="#+id/imageViewCancelFocusAreaChanges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:src="#drawable/ic_mini_undo" />
<ImageView
android:id="#+id/imageViewSaveFocusAreaChanges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/imageViewCancelFocusAreaChanges"
android:src="#drawable/ic_mini_save" />
<ImageView
android:id="#+id/imageViewEditFocusArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/imageViewSaveFocusAreaChanges"
android:src="#drawable/ic_mini_edit" />
</RelativeLayout>
<ImageView
android:id="#+id/imageViewEditMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/textViewCustomerNameNumber"
android:layout_alignRight="#+id/listViewFocusAreas"
android:src="#drawable/edit16x16"
android:visibility="gone" />
</RelativeLayout>
The following is the xml for the focus area row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<CheckBox
android:id="#+id/checkBoxFocusArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Focus Area" />
</LinearLayout>
The following is the code for the Custom ArrayAdapter:
public class FocusAreaAdapter extends ArrayAdapter<FocusArea> {
private ArrayList<FocusArea> focusAreas;
private Context context;
public FocusAreaAdapter(Context context, int textViewResourceId, ArrayList<FocusArea> focusAreas) {
super(context, textViewResourceId, focusAreas);
this.context = context;
this.focusAreas = focusAreas;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View v = convertView;
if(v == null) {
LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.focus_area_menu_item, null);
}
FocusArea focusArea = focusAreas.get(position);
if(focusArea != null) {
CheckBox cbFocusArea = (CheckBox)v.findViewById(R.id.checkBoxFocusArea);
cbFocusArea.setText(focusArea.getFocusAreaCodeDescription());
if(focusArea.isFocusAreaCodeChecked() == 1) {
cbFocusArea.setChecked(true);
} else {
cbFocusArea.setChecked(false);
}
cbFocusArea.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FocusArea focusArea = focusAreas.get(position);
if(focusArea.isFocusAreaCodeChecked() == 1) {
focusArea.setFocusAreaCodeChecked(0);
} else {
focusArea.setFocusAreaCodeChecked(1);
}
}
});
}
return v;
}
}
Finally I instanciate my custom array adapter with the following code:
private void assignFocusAreasToAdapter() {
// get reference to available responsibles list view control
lvFocusAreas.clearChoices();
// create an array adapter with the communications data array
activityFocusAreaAdapter = new FocusAreaAdapter(this, R.layout.focus_area_menu_item, activityFocusAreas);
// assign the my customers list control the array adapter
lvFocusAreas.setAdapter(activityFocusAreaAdapter);
activityFocusAreaAdapter.notifyDataSetChanged();
Log.i(TAG, "Available Activity Focus Areas Loaded");
}
Ok i found the solution to this problem for anyone who might have the same issue.
The XML for the Focus Area activity stays the same as posted above.
The XML for the Focus Area row item is modified accordingly:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants" >
<CheckBox
android:id="#+id/checkBoxFocusArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Focus Area" />
</LinearLayout>
You can see that this now has the following line added android:descendantFocusability="blocksDescendants" This prevents the checkboxes onClickListener from firing which normally will block the ListViews OnItemClickedListener from firing.
The Custom Adapter code is modified to remove the checkboxes OnClickListener like so:
public class FocusAreaAdapter extends ArrayAdapter<FocusArea> {
private ArrayList<FocusArea> focusAreas;
private Context context;
public FocusAreaAdapter(Context context, int textViewResourceId, ArrayList<FocusArea> focusAreas) {
super(context, textViewResourceId, focusAreas);
this.context = context;
this.focusAreas = focusAreas;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View v = convertView;
if(v == null) {
LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.focus_area_menu_item, null);
}
FocusArea focusArea = focusAreas.get(position);
if(focusArea != null) {
CheckBox cbFocusArea = (CheckBox)v.findViewById(R.id.checkBoxFocusArea);
cbFocusArea.setText(focusArea.getFocusAreaCodeDescription());
if(focusArea.isFocusAreaCodeChecked() == 1) {
cbFocusArea.setChecked(true);
} else {
cbFocusArea.setChecked(false);
}
cbFocusArea.setClickable(false);
}
return v;
}
}
The Custom Adapter is instanciated using the same code as posted in above but you must add an OnItemClickListener to the ListView and preform the check of the checkbox inside the OnItemClickListener click event like so:
lvFocusAreas = (ListView)findViewById(R.id.listViewFocusAreas);
lvFocusAreas.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
if(editMode){
FocusArea focusArea = (FocusArea)lvFocusAreas.getItemAtPosition(position);
if(focusArea.isFocusAreaCodeChecked() == 0) {
focusArea.setFocusAreaCodeChecked(1);
} else {
focusArea.setFocusAreaCodeChecked(0);
}
activityFocusAreaAdapter.notifyDataSetChanged();
setControlsEnabled();
}
}
});
Hope this helps any one thats having the same problem. :D