0

I have a page in which I'm taking the START TIME and END TIME from DATABASE.

Let's say the START TIME is 7:00 and END TIME is 22:00

I want to use this START TIME and END TIME to show in my page as textview like 7:00 8:00 9:00 and sooo on till 22:00 as textview

Also I have an imageview that will also increase when the text increases.

How can I achieve this?

Also I want the result text in Horizontal Scroll View with Imageview at top and text view as bottom of each imageview

char first = StartTime.charAt(0);

int StartTimeint = Integer.parseInt(String.valueOf(first));

int l;
for( l = StartTimeint; l<=22; l++){
    Log.d("SeatsPage", "Time is "+l);
}

timeofseats.setText(Integer.toString(l));

This is I have done so far but I'm getting 23 as a result, the textview is not increasing

This is my XML File

<?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:id="@+id/llMain"
    android:layout_height="match_parent"
    tools:context=".SeatsPagewithDB.SeatsPage">


    <ImageView
        android:id="@+id/imageView11"
        android:layout_width="150px"
        android:layout_height="150px"
        android:layout_marginStart="28dp"
        android:layout_marginEnd="326dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/seat" />


    <TextView
        android:id="@+id/timeofseats"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="40dp"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="334dp"
        android:background="#FF0000"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:text="7:00"
        android:textColor="#fff"
        android:textSize="20dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView11" />


</android.support.constraint.ConstraintLayout>

This is the result I am getting as layout

This what I want programmatically

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Small hint here, the set `timeofseats.setText(Integer.toString(l));` should be inside the `for` loop. – alexandrum Sep 09 '19 at 20:11
  • You are getting 23 because that is how your current logic works. When the loop will end `l` will have the value `23`. That is how you wrote your logic don't you think ? breaking the loop when `l` reaches `23`. But that is not the main issue. I wanted to know that do you want multiple `TextView` for displaying your time intervals or just a single `TextView` showing `7:00 . 8:00 . 9:00 ... 22:00` as single string ? – Syed Ahmed Jamil Sep 09 '19 at 23:36
  • yes i want multiple textview to display the time – Ayesha Israr Sep 10 '19 at 10:21
  • @SyedAhmedJamil how i can achieve this – Ayesha Israr Sep 10 '19 at 10:23
  • I think your question is related to UI logic rather than program logic. Can you update your question and include contents of your layout xml file. Also attach a screenshot of running app to get a better idea of your UI. – Syed Ahmed Jamil Sep 10 '19 at 11:10
  • @SyedAhmedJamil i have edited the answer and also attact the screen shot. Please help me solve my problem. its very urgent :) – Ayesha Israr Sep 10 '19 at 11:27
  • It looks like you need to just implement a RecyclerView using a LinearLayoutManager and set its orientation to HORIZONTAL. Doing that you will get a horizontal scrolling list. After that you can populate that list programmatically with your custom layout view. I will post a proper answer later. But meanwhile you can do it easily after reading a bit about RecyclerView. You can start here : https://developer.android.com/guide/topics/ui/layout/recyclerview – Syed Ahmed Jamil Sep 10 '19 at 15:14
  • Thank u @SyedAhmedJamil. I have worked with the recyclerview. how i can popoulate the recyclerview with just start time and end time ? Like 7:00 and 22:00 ? – Ayesha Israr Sep 10 '19 at 16:13
  • I need as 7:00 then a new textview as 8:00 and then 9:00 and then so on – Ayesha Israr Sep 10 '19 at 16:14
  • @SyedAhmedJamil – Ayesha Israr Sep 10 '19 at 16:14
  • See my answer below. – Syed Ahmed Jamil Sep 10 '19 at 22:47

2 Answers2

0

The XML code that you write in your layout.xml file to create the UI is for static UI only. What you are asking is to create views dynamically during runtime. Although you can definitely create views using java code on a click of a button or something. But it is better to code less for the UI whenever possible and keep it separated from the program code. Instead use the tools given to us by the framework we are using.

In Android those tools include stuff like ListView, GridView and the newer and better RecyclerView. These views help you add other views dynamically to your UI in runtime. You define one of them or more (depending on your UI needs) once in your layout.xml and configure them using java code like any other view.

This is how you can use RecyclerView to achieve your goal. I can't explain everything how RecyclerView works and what each line of code does as it will make a very long post but I have tried to highlight main things briefly.

1. Add RecyclerView in your layout file.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

2. Create another layout file and define the template UI of the item that the RecyclerView is going to display. RecyclerView will populate each item that it holds with this layout.

item_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    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="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imageView_alarm"
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:src="@drawable/alarm" />

    <TextView
        android:id="@+id/textView_Time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:background="#FF0000"
        android:paddingLeft="8dp"
        android:paddingRight="8dp"
        android:text="Time"
        android:textColor="@android:color/background_light"
        android:textSize="24sp" />
</LinearLayout>

3. Create a ViewHolder class that extends from RecyclerView.ViewHolder. View holder is a RecyclerView related concept. In short it works as a wrapper around the view of a single item and aids in binding new data to the view of the item. Create a bind() function inside view holder to make your life easier.

EDIT: I have updated the class by implementing the View.OnClickListener interface, modified the constructor to pass in the context from onCreateViewHolder() and adding a setItemPosition() just for the sake to pass the item position number from onBindViewHolder() all over to here so we can use this position number in our onClick() method of the interface

MyViewHolder.java [UPDATED]

