Adding clickable views dynamically to ScrollView - android

I'm a newbie to Android development, so apologies if the answers seem obvious to others...
I want to create a task tracker app for my org, where the set of tasks are usually about the same. Here's a mockup:
Project Progress Mockup
The mockup shows generic task names, but the real one will have different task names and more of them.
I need some help sorting out the layout design. Conceptually, this is pretty straightforward, but the implementation in Android turns out not to be so straightforward...
I thought I should create a "Task Item" class which contains 3 views: a text view for the task name, a progress bar & another text view for the percentage. Then I wanted to create an array of these Task Items.
Setting all this up in XML is not so bad, but I need it to be dynamic, as it will not always be the same list. Also, using XML is kinda brute force, as I would need to have unique code for each item in this activity, rather than looping through the list dynamically.
It seems like I need a ScrollView. I saw from another post the following statement:
A ScrollView is a FrameLayout, meaning you should place one child in it containing the entire contents to scroll; this child may itself be a layout manager with a complex hierarchy of objects. A child that is often used is a LinearLayout in a vertical orientation, presenting a vertical array of top-level items that the user can scroll through.
So I understand that I need to add my list of Task Items to something like a LinearLayout, which is embedded in the ScrollView. This I can simply set up in XML, right?
Then, for each Task Item, I need to:
- create 2 TextViews
- set the text to the task name & percentage, respectively
- set the font, font size, text color, etc.
- set the TextView positions
- create a Progress Bar
- set the Progress Bar position & percentage
None of this is trivial. So I wonder if it would be easier to set up an XML layout for a single task item & then somehow load() the XML layout. Hopefully from there I could simply set the text & Progress Bar percentage. Would this work, or am I going about this wrong? Also, how would I set up the XML for this? Do I add an activity to my project, or just another XML file?
Finally, I need the task name to be clickable, so I can capture the click & open a new activity showing the subtasks for a task & allowing the user to change the status. Therefore the task name TextView needs to have an ID. Should I make the task names Buttons rather than TextViews? How can I set the ID dynamically? I see that there is a setId(int id) method for Views. But how do I know what integer to use? Android reference View.html states:
View IDs need not be unique throughout the tree, but it is good
practice to ensure that they are at least unique within the part of
the tree you are searching.
How do I ensure that these IDs are unique?
In the XML file, IDs are not numbers, but rather text, like:
android:id="#+id/my_button"
And this is referenced in the code like this:
Button myButton = findViewById(R.id.my_button);
But how do I create & use unique numeric IDs in order to capture click events on these task names?
Thanks for any pointers you can give!
New information & questions...
I have the basic functionality working, but a couple things aren't quite right:
If you look at my updated mockup, Updated Project Progress Mockup, I want the area highlighted in green to scroll, while the rest stays in place. However, the heading at the top & the button at the bottom scroll off the screen and won't come back. Not sure what I did wrong.
My layout xml looks like this:
<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:id="#+id/summary"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorBG"
tools:ignore="LabelFor"
tools:context="com.myorg.myapp.ProjSummary">
<TextView
android:id="#+id/txtSumm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/summ"
android:textAppearance="#style/TextAppearance.AppCompat"
android:textColor="#color/colorPrimaryDark"
android:textSize="18sp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="#+id/txtProj"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="#+id/txtProj"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/proj"
android:textAppearance="#style/TextAppearance.AppCompat"
android:textColor="#color/colorPrimaryDark"
app:layout_constraintTop_toBottomOf="#+id/txtSumm"
android:layout_marginTop="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/edtProj"/>
<EditText
android:id="#+id/edtProj"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:paddingTop="5dp"
android:paddingBottom="0dp"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:textColor="#color/colorPrimaryDark"
android:textSize="14sp"
app:layout_constraintTop_toBottomOf="#+id/txtSumm"
app:layout_constraintLeft_toRightOf="#+id/txtProj"
app:layout_constraintRight_toRightOf="parent"/>
<ImageView
android:id="#+id/imgLogo"
android:layout_width="120dp"
android:layout_height="48dp"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/btnSend"
app:srcCompat="#mipmap/my_logo"
android:contentDescription="#string/org_logo"/>
<Button
android:id="#+id/btnSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#color/colorSecondaryDark"
android:text="#string/send"
android:textColor="#color/colorButtonText"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/imgLogo"
app:layout_constraintRight_toRightOf="parent"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rvTaskList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#+id/txtProj"
app:layout_constraintBottom_toTopOf="#+id/imgLogo"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
My last task item never is displayed. (i.e. if I have 10 task items, only the first 9 are displayed.) In my activity class, I have an ArrayList for the summary list of task items:
private ArrayList _alSummaries;
And in my RecyclerView.Adapter class, I have the following method:
#Override
public int getItemCount() { return _alSummaries.size(); }
Anywhere else I should look?
Thanks!
Further update:
in my layout I had...
android:layout_height="wrap_content"
Rather than wrap_content, it should have been "0dp". Seems like a bug in Android, actually - if I say wrap_content, that should never cause the view to become larger than the space available to it (as set by the constraints).
Problem solved - not a problem with the interface, but with the code that loaded my data into the app.

