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:
Related
I have created a study helper app for android. I use a custom array adapter that has a checkbox and a textview in each row. Some of my listviews are populated using this custom adapter. My listviews are used to navigate to other activities, and have onItemClick listeners.
On the android studio emulator, everything works fine. However, I exported the apk and installed it on my phone, and the listviews using my custom adapter no longer did anything on click.
Here is my custom adapter:
public class CheckboxAdapter extends BaseAdapter {
private Context context;
ArrayList<String[]> list = new ArrayList<>();
Boolean completed[];
public CheckboxAdapter(ArrayList<String[]> list,Context context) {
super();
this.context = context;
this.list = list;
completed = new Boolean[list.size()];
for (int i = 0; i < completed.length; i++){
if(list.get(i)[1].equalsIgnoreCase("true")){
completed[i] = true;
} else {
completed[i] = false;
}
}
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
// Class to temporarily store the textview and checkbox in each row
public class ViewHolder {
public TextView nametext;
public CheckBox tick;
}
// Override getView method to set custom row layout
// Use viewHolder to get the textview and checkbox then inflate it
// Set text to passed in list of string data
// Set checkbox to passed in array of booleans, then disable the checkbox
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder view = null;
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (view == null) {
view = new ViewHolder();
convertView = inflater.inflate( R.layout.checkbox_adapter, null);
view.nametext = (TextView) convertView.findViewById(R.id.adaptertextview);
view.tick = (CheckBox)convertView.findViewById(R.id.adaptercheckbox);
convertView.setTag(view);
} else {
view = (ViewHolder) convertView.getTag();
}
view.tick.setTag(position);
view.nametext.setText(list.get(position)[0]);
view.tick.setChecked(completed[position]);
view.tick.setEnabled(false);
return convertView;
}
}
And its XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:id="#+id/adaptercheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/adaptertextview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Here is an example of a listview using the custom adapter, and its onclick function:
ArrayList<String[]> content = new ArrayList<String[]>();
content.add(new String[] {"Lesson 1 Highest Mark: " + highest[0], completed[0]});
content.add(new String[] {"Lesson 2 Highest Mark: " + highest[1], completed[1]});
content.add(new String[] {"Lesson 3 Highest Mark: " + highest[2], completed[2]});
content.add(new String[] {"Lesson 4 Highest Mark: " + highest[3], completed[3]});
content.add(new String[] {"Lesson 5 Highest Mark: " + highest[4], completed[4]});
content.add(new String[] {"Combined Quiz", "false"});
ListView quizList = (ListView) findViewById(R.id.quizListView);
CheckboxAdapter adapter = new CheckboxAdapter(content, this);
quizList.setAdapter(adapter);
quizList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
System.out.println(parent. getItemAtPosition(position));
switch (position) {
case 0: Intent i0 = new Intent(Quiz.this, Quiz1.class);
startActivity(i0);
break;
case 1: Intent i1 = new Intent(Quiz.this, Quiz2.class);
startActivity(i1);
break;
case 2: Intent i2 = new Intent(Quiz.this, Quiz3.class);
startActivity(i2);
break;
case 3: Intent i3 = new Intent(Quiz.this, Quiz4.class);
startActivity(i3);
break;
case 4: Intent i4 = new Intent(Quiz.this, Quiz5.class);
startActivity(i4);
break;
case 5: Intent i5 = new Intent(Quiz.this, QuizCombined.class);
startActivity(i5);
break;
default: return;
}
}
});
Any ideas why this only works on the android studio emulator? I've tried on two devices and Memu emulator but it didn't work on any of them, only the android studio emulator.
EDIT: the xml for the activity using the above listview
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<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=".Quiz">
<TextView
android:id="#+id/quizTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="56dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/quizTextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/quizTextView" />
<ListView
android:id="#+id/quizListView"
android:layout_width="368dp"
android:layout_height="493dp"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/quizTextView2" />
</android.support.constraint.ConstraintLayout>
<include
layout="#layout/app_bar_main_menu"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main_menu"
app:menu="#menu/activity_main_menu_drawer" />
</android.support.v4.widget.DrawerLayout>
EDIT: I copied the project to my laptop and ran it in the emulator there, and it didn't work. Seems like it ONLY works on my pc
remove the duplicate
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"
from the android.support.constraint.ConstraintLayout.
most likely a transparent layout overlaps and prevents clicking...
the inspect view boundaries button is tacked away in the tiles;
think it's also available in the developer settings.
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 have used a ListFragment with an ArrayAdapter to show a list of items. You can find the code below.
public class SelectRepiceFragment extends ListFragment {
private BuyRecipeActivity mActivity;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Resources res = mActivity.getResources();
int recipeNum = res.getInteger(R.integer.recipe_number);
String[] titles = res.getStringArray(R.array.titles);
ArrayList<RecipeItem> recipeItems = new ArrayList<RecipeItem>(recipeNum);
for (int i = 0; i < recipeNum; i++) {
RecipeItem item = new RecipeItem();
item.title = titles[i];
recipeItems.add(item);
}
RecipeItemAdapter recipeItemAdapter = new RecipeItemAdapter(mActivity, recipeItems);
setListAdapter(recipeItemAdapter);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = (BuyRecipeActivity) activity;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mActivity.onRecipeSelected(position);
}
}
The size of recipeItems is 3 (I check it with debugger). So the getView function in ArrayAdapter should be called 3 times to generate the ListFragment. Here I have copied the ArrayAdapter.
public class RecipeItemAdapter extends ArrayAdapter<RecipeItem> {
private final Activity mActivity;
static class ViewHolder {
public MyTextView title;
public ImageView image;
}
public RecipeItemAdapter(Activity context, ArrayList<RecipeItem> recipeItems) {
super(context, R.layout.recipe_list, recipeItems);
this.mActivity = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
// reuse views
if (rowView == null) {
LayoutInflater inflater = mActivity.getLayoutInflater();
rowView = inflater.inflate(R.layout.recipe_item, null);
// configure view holder
ViewHolder viewHolder = new ViewHolder();
viewHolder.title = (MyTextView) rowView.findViewById(R.id.recipeItemTitle);
viewHolder.image = (ImageView) rowView.findViewById(R.id.recipeItemImage);
rowView.setTag(viewHolder);
}
// fill data
ViewHolder holder = (ViewHolder) rowView.getTag();
RecipeItem recipeItem = getItem(position);
holder.title.setText(recipeItem.title);
holder.image.setImageResource(R.drawable.ic_launcher);
return rowView;
}
}
The problem is that getView is actually called three times, while every time the position parameter is equal to 0. So After running the app, I just see a single row in my list instead of 3 rows.
UPDATE: I found out that I just see the first item, but if I scroll it up, then it shows the rest of items in that single row! Consequently I guessed there should be a mistake in the xml file. So I add xml files bellow.
This is my main activity xml.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- The main content view -->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/fragmentView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|top" />
</ScrollView>
<!-- The navigation drawer -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#dcdcdc"
android:choiceMode="singleChoice"
android:divider="#dcdcdc"
android:dividerHeight="0.5dp" />
</android.support.v4.widget.DrawerLayout>
And this is my recipe_item xml file.
<?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="100dp"
android:gravity="center"
android:orientation="horizontal" >
<TextView
android:id="#+id/recipeItemTitle"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:background="#drawable/design_price_view"
android:gravity="center" />
<ImageView
android:id="#+id/recipeItemImage"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/app_icon" />
</LinearLayout>
UPDATE 2: I removed the DrawerLayout from my main activity xml and now I see the list. Just confusing.
You may try removing the ScrollView, take the FrameLayout out, put
layout_height="0dp"
layout_weight="1"
to the FrameLayout. You will need to manually fix the height of your navigation drawer to predefined pixel.
The above setup will make your FrameLayout & your ListView inside it take all the available space left from the navigational drawer.
The problem is, if you place a ListView inside a ScrollView - there is a rendering problem. I have not worked with ListView inside FrameLayout so cant really comment on that.
If you absolutely need to keep the ScrollView, you would need to re-render your ListView so that it spans the height it needs. Check this thread
My goal is to display a chessboard. I have an Activity which displays a menu and load an instance of "ChessView" which extends GridView. I've created a custom GridView because I want to have a class fully dedicated to its display. So that class have its own layout.xml etc ...
GameActivity.java :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
//init a game
CChess.getInstance().init();
//creating the chessboard
ChessView lChessView = (ChessView) findViewById(R.id.chessView);
}
activity_game.xml :
<RelativeLayout 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:background="#color/background"
tools:context=".GameActivity" >
<project.chess.view.ChessView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/ChessView" >
</project.chess.view.ChessView>
</RelativeLayout>
ChessView.java :
public class ChessView extends GridView {
public ChessView(Context pContext, AttributeSet pAttrs) {
super(pContext, pAttrs);
GridView.inflate(pContext, R.layout.view_chess, null);
this.setAdapter(new ChessAdapter(pContext));
}
}
view_chess.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" >
<GridView
android:id="#+id/gridView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:numColumns="8"
android:gravity="center"
>
</GridView>
</LinearLayout>
ChessAdapter.java :
public class ChessAdapter extends BaseAdapter
{
private Context mContext;
public ChessAdapter (Context pContext)
{
this.mContext = pContext;
}
#Override
public int getCount()
{
return 64;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView lImageView;
if (convertView == null) {
lImageView = new ImageView(mContext);
int size = parent.getWidth()/8;
lImageView.setLayoutParams(new GridView.LayoutParams(size,size));
//background black or white depending of the position
int col = position/8 %2;
if (col == 0)
{
if (position%2 == 0)
lImageView.setBackgroundColor(Color.WHITE);
else
lImageView.setBackgroundColor(Color.BLACK);
}
else
{
if (position%2 == 0)
lImageView.setBackgroundColor(Color.BLACK);
else
lImageView.setBackgroundColor(Color.WHITE);
}
//load images
CPiece p = CChess.getInstance().getPiece(position/8, position%8);
if( p != null)
lImageView.setImageResource(mContext.getResources().getIdentifier(p.toString(), "drawable", mContext.getPackageName()));
} else {
lImageView = (ImageView) convertView;
}
return lImageView;
}
}
The result is : i have just 1 column of 64 squares all with an image (my init() in CChess is ok). To be clear, i want a 8x8 grid like all standards chessboards.
Few days ago, i had all this stuff in one activity without my custom view but just a simple gridView and all was working correctly. I have broken it since i've decided to separate my code in different classes
I'm sure i forgot something like an inflater somewhere but i don't understand how it works and what it does. I've parsed google for hours but i couldn't find the answer.
Can you help me please ? Thanks a lot for reading me and sorry for my english
I Think the problem with this LayoutInflator in ChessView.java
remove this line from that class
No Need to Inflate the GridView in that class
GridView.inflate(pContext, R.layout.view_chess, null);
and set the Column count and gravity in Chess View in activity_game.xml file.
android:layout_width="wrap_content"
android:numColumns="8"
I Think this works for you.
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