public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    private TextView textView;
    private int itemPosition;
    private Context mContext;

    public MyViewHolder(@NonNull View itemView, Context context) {
        super(itemView);

        itemView.setOnClickListener(this);

        mContext = context;
        textView = itemView.findViewById(R.id.textView_Time);
    }

    void bind(String timeText)
    {
        textView.setText(timeText);
    }

    void setItemPosition(int position)
    {
        itemPosition = position;
    }

    @Override
    public void onClick(View v) {

        Toast.makeText(mContext, "You clicked item number: " + itemPosition , Toast.LENGTH_SHORT).show();

    }
} 

4. Create an Adapter class that extends from RecyclerView.Adapter. Adapter works as a bridge between the UI data and RecyclerView itself. An Adapter tells the RecyclerView what layout file to inflate and how many to inflate. RecyclerView job is to deal with how to inflate it on the UI.

EDIT : Just changed myViewHolder in onCreateViewHolder() to match the modified constructor of MyViewHolder. Added the call to setItemPosition() in the onBindViewHolder().

MyAdapter.java [UPDATED]

public class MyAdapter extends RecyclerView.Adapter {

    List<String> timeIntervalList = new ArrayList<>();


    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false);
        MyViewHolder myViewHolder = new MyViewHolder(view , parent.getContext());

        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

        MyViewHolder viewHolder = (MyViewHolder) holder;

        viewHolder.setItemPosition(position);    
        viewHolder.bind(timeIntervalList.get(position));

    }

    @Override
    public int getItemCount() {
        return timeIntervalList.size();
    }

    public void addItem (String timeText)
    {
        timeIntervalList.add(timeText);
        notifyItemInserted(getItemCount());
    }
}

In this adapter you will see two functions. OnCreateViewHolder() inflates the view using the template layout file for a single item and OnBindViewHolder() binds new data to the default values of the of the view just created. The data used for binding is stored in a list inside this Adapter called the timeIntervalList. This list will hold your time interval strings so they can be updated on the view.

5. Finally, use this RecyclerView where you want to use it. Like in your MainActivity.java. RecyclerView needs to be told in what fashion to display the items (e.g list , grid etc ) using a LayoutManager. LinearLayoutManager will display items either vertically or horizontally. You can see I am using your logic to increment time from string and adding new views to RecyclerView using the addItem() function of the MyAdapter class.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private RecyclerView myRecyclerView;
    private MyAdapter myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myRecyclerView = findViewById(R.id.recyclerView);
        myAdapter = new MyAdapter();

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this , LinearLayoutManager.HORIZONTAL, false);

        myRecyclerView.setLayoutManager(linearLayoutManager);
        myRecyclerView.setAdapter(myAdapter);

        // This is how you will populate the recycler view

        String START_TIME  = "7:00";
        String END_TIME = "22:00";

        char first = START_TIME.charAt(0);

        int StartTimeint = Integer.parseInt(String.valueOf(first));

        int l;
        for( l = StartTimeint; l<=22; l++){

            // This is where new item are added to recyclerView.
            myAdapter.addItem(l + ":00");

        }

    }
}

This is the final result.

enter image description here

Syed Ahmed Jamil
  • 1,881
  • 3
  • 18
  • 34
  • Thanks ur answer workss!! But how to get OnClickListener on each item?? @Syed Ahmed Jamil . – Ayesha Israr Sep 12 '19 at 00:03
  • There are many ways to go by it. If you search stack overflow you will find techniques like https://stackoverflow.com/questions/24471109/recyclerview-onclick and https://stackoverflow.com/questions/24885223/why-doesnt-recyclerview-have-onitemclicklistener or you can do it the hard way by following the docs https://developer.android.com/guide/topics/ui/layout/recyclerview#select – Syed Ahmed Jamil Sep 12 '19 at 03:59
  • I have updated my answer. See step number 3 and 4. Just update your code according to the updates in step number 3 and 4. The way I did it might not be the best way to do it. All I did mainly was to implement `View.OnClickListener` on the `MyViewHolder` class. That way you can set an onClickListener on view of each item at the time when RecyclerView creates a new view holder for an item in `OnCreateViewHolder()`. What ever you want to do on click of each item , do it in the `onClick()` method of the `MyViewHolder` class – Syed Ahmed Jamil Sep 12 '19 at 04:06
0

Change your activity layout XML code as follows,

<?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:id="@+id/llMain"
    android:layout_height="match_parent"
    tools:context=".SeatsPagewithDB.SeatsPage">

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ...
        ...>

        <LinearLayout
            android:id="@+id/container"
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </HorizontalScrollView>

</android.support.constraint.ConstraintLayout>

Move the textview and imageview to another XML file let's call it item_view.xml (you can name it whatever you wish). we are doing so because the root view of this file will be reused.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/imageView11"
        android:layout_width="150px"
        android:layout_height="150px"
        app:srcCompat="@drawable/seat"/>


    <TextView
        android:id="@+id/timeofseats"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#FF0000"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:text="7:00"
        android:textColor="#fff"
        android:textSize="20dp"/>

</LinearLayout>

Now make following changes in your Java file

    LinearLayout container = findViewById(R.id.container); // or rootView.findViewById() for custom View and Fragment

    char first = StartTime.charAt(0);

    int StartTimeint = Integer.parseInt(String.valueOf(first));

    for(int l = StartTimeint; l<=22; l++){
        Log.d("SeatsPage", "Time is "+l);
        View view = LayoutInflater.from(container.getContext()).inflate(R.layout.item_view, null);
        TextView timeofseats = view.findViewById(R.id.timeofseats);
        timeofseats.setText(Integer.toString(l));
        container.addView(view);
    }
Roaim
  • 2,298
  • 2
  • 11
  • 23