So I wonder if it would be easier to set up an XML layout for a single task item & then somehow load() the XML layout. Hopefully from there I could simply set the text & Progress Bar percentage.
This is what a Recycler View adapter does. You have an xml layout containing the three simple views: a text, the bar and another text.
Now in your code (in the adapter), you inflate each row and set the text and progress bar individually.
Should I make the task names Buttons rather than TextViews? How can I set the ID dynamically?
You do not need to do that. You can just assign custom onClick listeners which do what you want in the adapter code.
For a beginner, the setup is definitely not trivial, but once you get the hang of it, you will find it to be a very valuable tool.
Look here for the official tutorial: https://developer.android.com/training/material/lists-cards.html

Related

Android Studio 3.1.3 Error: The view is not constrainted. How to solve this permanently?

Whenever I try to drag and drop "Button" or "TextView", it give the error message with a red exclamation mark. How to solve this permanently?
enter image description here
It means exactly what it says, the view has no constraints set. The constraints are what set its position on the screen and relative position to other views. The way to fix the error is to add constraints, either with the GUI or in the XML file directly.
For example, to make it centered at the top of the screen you could set the following attributes in the XML file (click the "Text" tab below the image preview to edit the XML)
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
For more details about setting up a ConstraintLayout, including how to set constraints in the GUI rather than XML, check the user guide here. Whenever you drag a new component into your layout you will see this error until you've set constraints for it.
A view must have at least one horizontal and vertical constraint or else it would be scattered when run on a real device. The warning is for you to take note of that.
See sample of a well constraint view.
<TextView
android:id="#+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Since when you create the view (Button, TextView etc) it has only a design-time view, you should set specific positions on the screen which you intend to locate the view exactly when the application is run. That is what mean by setting constraints. If the view should have at least one constraint. Otherwise it automatically goes in to the (0,0) location (top-left corner) when your run your application.
Setting Constraints
1.GUI (Design)
Go to Design of your activity xml and drag from the anchors of the view and set the place or
Go to Attributes -> Layout -> Constraint Widget and set values for the constraints.
2.Text
Following is the xml code of constraints corresponds to the above image.
<Button>
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.117"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.499"></Button>
Hope this is somehow helpful. Happy coding!

Border Lines for cells in GridLayout, TableLayout, or GridView?

I am trying to create a table/grid for some items within my app and I would like to have a border around each cell to divide the items up and have a coherent association of the setting with the item. This app will be used in an industrial setting where there may be people unfamiliar with Android that need to use this, thus trying to make it as easy as possible.
The table/grid will contain TextView, EditText, Spinner, and Button, and will also be scrollable (via ScrollView parent).
I read about the GridView and found that it (seems) to only be able to get items programmatically, please correct me if I am wrong. I felt that this was unnecessary since I know what items I want and where. Also, I have not tried adding items to a layout programmatically yet so I figured I would try the other options first. Also, the GridView documentation does not say one way or the other if border lines are automatically shown, or if you can have them shown at all.
I started with a TableLayout and was able to get everything except the border lines to work. I tried android:divider to get the lines but that didn't work. One thought I had was to create a bunch of TextViews with black backgrounds and ~2dp widths/heights to make my own border lines. This feels like a huge waste though. Then I also read the TableLayout documentation and found this: "TableLayout containers do not display border lines for their rows, columns, or cells."
I then tried the GridLayout and had the same results as the TableLayout. I tried padding and margins, neither worked. Also, the GridLayout documentation states: "The grid is composed of a set of infinitely thin lines that separate the viewing area into cells."
My questions are:
Is there an attirbute that I missed in TableLayout or GridLayout that will give me border lines via the xml?
If no, then will the GridView give me the lines I want?
Will I be able to add all the perviously mentioned items I want to the GridView?
I was actually able to achieve the desired look by setting the android:background="#000000" within the GridLayout view and then in the child items I set the android:background="#8CDD81" (just some green color) and combined with android:layout_margin="2dp" I was able to get the "grid" lines that I wanted. Thanks to CommonsWare though for getting me thinking in a new direction that turned into a solution.
EDIT:
This does not work quite as anticipated. You need the android:layout_alignLeft/Right which are only available via RelativeLayout in order to get just the right width on the child items. Haven't tested this yet using this idea, child items within RelativeLayout within GridLayout.
Is there an attirbute that I missed in TableLayout or GridLayout that will give me border lines via the xml?
No.
If no, then will the GridView give me the lines I want?
No.
Will I be able to add all the perviously mentioned items I want to the GridView?
Yes, though how well something like a Spinner will work, I can't say.
The simplest way, off the top of my head, to give you the lines you seek is to have each cell of the TableLayout or GridLayout be some container containing the widget(s) for that cell, where you give the container a background that is your line. A ShapeDrawable could be defined in XML for that background, which will be nicely resizeable based upon the actual requirements of the cell.
For future visiters this is how I did it with TableLayout:
table.xml
<TableLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#969696">
<!-- table heading -->
<TableRow>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:background="#d2d2d2"
android:layout_margin="1dp"
/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Address"
android:background="#d2d2d2"
android:layout_margin="1dp"
/>
</TableRow>
<!-- table data -->
<TableRow>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ahtisham"
android:layout_margin="1dp"
android:background="#f1f1f1"
/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Kashmir"
android:layout_margin="1dp"
android:background="#f1f1f1"
/>
</TableRow>
</TableLayout>

How to split text in 2 textviews like if there were 1?

I have a listview where each item has 2 images, one on the right and the other on the left. Between them there is a textview that is filled from data. If text is long then it can continue down but there is a lot of free space just as you can see in the image. I want to use this space also to display text. I have been looking around the web and I have seen things like this http://code.google.com/p/android-flowtextview/downloads/detail?name=FlowTextDemo.zip&can=2&q= but this is useless. I don't want to lose the control of the images because I need their click method. What is the best way to do it? I have thought that maybe I can put a textview between images and an other down and when the first is filled continue in the second one but how can I know how many letters can keep the first textview?
I don't understand why FlowTextView (that you linked to) won't work for you. It's derived from RelativeLayout and flows text around any child views. The child views can be your images, positioned as you normally would in a RelativeLayout. Their onClick methods should work just fine.
<com.pagesuite.flowtext.FlowTextView
android:id="#+id/tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/the_text >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:onClick="onTopLeftClick"
android:src="#drawable/top_left_image" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:onClick="onTopRightClick"
android:src="#drawable/top_right_image" />
</com.pagesuite.flowtext.FlowTextView>
You will need to set the text in code, or else extend FlowTextView and define your own custom attribute(s) to do it from xml.

Android Image Control

I have a big problem. I want to create a control for android in which the user sees an image and over lapping this image are smaller icons/image which are positioned relative to background image.
The smaller icons can be selected.
I really do not know how to go about it.
You could do this by having a clean image as background, like this:
and then you could have TextViews within a RelativeLayout with the names for example, and on every textView you can set the attribute clickable to your method.
Something like this:
<TextView
android:id="#+id/nevada"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/Oregon"
android:layout_marginRight="50dp"
android:layout_marginTop="21dp"
android:layout_toLeftOf="#+id/Cali"
android:clickable="true"
android:onClick="showState"
android:text="#string/Nevada"
android:textColor="#color/contact_map_text_color" />
and on your activity/fragment you will have your method that will be called by the View, in the example case: "showState"
Edit: its probably not the best approach but it certainly works

Best solution to merge/include an xml layout file multiple times in an activity layout

I'm building a flashcards app as a college project, and wanted a horizontally scrolling display of the cards. I've built an xml file for the flashcard design itself:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:background="#drawable/whitenote" android:padding="3dp">
<ImageButton
android:id="#+id/imageButtonPins"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" android:background="#color/transparent" android:src="#drawable/pinselector"/>
<TextView
android:id="#+id/textViewWord"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/imageButton1"
android:layout_centerHorizontal="true"
android:text="Word" android:textColor="#color/black" android:paddingTop="30dp" android:textSize="20dp"/>
<TextView
android:id="#+id/textViewMeaning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textViewWord"
android:layout_centerHorizontal="true"
android:text="Meaning" android:textColor="#color/black"/>
</RelativeLayout>
I've also created the Class file.
In the activity layout, I have a few more elements and as such a linearlayout at the root level is necessary. I've been able to display a single flashcard for test purposes using and using layout inflater.
Question
In both the ways, in and layout inflater I've been unable to get the ImageButton working. My question is how do I get the button to work.
Update: Managed to get the ImageButton working using . Realised that I have to handle the onclick event in the activity, and not the Custom Adapter class. This should allow me to obtain the words too, as long as I can keep track of the "current" flashcard on display
Also, whats the best way to handle the scrolling for a flashcard app? My current plans so far is to use a HorizontalScrollView and customise it a bit, because I need (a) a swipe should make the flashcard move only to the next one (b) I need to focus on the "current" flashcard since I need some data from its children views (ie, the word).
Are you considering Fragments?
You can get some help with the ViewPager here.This is supported in Android 3.0 or above or Android 1.6 with the compatibility package.
http://geekyouup.blogspot.com/2011/07/viewpager-example-from-paug.html
If you do not wish to use the fragments, you can simply use the Gallery. This way, you can achieve the horizontal scrolling. (like in the Amazon app) without complex ViewPager.
For the second part of your question, take a look at the ViewPager.
A HorizontalScrollView or a Gallery are probably the most direct way of implementing this. I don't use Gallery-- but it is good to at least know it exists.
If you want a much more robust implementation, I agree with dcanh121 and think you should check out a Fragment based ViewPager. This will allow more options than just a View , but might be overkill depending on the goal. A fragment is basically the bizarre offspring of an Activity and a View, but don't quote me on that.
Also,
Inflating layouts is costly, so try to only inflate the XML into a View once, and reuse that View object. Try not to re-inflate the XML every time a new flashcard is drawn.

Categories

Resources